summaryrefslogtreecommitdiffstats
path: root/formula/source/ui/dlg
diff options
context:
space:
mode:
Diffstat (limited to 'formula/source/ui/dlg')
-rw-r--r--formula/source/ui/dlg/ControlHelper.hxx106
-rw-r--r--formula/source/ui/dlg/FormulaHelper.cxx417
-rw-r--r--formula/source/ui/dlg/formula.cxx1960
-rw-r--r--formula/source/ui/dlg/funcpage.cxx257
-rw-r--r--formula/source/ui/dlg/funcpage.hxx87
-rw-r--r--formula/source/ui/dlg/funcutl.cxx486
-rw-r--r--formula/source/ui/dlg/parawin.cxx600
-rw-r--r--formula/source/ui/dlg/parawin.hxx145
-rw-r--r--formula/source/ui/dlg/structpg.cxx154
-rw-r--r--formula/source/ui/dlg/structpg.hxx74
10 files changed, 4286 insertions, 0 deletions
diff --git a/formula/source/ui/dlg/ControlHelper.hxx b/formula/source/ui/dlg/ControlHelper.hxx
new file mode 100644
index 000000000..249547451
--- /dev/null
+++ b/formula/source/ui/dlg/ControlHelper.hxx
@@ -0,0 +1,106 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <formula/funcutl.hxx>
+
+namespace formula
+{
+
+class ParaWin;
+
+
+class ArgEdit : public RefEdit
+{
+public:
+ ArgEdit(std::unique_ptr<weld::Entry> xControl);
+
+ void Init(ArgEdit* pPrevEdit, ArgEdit* pNextEdit,
+ weld::ScrolledWindow& rArgSlider,
+ ParaWin& rParaWin, sal_uInt16 nArgCount);
+
+protected:
+ virtual bool KeyInput(const KeyEvent& rKEvt) override;
+
+private:
+ ArgEdit* pEdPrev;
+ ArgEdit* pEdNext;
+ weld::ScrolledWindow* pSlider;
+ ParaWin* pParaWin;
+ sal_uInt16 nArgs;
+};
+
+
+
+class ArgInput final
+{
+private:
+ Link<ArgInput&,void> aFxClickLink;
+ Link<ArgInput&,void> aFxFocusLink;
+ Link<ArgInput&,void> aEdFocusLink;
+ Link<ArgInput&,void> aEdModifyLink;
+
+ weld::Label*pFtArg;
+ weld::Button* pBtnFx;
+ ArgEdit* pEdArg;
+ RefButton* pRefBtn;
+
+ DECL_LINK( FxBtnClickHdl, weld::Button&, void );
+ DECL_LINK( FxBtnFocusHdl, weld::Widget&, void );
+ DECL_LINK( EdFocusHdl, RefEdit&, void );
+ DECL_LINK( EdModifyHdl, RefEdit&, void );
+
+public:
+
+ ArgInput();
+
+ void InitArgInput(weld::Label* pftArg,
+ weld::Button* pbtnFx,
+ ArgEdit* pedArg,
+ RefButton* prefBtn);
+
+ void SetArgName(const OUString &aArg);
+ OUString GetArgName() const;
+ void SetArgNameFont(const vcl::Font&);
+
+ void SetArgVal(const OUString &aVal);
+ OUString GetArgVal() const;
+
+ void SelectAll();
+
+ ArgEdit* GetArgEdPtr() { return pEdArg; }
+
+
+ void SetFxClickHdl( const Link<ArgInput&,void>& rLink ) { aFxClickLink = rLink; }
+
+ void SetFxFocusHdl( const Link<ArgInput&,void>& rLink ) { aFxFocusLink = rLink; }
+
+ void SetEdFocusHdl( const Link<ArgInput&,void>& rLink ) { aEdFocusLink = rLink; }
+
+ void SetEdModifyHdl( const Link<ArgInput&,void>& rLink ) { aEdModifyLink = rLink; }
+
+ void Hide();
+ void Show();
+
+ void UpdateAccessibleNames();
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/formula/source/ui/dlg/FormulaHelper.cxx b/formula/source/ui/dlg/FormulaHelper.cxx
new file mode 100644
index 000000000..15d3b411a
--- /dev/null
+++ b/formula/source/ui/dlg/FormulaHelper.cxx
@@ -0,0 +1,417 @@
+/* -*- 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 <algorithm>
+
+#include <formula/formulahelper.hxx>
+#include <formula/IFunctionDescription.hxx>
+#include <unotools/charclass.hxx>
+#include <unotools/syslocale.hxx>
+
+namespace formula
+{
+
+ namespace
+ {
+
+ class OEmptyFunctionDescription : public IFunctionDescription
+ {
+ public:
+ OEmptyFunctionDescription(){}
+ virtual ~OEmptyFunctionDescription(){}
+
+ virtual OUString getFunctionName() const override { return OUString(); }
+ virtual const IFunctionCategory* getCategory() const override { return nullptr; }
+ virtual OUString getDescription() const override { return OUString(); }
+ virtual sal_Int32 getSuppressedArgumentCount() const override { return 0; }
+ virtual OUString getFormula(const ::std::vector< OUString >& ) const override { return OUString(); }
+ virtual void fillVisibleArgumentMapping(::std::vector<sal_uInt16>& ) const override {}
+ virtual void initArgumentInfo() const override {}
+ virtual OUString getSignature() const override { return OUString(); }
+ virtual OString getHelpId() const override { return ""; }
+ virtual bool isHidden() const override { return false; }
+ virtual sal_uInt32 getParameterCount() const override { return 0; }
+ virtual sal_uInt32 getVarArgsStart() const override { return 0; }
+ virtual sal_uInt32 getVarArgsLimit() const override { return 0; }
+ virtual OUString getParameterName(sal_uInt32 ) const override { return OUString(); }
+ virtual OUString getParameterDescription(sal_uInt32 ) const override { return OUString(); }
+ virtual bool isParameterOptional(sal_uInt32 ) const override { return false; }
+ };
+ }
+
+// class FormulaHelper - static Method
+
+
+#define FUNC_NOTFOUND -1
+
+FormulaHelper::FormulaHelper(const IFunctionManager* _pFunctionManager)
+ :m_pSysLocale(new SvtSysLocale)
+ ,m_pFunctionManager(_pFunctionManager)
+ ,open(_pFunctionManager->getSingleToken(IFunctionManager::eOk))
+ ,close(_pFunctionManager->getSingleToken(IFunctionManager::eClose))
+ ,sep(_pFunctionManager->getSingleToken(IFunctionManager::eSep))
+ ,arrayOpen(_pFunctionManager->getSingleToken(IFunctionManager::eArrayOpen))
+ ,arrayClose(_pFunctionManager->getSingleToken(IFunctionManager::eArrayClose))
+{
+ m_pCharClass = &m_pSysLocale->GetCharClass();
+}
+
+sal_Int32 FormulaHelper::GetCategoryCount() const
+{
+ return m_pFunctionManager->getCount();
+}
+
+bool FormulaHelper::GetNextFunc( const OUString& rFormula,
+ bool bBack,
+ sal_Int32& rFStart, // Input and output
+ sal_Int32* pFEnd, // = NULL
+ const IFunctionDescription** ppFDesc, // = NULL
+ ::std::vector< OUString>* pArgs ) const // = NULL
+{
+ sal_Int32 nOldStart = rFStart;
+ OUString aFname;
+
+ rFStart = GetFunctionStart( rFormula, rFStart, bBack, ppFDesc ? &aFname : nullptr );
+ bool bFound = ( rFStart != FUNC_NOTFOUND );
+
+ if ( bFound )
+ {
+ if ( pFEnd )
+ *pFEnd = GetFunctionEnd( rFormula, rFStart );
+
+ if ( ppFDesc )
+ {
+ *ppFDesc = nullptr;
+ const sal_uInt32 nCategoryCount = m_pFunctionManager->getCount();
+ for(sal_uInt32 j= 0; j < nCategoryCount && !*ppFDesc; ++j)
+ {
+ const IFunctionCategory* pCategory = m_pFunctionManager->getCategory(j);
+ const sal_uInt32 nCount = pCategory->getCount();
+ for(sal_uInt32 i = 0 ; i < nCount; ++i)
+ {
+ const IFunctionDescription* pCurrent = pCategory->getFunction(i);
+ if ( pCurrent->getFunctionName().equalsIgnoreAsciiCase(aFname) )
+ {
+ *ppFDesc = pCurrent;
+ break;
+ }
+ }// for(sal_uInt32 i = 0 ; i < nCount; ++i)
+ }
+ if ( *ppFDesc && pArgs )
+ {
+ GetArgStrings( *pArgs,rFormula, rFStart, static_cast<sal_uInt16>((*ppFDesc)->getParameterCount() ));
+ }
+ else
+ {
+ static OEmptyFunctionDescription s_aFunctionDescription;
+ *ppFDesc = &s_aFunctionDescription;
+ }
+ }
+ }
+ else
+ rFStart = nOldStart;
+
+ return bFound;
+}
+
+
+void FormulaHelper::FillArgStrings( const OUString& rFormula,
+ sal_Int32 nFuncPos,
+ sal_uInt16 nArgs,
+ ::std::vector< OUString >& _rArgs ) const
+{
+ sal_Int32 nStart = 0;
+ sal_Int32 nEnd = 0;
+ sal_uInt16 i;
+ bool bLast = false;
+
+ for ( i=0; i<nArgs && !bLast; i++ )
+ {
+ nStart = GetArgStart( rFormula, nFuncPos, i );
+
+ if ( i+1<nArgs ) // last argument?
+ {
+ nEnd = GetArgStart( rFormula, nFuncPos, i+1 );
+
+ if ( nEnd != nStart )
+ _rArgs.push_back(rFormula.copy( nStart, nEnd-1-nStart ));
+ else
+ {
+ _rArgs.emplace_back();
+ bLast = true;
+ }
+ }
+ else
+ {
+ nEnd = GetFunctionEnd( rFormula, nFuncPos )-1;
+ if ( nStart < nEnd )
+ _rArgs.push_back( rFormula.copy( nStart, nEnd-nStart ) );
+ else
+ _rArgs.emplace_back();
+ }
+ }
+
+ if ( bLast )
+ for ( ; i<nArgs; i++ )
+ _rArgs.emplace_back();
+}
+
+
+void FormulaHelper::GetArgStrings( ::std::vector< OUString >& _rArgs,
+ const OUString& rFormula,
+ sal_Int32 nFuncPos,
+ sal_uInt16 nArgs ) const
+{
+ if (nArgs)
+ {
+ FillArgStrings( rFormula, nFuncPos, nArgs, _rArgs );
+ }
+}
+
+
+static bool IsFormulaText( const CharClass* _pCharClass,const OUString& rStr, sal_Int32 nPos )
+{
+ if( _pCharClass->isLetterNumeric( rStr, nPos ) )
+ return true;
+ else
+ { // In internationalized versions function names may contain a dot
+ // and in every version also an underscore... ;-)
+ sal_Unicode c = rStr[nPos];
+ return c == '.' || c == '_';
+ }
+
+}
+
+sal_Int32 FormulaHelper::GetFunctionStart( const OUString& rFormula,
+ sal_Int32 nStart,
+ bool bBack,
+ OUString* pFuncName ) const
+{
+ sal_Int32 nStrLen = rFormula.getLength();
+
+ if ( nStrLen < nStart )
+ return nStart;
+
+ sal_Int32 nFStart = FUNC_NOTFOUND;
+ sal_Int32 nParPos = bBack ? ::std::min( nStart, nStrLen - 1) : nStart;
+
+ bool bRepeat;
+ do
+ {
+ bool bFound = false;
+ bRepeat = false;
+
+ if ( bBack )
+ {
+ while ( !bFound && (nParPos > 0) )
+ {
+ if ( rFormula[nParPos] == '"' )
+ {
+ nParPos--;
+ while ( (nParPos > 0) && rFormula[nParPos] != '"' )
+ nParPos--;
+ if (nParPos > 0)
+ nParPos--;
+ }
+ else
+ {
+ bFound = rFormula[nParPos] == '(';
+ if ( !bFound )
+ nParPos--;
+ }
+ }
+ }
+ else
+ {
+ while ( !bFound && (0 <= nParPos && nParPos < nStrLen) )
+ {
+ if ( rFormula[nParPos] == '"' )
+ {
+ nParPos++;
+ while ( (nParPos < nStrLen) && rFormula[nParPos] != '"' )
+ nParPos++;
+ nParPos++;
+ }
+ else
+ {
+ bFound = rFormula[nParPos] == '(';
+ if ( !bFound )
+ nParPos++;
+ }
+ }
+ }
+
+ if ( bFound && (nParPos > 0) )
+ {
+ nFStart = nParPos-1;
+
+ while ( (nFStart > 0) && IsFormulaText(m_pCharClass, rFormula, nFStart ))
+ nFStart--;
+ }
+
+ nFStart++;
+
+ if ( bFound )
+ {
+ if ( IsFormulaText( m_pCharClass,rFormula, nFStart ) )
+ {
+ // Function found
+ if ( pFuncName )
+ *pFuncName = rFormula.copy( nFStart, nParPos-nFStart );
+ }
+ else // Brackets without function -> keep searching
+ {
+ bRepeat = true;
+ if ( !bBack )
+ nParPos++;
+ else if (nParPos > 0)
+ nParPos--;
+ else
+ bRepeat = false;
+ }
+ }
+ else // No brackets found
+ {
+ nFStart = FUNC_NOTFOUND;
+ if ( pFuncName )
+ pFuncName->clear();
+ }
+ }
+ while(bRepeat);
+
+ return nFStart;
+}
+
+
+sal_Int32 FormulaHelper::GetFunctionEnd( const OUString& rStr, sal_Int32 nStart ) const
+{
+ sal_Int32 nStrLen = rStr.getLength();
+
+ if ( nStrLen < nStart )
+ return nStart;
+
+ short nParCount = 0;
+ bool bInArray = false;
+ bool bFound = false;
+
+ while ( !bFound && (nStart < nStrLen) )
+ {
+ sal_Unicode c = rStr[nStart];
+
+ if ( c == '"' )
+ {
+ nStart++;
+ while ( (nStart < nStrLen) && rStr[nStart] != '"' )
+ nStart++;
+ }
+ else if ( c == open )
+ nParCount++;
+ else if ( c == close )
+ {
+ nParCount--;
+ if ( nParCount == 0 )
+ bFound = true;
+ else if ( nParCount < 0 )
+ {
+ bFound = true;
+ nStart--; // read one too far
+ }
+ }
+ else if ( c == arrayOpen )
+ {
+ bInArray = true;
+ }
+ else if ( c == arrayClose )
+ {
+ bInArray = false;
+ }
+ else if ( c == sep )
+ {
+ if ( !bInArray && nParCount == 0 )
+ {
+ bFound = true;
+ nStart--; // read one too far
+ }
+ }
+ nStart++; // Set behind found position
+ }
+
+ // nStart > nStrLen can happen if there was an unclosed quote; instead of
+ // checking that in every loop iteration check it once here.
+ return std::min(nStart, nStrLen);
+}
+
+
+sal_Int32 FormulaHelper::GetArgStart( const OUString& rStr, sal_Int32 nStart, sal_uInt16 nArg ) const
+{
+ sal_Int32 nStrLen = rStr.getLength();
+
+ if ( nStrLen < nStart )
+ return nStart;
+
+ short nParCount = 0;
+ bool bInArray = false;
+ bool bFound = false;
+
+ while ( !bFound && (nStart < nStrLen) )
+ {
+ sal_Unicode c = rStr[nStart];
+
+ if ( c == '"' )
+ {
+ nStart++;
+ while ( (nStart < nStrLen) && rStr[nStart] != '"' )
+ nStart++;
+ }
+ else if ( c == open )
+ {
+ bFound = ( nArg == 0 );
+ nParCount++;
+ }
+ else if ( c == close )
+ {
+ nParCount--;
+ bFound = ( nParCount == 0 );
+ }
+ else if ( c == arrayOpen )
+ {
+ bInArray = true;
+ }
+ else if ( c == arrayClose )
+ {
+ bInArray = false;
+ }
+ else if ( c == sep )
+ {
+ if ( !bInArray && nParCount == 1 )
+ {
+ nArg--;
+ bFound = ( nArg == 0 );
+ }
+ }
+ nStart++;
+ }
+
+ return nStart;
+}
+
+} // formula
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/formula/source/ui/dlg/formula.cxx b/formula/source/ui/dlg/formula.cxx
new file mode 100644
index 000000000..9898fe1be
--- /dev/null
+++ b/formula/source/ui/dlg/formula.cxx
@@ -0,0 +1,1960 @@
+/* -*- 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 <memory>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+#include <sal/log.hxx>
+
+#include <unotools/charclass.hxx>
+#include <tools/diagnose_ex.h>
+
+#include "funcpage.hxx"
+#include <formula/formula.hxx>
+#include <formula/IFunctionDescription.hxx>
+#include <formula/FormulaCompiler.hxx>
+#include <formula/token.hxx>
+#include <formula/tokenarray.hxx>
+#include <formula/formdata.hxx>
+#include <formula/formulahelper.hxx>
+#include "structpg.hxx"
+#include "parawin.hxx"
+#include <strings.hrc>
+#include <core_resource.hxx>
+#include <com/sun/star/sheet/FormulaToken.hpp>
+#include <com/sun/star/sheet/FormulaLanguage.hpp>
+#include <com/sun/star/sheet/FormulaMapGroup.hpp>
+#include <com/sun/star/sheet/FormulaMapGroupSpecialOffset.hpp>
+#include <com/sun/star/sheet/XFormulaOpCodeMapper.hpp>
+#include <com/sun/star/sheet/XFormulaParser.hpp>
+#include <map>
+
+// For tab page
+#define TOKEN_OPEN 0
+#define TOKEN_CLOSE 1
+namespace formula
+{
+
+using namespace ::com::sun::star;
+
+class FormulaDlg_Impl
+{
+public:
+ ::std::pair<RefButton*, RefEdit*>
+ RefInputStartBefore( RefEdit* pEdit, RefButton* pButton );
+ void RefInputStartAfter();
+ void RefInputDoneAfter( bool bForced );
+ bool CalcValue( const OUString& rStrExp, OUString& rStrResult, bool bForceMatrixFormula = false );
+ void CalcStruct( const OUString& rStrExp, bool bForceRecalcStruct = false );
+ void UpdateValues( bool bForceRecalcStruct = false );
+ void DeleteArgs();
+ sal_Int32 GetFunctionPos(sal_Int32 nPos);
+ void ClearAllParas();
+
+ void MakeTree(StructPage* _pTree, weld::TreeIter* pParent, const FormulaToken* pFuncToken,
+ const FormulaToken* _pToken, tools::Long Count);
+ void fillTree(StructPage* _pTree);
+ void UpdateTokenArray( const OUString& rStrExp);
+ OUString RepairFormula(const OUString& aFormula);
+ void FillDialog(bool bFlag = true);
+ bool EditNextFunc( bool bForward, sal_Int32 nFStart = NOT_FOUND );
+ void EditThisFunc(sal_Int32 nFStart);
+
+ OUString GetPrevFuncExpression( bool bStartFromEnd );
+
+ void StoreFormEditData(FormEditData* pEditData);
+
+ void Update();
+ void Update(const OUString& _sExp);
+
+ void SaveArg( sal_uInt16 nEd );
+ void UpdateSelection();
+ void DoEnter( bool bOk );
+ void FillListboxes();
+ void FillControls( bool &rbNext, bool &rbPrev);
+
+ FormulaDlgMode SetMeText( const OUString& _sText, sal_Int32 PrivStart, sal_Int32 PrivEnd, bool bMatrix, bool _bSelect, bool _bUpdate);
+ void SetMeText(const OUString& _sText);
+ bool CheckMatrix(OUString& aFormula /*IN/OUT*/);
+
+ void SetEdSelection();
+
+ bool UpdateParaWin(Selection& _rSelection);
+ void UpdateParaWin( const Selection& _rSelection, const OUString& _sRefStr);
+
+ void SetData( sal_Int32 nFStart, sal_Int32 nNextFStart, sal_Int32 nNextFEnd, sal_Int32& PrivStart, sal_Int32& PrivEnd);
+
+ RefEdit* GetCurrRefEdit();
+
+ const FormulaHelper& GetFormulaHelper() const { return m_aFormulaHelper;}
+ void InitFormulaOpCodeMapper();
+
+ void UpdateOldSel();
+ void FormulaCursor();
+
+ DECL_LINK( ModifyHdl, ParaWin&, void );
+ DECL_LINK( FxHdl, ParaWin&, void );
+
+ DECL_LINK( MatrixHdl, weld::Toggleable&, void );
+ DECL_LINK( FormulaHdl, weld::TextView&, void);
+ DECL_LINK( FormulaCursorHdl, weld::TextView&, void );
+ DECL_LINK( BtnHdl, weld::Button&, void );
+ DECL_LINK( DblClkHdl, FuncPage&, void );
+ DECL_LINK( FuncSelHdl, FuncPage&, void );
+ DECL_LINK( StructSelHdl, StructPage&, void );
+public:
+ mutable uno::Reference< sheet::XFormulaOpCodeMapper> m_xOpCodeMapper;
+ uno::Sequence< sheet::FormulaToken > m_aTokenList;
+ ::std::unique_ptr<FormulaTokenArray> m_pTokenArray;
+ ::std::unique_ptr<FormulaTokenArrayPlainIterator> m_pTokenArrayIterator;
+ mutable uno::Sequence< sheet::FormulaOpCodeMapEntry > m_aSpecialOpCodes;
+ mutable uno::Sequence< sheet::FormulaToken > m_aSeparatorsOpCodes;
+ mutable uno::Sequence< sheet::FormulaOpCodeMapEntry > m_aFunctionOpCodes;
+ mutable const sheet::FormulaOpCodeMapEntry* m_pFunctionOpCodesEnd;
+ ::std::map<const FormulaToken*, sheet::FormulaToken> m_aTokenMap;
+ IFormulaEditorHelper* m_pHelper;
+ weld::Dialog& m_rDialog;
+
+ OUString m_aOldFormula;
+ bool m_bStructUpdate;
+ bool m_bUserMatrixFlag;
+
+ const OUString m_aTitle1;
+ const OUString m_aTitle2;
+ FormulaHelper m_aFormulaHelper;
+
+ OString m_aEditHelpId;
+
+ OString m_aOldHelp;
+ bool m_bMakingTree; // in method of constructing tree
+
+ bool m_bEditFlag;
+ const IFunctionDescription* m_pFuncDesc;
+ sal_Int32 m_nArgs;
+ ::std::vector< OUString > m_aArguments;
+ Selection m_aFuncSel;
+
+ sal_Int32 m_nFuncExpStart; ///< current formula position for treeview results
+
+ int m_nSelectionStart;
+ int m_nSelectionEnd;
+
+ RefEdit* m_pTheRefEdit;
+ RefButton* m_pTheRefButton;
+
+ std::unique_ptr<weld::Notebook> m_xTabCtrl;
+ std::unique_ptr<weld::Container> m_xParaWinBox;
+ std::unique_ptr<ParaWin> m_xParaWin;
+ std::unique_ptr<weld::Label> m_xFtHeadLine;
+ std::unique_ptr<weld::Label> m_xFtFuncName;
+ std::unique_ptr<weld::Label> m_xFtFuncDesc;
+
+ std::unique_ptr<weld::Label> m_xFtEditName;
+
+ std::unique_ptr<weld::Label> m_xFtResult;
+ std::unique_ptr<weld::Entry> m_xWndResult;
+
+ std::unique_ptr<weld::Label> m_xFtFormula;
+ std::unique_ptr<weld::TextView> m_xMEdit;
+
+ std::unique_ptr<weld::CheckButton> m_xBtnMatrix;
+ std::unique_ptr<weld::Button> m_xBtnCancel;
+
+ std::unique_ptr<weld::Button> m_xBtnBackward;
+ std::unique_ptr<weld::Button> m_xBtnForward;
+ std::unique_ptr<weld::Button> m_xBtnEnd;
+
+ std::unique_ptr<weld::Label> m_xFtFormResult;
+ std::unique_ptr<weld::Entry> m_xWndFormResult;
+
+ std::unique_ptr<RefEdit> m_xEdRef;
+ std::unique_ptr<RefButton> m_xRefBtn;
+
+ std::unique_ptr<FuncPage> m_xFuncPage;
+ std::unique_ptr<StructPage> m_xStructPage;
+
+ FormulaDlg_Impl(weld::Dialog& rDialog,
+ weld::Builder& rBuilder,
+ bool _bSupportFunctionResult,
+ bool _bSupportResult,
+ bool _bSupportMatrix,
+ IFormulaEditorHelper* _pHelper,
+ const IFunctionManager* _pFunctionMgr,
+ IControlReferenceHandler* _pDlg);
+ ~FormulaDlg_Impl();
+};
+
+FormulaDlg_Impl::FormulaDlg_Impl(weld::Dialog& rDialog,
+ weld::Builder& rBuilder,
+ bool _bSupportFunctionResult,
+ bool _bSupportResult,
+ bool _bSupportMatrix,
+ IFormulaEditorHelper* _pHelper,
+ const IFunctionManager* _pFunctionMgr,
+ IControlReferenceHandler* _pDlg)
+ : m_pFunctionOpCodesEnd(nullptr)
+ , m_pHelper(_pHelper)
+ , m_rDialog(rDialog)
+ , m_bUserMatrixFlag(false)
+ , m_aTitle1( ForResId( STR_TITLE1 ) )
+ , m_aTitle2( ForResId( STR_TITLE2 ) )
+ , m_aFormulaHelper(_pFunctionMgr)
+ , m_bMakingTree(false)
+ , m_pFuncDesc(nullptr)
+ , m_nArgs(0)
+ , m_nFuncExpStart(0)
+ , m_nSelectionStart(-1)
+ , m_nSelectionEnd(-1)
+ , m_pTheRefEdit(nullptr)
+ , m_pTheRefButton(nullptr)
+ , m_xTabCtrl(rBuilder.weld_notebook("tabcontrol"))
+ , m_xParaWinBox(rBuilder.weld_container("BOX"))
+ , m_xFtHeadLine(rBuilder.weld_label("headline"))
+ , m_xFtFuncName(rBuilder.weld_label("funcname"))
+ , m_xFtFuncDesc(rBuilder.weld_label("funcdesc"))
+ , m_xFtEditName(rBuilder.weld_label("editname"))
+ , m_xFtResult(rBuilder.weld_label("label2"))
+ , m_xWndResult(rBuilder.weld_entry("result"))
+ , m_xFtFormula(rBuilder.weld_label("formula"))
+ , m_xMEdit(rBuilder.weld_text_view("ed_formula"))
+ , m_xBtnMatrix(rBuilder.weld_check_button("array"))
+ , m_xBtnCancel(rBuilder.weld_button("cancel"))
+ , m_xBtnBackward(rBuilder.weld_button("back"))
+ , m_xBtnForward(rBuilder.weld_button("next"))
+ , m_xBtnEnd(rBuilder.weld_button("ok"))
+ , m_xFtFormResult(rBuilder.weld_label("label1"))
+ , m_xWndFormResult(rBuilder.weld_entry("formula_result"))
+ , m_xEdRef(new RefEdit(rBuilder.weld_entry("ED_REF")))
+ , m_xRefBtn(new RefButton(rBuilder.weld_button("RB_REF")))
+{
+ auto nWidth = m_xMEdit->get_approximate_digit_width() * 62;
+
+ //Space for two lines of text
+ m_xFtHeadLine->set_label("X\nX\n");
+ auto nHeight = m_xFtHeadLine->get_preferred_size().Height();
+ m_xFtHeadLine->set_size_request(nWidth, nHeight);
+ m_xFtHeadLine->set_label("");
+
+ m_xFtFuncName->set_label("X\nX\n");
+ nHeight = m_xFtFuncName->get_preferred_size().Height();
+ m_xFtFuncName->set_size_request(nWidth, nHeight);
+ m_xFtFuncDesc->set_size_request(nWidth, nHeight);
+ m_xFtFuncName->set_label("");
+
+ m_xMEdit->set_size_request(nWidth,
+ m_xMEdit->get_height_rows(5));
+
+ m_xEdRef->SetReferences(_pDlg, m_xFtEditName.get());
+ m_xRefBtn->SetReferences(_pDlg, m_xEdRef.get());
+
+ m_xParaWin.reset(new ParaWin(m_xParaWinBox.get(), _pDlg));
+ m_xParaWin->Show();
+ m_xParaWinBox->hide();
+ m_xFtEditName->hide();
+ m_xEdRef->GetWidget()->hide();
+ m_xRefBtn->GetWidget()->hide();
+
+ m_xMEdit->set_accessible_name(m_xFtFormula->get_label());
+
+ m_aEditHelpId = m_xMEdit->get_help_id();
+
+ m_bEditFlag =false;
+ m_bStructUpdate =true;
+ m_xParaWin->SetArgModifiedHdl( LINK( this, FormulaDlg_Impl, ModifyHdl ) );
+ m_xParaWin->SetFxHdl( LINK( this, FormulaDlg_Impl, FxHdl ) );
+
+ m_xFuncPage.reset(new FuncPage(m_xTabCtrl->get_page("function"), _pFunctionMgr));
+ m_xStructPage.reset(new StructPage(m_xTabCtrl->get_page("struct")));
+ m_xTabCtrl->set_current_page("function");
+
+ m_aOldHelp = m_rDialog.get_help_id(); // HelpId from resource always for "Page 1"
+
+ m_xFtResult->set_visible( _bSupportResult );
+ m_xWndResult->set_visible( _bSupportResult );
+
+ m_xFtFormResult->set_visible( _bSupportFunctionResult );
+ m_xWndFormResult->set_visible( _bSupportFunctionResult );
+
+ if ( _bSupportMatrix )
+ m_xBtnMatrix->connect_toggled( LINK( this, FormulaDlg_Impl, MatrixHdl ) );
+ else
+ m_xBtnMatrix->hide();
+
+ m_xBtnCancel->connect_clicked( LINK( this, FormulaDlg_Impl, BtnHdl ) );
+ m_xBtnEnd->connect_clicked( LINK( this, FormulaDlg_Impl, BtnHdl ) );
+ m_xBtnForward->connect_clicked( LINK( this, FormulaDlg_Impl, BtnHdl ) );
+ m_xBtnBackward->connect_clicked( LINK( this, FormulaDlg_Impl, BtnHdl ) );
+
+ m_xFuncPage->SetDoubleClickHdl( LINK( this, FormulaDlg_Impl, DblClkHdl ) );
+ m_xFuncPage->SetSelectHdl( LINK( this, FormulaDlg_Impl, FuncSelHdl) );
+ m_xStructPage->SetSelectionHdl( LINK( this, FormulaDlg_Impl, StructSelHdl ) );
+ m_xMEdit->connect_changed( LINK( this, FormulaDlg_Impl, FormulaHdl ) );
+ m_xMEdit->connect_cursor_position( LINK( this, FormulaDlg_Impl, FormulaCursorHdl ) );
+
+ vcl::Font aFntLight = m_xFtFormula->get_font();
+ vcl::Font aFntBold = aFntLight;
+ aFntBold.SetWeight( WEIGHT_BOLD );
+
+ m_xParaWin->SetArgumentFonts( aFntBold, aFntLight);
+}
+
+FormulaDlg_Impl::~FormulaDlg_Impl()
+{
+ m_xTabCtrl->remove_page("function");
+ m_xTabCtrl->remove_page("struct");
+
+ DeleteArgs();
+}
+
+void FormulaDlg_Impl::StoreFormEditData(FormEditData* pData)
+{
+ if (!pData) // it won't be destroyed via Close
+ return;
+
+ int nStartPos, nEndPos;
+ m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
+ if (nStartPos > nEndPos)
+ std::swap(nStartPos, nEndPos);
+
+ pData->SetFStart(nStartPos);
+ pData->SetSelection(Selection(nStartPos, nEndPos));
+
+ if (m_xTabCtrl->get_current_page_ident() == "function")
+ pData->SetMode( FormulaDlgMode::Formula );
+ else
+ pData->SetMode( FormulaDlgMode::Edit );
+ pData->SetUndoStr(m_xMEdit->get_text());
+ pData->SetMatrixFlag(m_xBtnMatrix->get_active());
+}
+
+void FormulaDlg_Impl::InitFormulaOpCodeMapper()
+{
+ if ( m_xOpCodeMapper.is() )
+ return;
+
+ m_xOpCodeMapper = m_pHelper->getFormulaOpCodeMapper();
+ m_aFunctionOpCodes = m_xOpCodeMapper->getAvailableMappings( sheet::FormulaLanguage::ODFF, sheet::FormulaMapGroup::FUNCTIONS);
+ m_pFunctionOpCodesEnd = m_aFunctionOpCodes.getConstArray() + m_aFunctionOpCodes.getLength();
+
+ // 0:TOKEN_OPEN, 1:TOKEN_CLOSE, 2:TOKEN_SEP
+ uno::Sequence< OUString > aArgs { "(", ")", ";" };
+ m_aSeparatorsOpCodes = m_xOpCodeMapper->getMappings( aArgs, sheet::FormulaLanguage::ODFF);
+
+ m_aSpecialOpCodes = m_xOpCodeMapper->getAvailableMappings( sheet::FormulaLanguage::ODFF, sheet::FormulaMapGroup::SPECIAL);
+}
+
+void FormulaDlg_Impl::DeleteArgs()
+{
+ ::std::vector< OUString>().swap(m_aArguments);
+ m_nArgs = 0;
+}
+
+sal_Int32 FormulaDlg_Impl::GetFunctionPos(sal_Int32 nPos)
+{
+ if ( !m_aTokenList.hasElements() )
+ return SAL_MAX_INT32;
+
+ const sal_Unicode sep = m_pHelper->getFunctionManager()->getSingleToken(IFunctionManager::eSep);
+
+ sal_Int32 nFuncPos = SAL_MAX_INT32;
+ OUString aFormString = m_aFormulaHelper.GetCharClass()->uppercase(m_xMEdit->get_text());
+
+ const uno::Reference< sheet::XFormulaParser > xParser(m_pHelper->getFormulaParser());
+ const table::CellAddress aRefPos(m_pHelper->getReferencePosition());
+
+ const sheet::FormulaToken* pIter = m_aTokenList.getConstArray();
+ const sheet::FormulaToken* pEnd = pIter + m_aTokenList.getLength();
+ try
+ {
+ bool bFlag = false;
+ sal_Int32 nTokPos = 1;
+ sal_Int32 nOldTokPos = 1;
+ sal_Int32 nPrevFuncPos = 1;
+ short nBracketCount = 0;
+ const sal_Int32 nOpPush = m_aSpecialOpCodes[sheet::FormulaMapGroupSpecialOffset::PUSH].Token.OpCode;
+ const sal_Int32 nOpSpaces = m_aSpecialOpCodes[sheet::FormulaMapGroupSpecialOffset::SPACES].Token.OpCode;
+ const sal_Int32 nOpWhitespace = m_aSpecialOpCodes[sheet::FormulaMapGroupSpecialOffset::WHITESPACE].Token.OpCode;
+ while ( pIter != pEnd )
+ {
+ const sal_Int32 eOp = pIter->OpCode;
+ uno::Sequence<sheet::FormulaToken> aArgs { *pIter };
+ const OUString aString = xParser->printFormula( aArgs, aRefPos);
+ const sheet::FormulaToken* pNextToken = pIter + 1;
+
+ if ( !m_bUserMatrixFlag && FormulaCompiler::IsMatrixFunction(static_cast<OpCode>(eOp)) )
+ {
+ m_xBtnMatrix->set_active(true);
+ }
+
+ if (eOp == nOpPush || eOp == nOpSpaces || eOp == nOpWhitespace)
+ {
+ const sal_Int32 n1 = nTokPos < 0 ? -1 : aFormString.indexOf( sep, nTokPos);
+ const sal_Int32 n2 = nTokPos < 0 ? -1 : aFormString.indexOf( ')', nTokPos);
+ sal_Int32 nXXX = nTokPos;
+ if ( n1 < n2 && n1 != -1 )
+ {
+ nTokPos = n1;
+ }
+ else
+ {
+ nTokPos = n2;
+ }
+ if ( pNextToken != pEnd )
+ {
+ aArgs.getArray()[0] = *pNextToken;
+ const OUString a2String = xParser->printFormula( aArgs, aRefPos);
+ const sal_Int32 n3 = nXXX < 0 ? -1 : aFormString.indexOf( a2String, nXXX);
+ if (n3 < nTokPos && n3 != -1)
+ nTokPos = n3;
+ }
+ }
+ else
+ {
+ nTokPos = nTokPos + aString.getLength();
+ }
+
+ if ( eOp == m_aSeparatorsOpCodes[TOKEN_OPEN].OpCode )
+ {
+ nBracketCount++;
+ bFlag = true;
+ }
+ else if ( eOp == m_aSeparatorsOpCodes[TOKEN_CLOSE].OpCode )
+ {
+ nBracketCount--;
+ bFlag = false;
+ nFuncPos = nPrevFuncPos;
+ }
+ bool bIsFunction = std::any_of( m_aFunctionOpCodes.getConstArray(),
+ m_pFunctionOpCodesEnd,
+ [&eOp](const sheet::FormulaOpCodeMapEntry& aEntry) { return aEntry.Token.OpCode == eOp; });
+
+ if ( bIsFunction && nOpSpaces != eOp && nOpWhitespace != eOp )
+ {
+ nPrevFuncPos = nFuncPos;
+ nFuncPos = nOldTokPos;
+ }
+
+ if ( nOldTokPos <= nPos && nPos < nTokPos )
+ {
+ if ( !bIsFunction )
+ {
+ if ( nBracketCount < 1 )
+ {
+ nFuncPos = m_xMEdit->get_text().getLength();
+ }
+ else if ( !bFlag )
+ {
+ nFuncPos = nPrevFuncPos;
+ }
+ }
+ break;
+ }
+
+ pIter = pNextToken;
+ nOldTokPos = nTokPos;
+ } // while ( pIter != pEnd )
+ }
+ catch ( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("formula.ui", "FormulaDlg_Impl::GetFunctionPos");
+ }
+
+ return nFuncPos;
+}
+
+bool FormulaDlg_Impl::CalcValue( const OUString& rStrExp, OUString& rStrResult, bool bForceMatrixFormula )
+{
+ bool bResult = true;
+
+ if ( !rStrExp.isEmpty() )
+ {
+ // Only calculate the value when there isn't any more keyboard input:
+
+ // Make this debuggable by assigning to a variable that can be changed
+ // from within the debugger.
+ bool bInput = Application::AnyInput( VclInputFlags::KEYBOARD );
+ if ( !bInput )
+ {
+ bResult = m_pHelper->calculateValue( rStrExp, rStrResult, bForceMatrixFormula || m_xBtnMatrix->get_active());
+ }
+ else
+ bResult = false;
+ }
+
+ return bResult;
+}
+
+void FormulaDlg_Impl::UpdateValues( bool bForceRecalcStruct )
+{
+ // Take a force-array context into account. RPN creation propagated those
+ // to tokens that are ref-counted so also available in the token array.
+ bool bForceArray = false;
+ // Only necessary if it's not a matrix formula anyway and matrix evaluation
+ // is supported, i.e. the button is visible.
+ if (m_xBtnMatrix->get_visible() && !m_xBtnMatrix->get_active())
+ {
+ std::unique_ptr<FormulaCompiler> pCompiler(m_pHelper->createCompiler(*m_pTokenArray));
+ // In the case of the reportdesign dialog there is no currently active
+ // OpCode symbol mapping that could be used to create strings from
+ // tokens, it's all dreaded API mapping. However, in that case there's
+ // no array/matrix support anyway, but ensure checking.
+ if (pCompiler->GetCurrentOpCodeMap())
+ {
+ const sal_Int32 nPos = m_aFuncSel.Min();
+ assert( 0 <= nPos && nPos < m_pHelper->getCurrentFormula().getLength());
+ OUStringBuffer aBuf;
+ const FormulaToken* pToken = nullptr;
+ for (pToken = m_pTokenArrayIterator->First(); pToken; pToken = m_pTokenArrayIterator->Next())
+ {
+ pCompiler->CreateStringFromToken( aBuf, pToken);
+ if (nPos < aBuf.getLength())
+ break;
+ }
+ if (pToken && nPos < aBuf.getLength())
+ bForceArray = pToken->IsInForceArray();
+ }
+ }
+
+ OUString aStrResult;
+ if (m_pFuncDesc && CalcValue( m_pFuncDesc->getFormula( m_aArguments), aStrResult, bForceArray))
+ m_xWndResult->set_text( aStrResult );
+
+ if (m_bMakingTree)
+ return;
+
+ aStrResult.clear();
+ if ( CalcValue( m_pHelper->getCurrentFormula(), aStrResult ) )
+ m_xWndFormResult->set_text( aStrResult );
+ else
+ {
+ aStrResult.clear();
+ m_xWndFormResult->set_text( aStrResult );
+ }
+ CalcStruct( m_xMEdit->get_text(), bForceRecalcStruct);
+}
+
+void FormulaDlg_Impl::CalcStruct( const OUString& rStrExp, bool bForceRecalcStruct )
+{
+ sal_Int32 nLength = rStrExp.getLength();
+
+ if ( !(!rStrExp.isEmpty() && (bForceRecalcStruct || m_aOldFormula != rStrExp) && m_bStructUpdate))
+ return;
+
+ m_xStructPage->ClearStruct();
+
+ OUString aString = rStrExp;
+ if (rStrExp[nLength-1] == '(')
+ {
+ aString = aString.copy( 0, nLength-1);
+ }
+
+ aString = aString.replaceAll( "\n", "");
+ OUString aStrResult;
+
+ if ( CalcValue( aString, aStrResult ) )
+ m_xWndFormResult->set_text(aStrResult);
+
+ UpdateTokenArray(aString);
+ fillTree(m_xStructPage.get());
+
+ m_aOldFormula = rStrExp;
+ if (rStrExp[nLength-1] == '(')
+ UpdateTokenArray(rStrExp);
+}
+
+void FormulaDlg_Impl::MakeTree(StructPage* _pTree, weld::TreeIter* pParent, const FormulaToken* pFuncToken,
+ const FormulaToken* _pToken, tools::Long Count)
+{
+ if ( _pToken == nullptr || Count <= 0 )
+ return;
+
+ tools::Long nParas = _pToken->GetParamCount();
+ OpCode eOp = _pToken->GetOpCode();
+
+ // #i101512# for output, the original token is needed
+ const FormulaToken* pOrigToken = (_pToken->GetType() == svFAP) ? _pToken->GetFAPOrigToken() : _pToken;
+ ::std::map<const FormulaToken*, sheet::FormulaToken>::const_iterator itr = m_aTokenMap.find(pOrigToken);
+ if (itr == m_aTokenMap.end())
+ return;
+
+ uno::Sequence<sheet::FormulaToken> aArgs { itr->second };
+ try
+ {
+ const table::CellAddress aRefPos(m_pHelper->getReferencePosition());
+ const OUString aResult = m_pHelper->getFormulaParser()->printFormula( aArgs, aRefPos);
+
+ if ( nParas > 0 || (nParas == 0 && _pToken->IsFunction()) )
+ {
+ std::unique_ptr<weld::TreeIter> xEntry;
+ weld::TreeIter* pEntry;
+
+ bool bCalcSubformula = false;
+ OUString aTest = _pTree->GetEntryText(pParent);
+
+ if (aTest == aResult && (eOp == ocAdd || eOp == ocMul || eOp == ocAmpersand))
+ {
+ pEntry = pParent;
+ }
+ else
+ {
+ xEntry = m_xStructPage->GetTlbStruct().make_iterator();
+
+ if (eOp == ocBad)
+ {
+ _pTree->InsertEntry(aResult, pParent, STRUCT_ERROR, 0, _pToken, *xEntry);
+ }
+ else if (!((SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP) ||
+ (SC_OPCODE_START_UN_OP <= eOp && eOp < SC_OPCODE_STOP_UN_OP)))
+ {
+ // Not a binary or unary operator.
+ bCalcSubformula = true;
+ _pTree->InsertEntry(aResult, pParent, STRUCT_FOLDER, 0, _pToken, *xEntry);
+ }
+ else
+ {
+ /* TODO: question remains, why not sub calculate operators? */
+ _pTree->InsertEntry(aResult, pParent, STRUCT_FOLDER, 0, _pToken, *xEntry);
+ }
+
+ pEntry = xEntry.get();
+ }
+
+ MakeTree(_pTree, pEntry, _pToken, m_pTokenArrayIterator->PrevRPN(), nParas);
+
+ if (bCalcSubformula)
+ {
+ OUString aFormula;
+
+ if (!m_bMakingTree)
+ {
+ // gets the last subformula result
+ m_bMakingTree = true;
+ aFormula = GetPrevFuncExpression( true);
+ }
+ else
+ {
+ // gets subsequent subformula results (from the back)
+ aFormula = GetPrevFuncExpression( false);
+ }
+
+ OUString aStr;
+ if (CalcValue( aFormula, aStr, _pToken->IsInForceArray()))
+ m_xWndResult->set_text( aStr );
+ aStr = m_xWndResult->get_text();
+ m_xStructPage->GetTlbStruct().set_text(*pEntry, aResult + " = " + aStr);
+ }
+
+ --Count;
+ m_pTokenArrayIterator->NextRPN(); /* TODO: what's this to be? ThisRPN()? */
+ MakeTree( _pTree, pParent, _pToken, m_pTokenArrayIterator->PrevRPN(), Count);
+ }
+ else
+ {
+ std::unique_ptr<weld::TreeIter> xEntry(m_xStructPage->GetTlbStruct().make_iterator());
+ if (eOp == ocBad)
+ {
+ _pTree->InsertEntry( aResult, pParent, STRUCT_ERROR, 0, _pToken, *xEntry);
+ }
+ else if (eOp == ocPush)
+ {
+ // Interpret range reference in matrix context to resolve
+ // as array elements. Depending on parameter classification
+ // a scalar value (non-array context) is calculated first.
+ OUString aUnforcedResult;
+ bool bForceMatrix = (!m_xBtnMatrix->get_active() &&
+ (_pToken->GetType() == svDoubleRef || _pToken->GetType() == svExternalDoubleRef));
+ if (bForceMatrix && pFuncToken)
+ {
+ formula::ParamClass eParamClass = ParamClass::Reference;
+ if (pFuncToken->IsInForceArray())
+ eParamClass = ParamClass::ForceArray;
+ else
+ {
+ std::shared_ptr<FormulaCompiler> pCompiler = m_pHelper->getCompiler();
+ if (pCompiler)
+ eParamClass = pCompiler->GetForceArrayParameter( pFuncToken, Count - 1);
+ }
+ switch (eParamClass)
+ {
+ case ParamClass::Unknown:
+ case ParamClass::Bounds:
+ case ParamClass::Value:
+ if (CalcValue( "=" + aResult, aUnforcedResult, false) && aUnforcedResult != aResult)
+ aUnforcedResult += " ";
+ else
+ aUnforcedResult.clear();
+ break;
+ case ParamClass::Reference:
+ case ParamClass::ReferenceOrRefArray:
+ case ParamClass::Array:
+ case ParamClass::ForceArray:
+ case ParamClass::ReferenceOrForceArray:
+ case ParamClass::SuppressedReferenceOrForceArray:
+ case ParamClass::ForceArrayReturn:
+ ; // nothing, only as array/matrix
+ // no default to get compiler warning
+ }
+ }
+ OUString aCellResult;
+ if (CalcValue( "=" + aResult, aCellResult, bForceMatrix) && aCellResult != aResult)
+ {
+ // Cell is a formula, print subformula.
+ // With scalar values prints "A1:A3 = 2 {1;2;3}"
+ _pTree->InsertEntry( aResult + " = " + aUnforcedResult + aCellResult,
+ pParent, STRUCT_END, 0, _pToken, *xEntry);
+ }
+ else
+ _pTree->InsertEntry(aResult, pParent, STRUCT_END, 0, _pToken, *xEntry);
+ }
+ else
+ {
+ _pTree->InsertEntry(aResult, pParent, STRUCT_END, 0, _pToken, *xEntry);
+ }
+ --Count;
+ MakeTree( _pTree, pParent, _pToken, m_pTokenArrayIterator->PrevRPN(), Count);
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("formula.ui");
+ }
+}
+
+void FormulaDlg_Impl::fillTree(StructPage* _pTree)
+{
+ InitFormulaOpCodeMapper();
+ FormulaToken* pToken = m_pTokenArrayIterator->LastRPN();
+
+ if ( pToken != nullptr)
+ {
+ MakeTree( _pTree, nullptr, nullptr, pToken, 1);
+ m_bMakingTree = false;
+ }
+}
+
+void FormulaDlg_Impl::UpdateTokenArray( const OUString& rStrExp)
+{
+ m_aTokenMap.clear();
+ m_aTokenList.realloc(0);
+ try
+ {
+ const table::CellAddress aRefPos(m_pHelper->getReferencePosition());
+ m_aTokenList = m_pHelper->getFormulaParser()->parseFormula( rStrExp, aRefPos);
+ }
+ catch (const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("formula.ui");
+ }
+ InitFormulaOpCodeMapper();
+ m_pTokenArray = m_pHelper->convertToTokenArray(m_aTokenList);
+ m_pTokenArrayIterator.reset(new FormulaTokenArrayPlainIterator(*m_pTokenArray));
+ const sal_Int32 nLen = static_cast<sal_Int32>(m_pTokenArray->GetLen());
+ FormulaToken** pTokens = m_pTokenArray->GetArray();
+ if ( pTokens && nLen == m_aTokenList.getLength() )
+ {
+ for (sal_Int32 nPos = 0; nPos < nLen; nPos++)
+ {
+ m_aTokenMap.emplace( pTokens[nPos], m_aTokenList[nPos] );
+ }
+ } // if ( pTokens && nLen == m_aTokenList.getLength() )
+
+ std::unique_ptr<FormulaCompiler> pCompiler(m_pHelper->createCompiler(*m_pTokenArray));
+ // #i101512# Disable special handling of jump commands.
+ pCompiler->EnableJumpCommandReorder(false);
+ pCompiler->EnableStopOnError(false);
+ pCompiler->SetComputeIIFlag(true);
+ pCompiler->SetMatrixFlag(m_bUserMatrixFlag);
+ pCompiler->CompileTokenArray();
+}
+
+void FormulaDlg_Impl::FillDialog(bool bFlag)
+{
+ bool bNext = true, bPrev = true;
+ if (bFlag)
+ FillControls( bNext, bPrev);
+ FillListboxes();
+ if (bFlag)
+ {
+ m_xBtnBackward->set_sensitive(bPrev);
+ m_xBtnForward->set_sensitive(bNext);
+ }
+
+ OUString aStrResult;
+
+ if ( CalcValue( m_pHelper->getCurrentFormula(), aStrResult ) )
+ m_xWndFormResult->set_text( aStrResult );
+ else
+ {
+ aStrResult.clear();
+ m_xWndFormResult->set_text( aStrResult );
+ }
+}
+
+void FormulaDlg_Impl::FillListboxes()
+{
+ // Switch between the "Pages"
+ FormEditData* pData = m_pHelper->getFormEditData();
+ // 1. Page: select function
+ if ( m_pFuncDesc && m_pFuncDesc->getCategory() )
+ {
+ // We'll never have more than int32 max categories so this is safe ...
+ // Category listbox holds additional entries for Last Used and All, so
+ // the offset should be two but hard coded numbers are ugly...
+ const sal_Int32 nCategoryOffset = m_xFuncPage->GetCategoryEntryCount() - m_aFormulaHelper.GetCategoryCount();
+ if ( m_xFuncPage->GetCategory() != static_cast<sal_Int32>(m_pFuncDesc->getCategory()->getNumber() + nCategoryOffset) )
+ m_xFuncPage->SetCategory(m_pFuncDesc->getCategory()->getNumber() + nCategoryOffset);
+
+ sal_Int32 nPos = m_xFuncPage->GetFuncPos(m_pFuncDesc);
+
+ m_xFuncPage->SetFunction(nPos);
+ }
+ else if ( pData )
+ {
+ m_xFuncPage->SetCategory( 1 );
+ m_xFuncPage->SetFunction( -1 );
+ }
+ FuncSelHdl(*m_xFuncPage);
+
+ m_pHelper->setDispatcherLock( true ); // Activate Modal-Mode
+
+ // HelpId for 1. page is the one from the resource
+ m_rDialog.set_help_id( m_aOldHelp );
+}
+
+void FormulaDlg_Impl::FillControls( bool &rbNext, bool &rbPrev)
+{
+ // Switch between the "Pages"
+ FormEditData* pData = m_pHelper->getFormEditData();
+ if (!pData )
+ return;
+
+ // 2. Page or Edit: show selected function
+
+ sal_Int32 nFStart = pData->GetFStart();
+ OUString aFormula = m_pHelper->getCurrentFormula() + " )";
+ sal_Int32 nNextFStart = nFStart;
+ sal_Int32 nNextFEnd = 0;
+
+ DeleteArgs();
+ const IFunctionDescription* pOldFuncDesc = m_pFuncDesc;
+
+ if ( m_aFormulaHelper.GetNextFunc( aFormula, false,
+ nNextFStart, &nNextFEnd, &m_pFuncDesc, &m_aArguments ) )
+ {
+ const bool bTestFlag = (pOldFuncDesc != m_pFuncDesc);
+ if (bTestFlag)
+ {
+ m_xFtHeadLine->hide();
+ m_xFtFuncName->hide();
+ m_xFtFuncDesc->hide();
+ m_xParaWin->SetFunctionDesc(m_pFuncDesc);
+ m_xFtEditName->set_label( m_pFuncDesc->getFunctionName() );
+ m_xFtEditName->show();
+ m_xParaWinBox->show();
+ const OString aHelpId = m_pFuncDesc->getHelpId();
+ if ( !aHelpId.isEmpty() )
+ m_xMEdit->set_help_id(aHelpId);
+ }
+
+ sal_Int32 nOldStart, nOldEnd;
+ m_pHelper->getSelection( nOldStart, nOldEnd );
+ if ( nOldStart != nNextFStart || nOldEnd != nNextFEnd )
+ {
+ m_pHelper->setSelection( nNextFStart, nNextFEnd );
+ }
+ m_aFuncSel.Min() = nNextFStart;
+ m_aFuncSel.Max() = nNextFEnd;
+
+ if (!m_bEditFlag)
+ m_xMEdit->set_text(m_pHelper->getCurrentFormula());
+ sal_Int32 PrivStart, PrivEnd;
+ m_pHelper->getSelection( PrivStart, PrivEnd);
+ if (!m_bEditFlag)
+ m_xMEdit->select_region(PrivStart, PrivEnd);
+
+ m_nArgs = m_pFuncDesc->getSuppressedArgumentCount();
+ sal_uInt16 nOffset = pData->GetOffset();
+
+ // Concatenate the Edit's for Focus-Control
+
+ if (bTestFlag)
+ m_xParaWin->SetArgumentOffset(nOffset);
+ sal_uInt16 nActiv = 0;
+ sal_Int32 nArgPos = m_aFormulaHelper.GetArgStart( aFormula, nFStart, 0 );
+
+ int nStartPos, nEndPos;
+ m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
+ if (nStartPos > nEndPos)
+ std::swap(nStartPos, nEndPos);
+
+ sal_Int32 nEditPos = nStartPos;
+ bool bFlag = false;
+
+ for (sal_Int32 i = 0; i < m_nArgs; i++)
+ {
+ sal_Int32 nLength = m_aArguments[i].getLength()+1;
+ m_xParaWin->SetArgument( i, m_aArguments[i]);
+ if (nArgPos <= nEditPos && nEditPos < nArgPos+nLength)
+ {
+ nActiv = i;
+ bFlag = true;
+ }
+ nArgPos = nArgPos + nLength;
+ }
+ m_xParaWin->UpdateParas();
+
+ if (bFlag)
+ {
+ m_xParaWin->SetActiveLine(nActiv);
+ }
+
+ UpdateValues();
+ }
+ else
+ {
+ m_xFtEditName->set_label("");
+ m_xMEdit->set_help_id(m_aEditHelpId);
+ }
+ // test if before/after are anymore functions
+
+ sal_Int32 nTempStart = m_aFormulaHelper.GetArgStart( aFormula, nFStart, 0 );
+ rbNext = m_aFormulaHelper.GetNextFunc( aFormula, false, nTempStart );
+
+ int nStartPos, nEndPos;
+ m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
+ if (nStartPos > nEndPos)
+ std::swap(nStartPos, nEndPos);
+
+ nTempStart = nStartPos;
+ pData->SetFStart(nTempStart);
+ rbPrev = m_aFormulaHelper.GetNextFunc( aFormula, true, nTempStart );
+}
+
+
+void FormulaDlg_Impl::ClearAllParas()
+{
+ DeleteArgs();
+ m_pFuncDesc = nullptr;
+ m_xParaWin->ClearAll();
+ m_xWndResult->set_text(OUString());
+ m_xFtFuncName->set_label(OUString());
+ FuncSelHdl(*m_xFuncPage);
+
+ if (m_xFuncPage->IsVisible())
+ {
+ m_xFtEditName->hide();
+ m_xParaWinBox->hide();
+
+ m_xBtnForward->set_sensitive(true); //@new
+ m_xFtHeadLine->show();
+ m_xFtFuncName->show();
+ m_xFtFuncDesc->show();
+ }
+}
+
+OUString FormulaDlg_Impl::RepairFormula(const OUString& aFormula)
+{
+ OUString aResult('=');
+ try
+ {
+ UpdateTokenArray(aFormula);
+
+ if ( m_aTokenList.hasElements() )
+ {
+ const table::CellAddress aRefPos(m_pHelper->getReferencePosition());
+ const OUString sFormula( m_pHelper->getFormulaParser()->printFormula( m_aTokenList, aRefPos));
+ if ( sFormula.isEmpty() || sFormula[0] != '=' )
+ aResult += sFormula;
+ else
+ aResult = sFormula;
+
+ }
+ }
+ catch ( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("formula.ui", "FormulaDlg_Impl::RepairFormula");
+ }
+ return aResult;
+}
+
+void FormulaDlg_Impl::DoEnter(bool bOk)
+{
+ // Accept input to the document or cancel
+ if ( bOk)
+ {
+ // remove dummy arguments
+ OUString aInputFormula = m_pHelper->getCurrentFormula();
+ OUString aString = RepairFormula(m_xMEdit->get_text());
+ m_pHelper->setSelection( 0, aInputFormula.getLength());
+ m_pHelper->setCurrentFormula(aString);
+ }
+
+ m_pHelper->switchBack();
+
+ m_pHelper->dispatch( bOk, m_xBtnMatrix->get_active());
+ // Clear data
+ m_pHelper->deleteFormData();
+
+ // Close dialog
+ m_pHelper->doClose(bOk);
+}
+
+
+IMPL_LINK(FormulaDlg_Impl, BtnHdl, weld::Button&, rBtn, void)
+{
+ if (&rBtn == m_xBtnCancel.get())
+ {
+ DoEnter(false); // closes the Dialog
+ }
+ else if (&rBtn == m_xBtnEnd.get())
+ {
+ DoEnter(true); // closes the Dialog
+ }
+ else if (&rBtn == m_xBtnForward.get())
+ {
+ const IFunctionDescription* pDesc;
+ sal_Int32 nSelFunc = m_xFuncPage->GetFunction();
+ if (nSelFunc != -1)
+ pDesc = m_xFuncPage->GetFuncDesc( nSelFunc );
+ else
+ {
+ // Do not overwrite the selected formula expression, just edit the
+ // unlisted function.
+ m_pFuncDesc = pDesc = nullptr;
+ }
+
+ if (pDesc == m_pFuncDesc || !m_xFuncPage->IsVisible())
+ EditNextFunc( true );
+ else
+ {
+ DblClkHdl(*m_xFuncPage); //new
+ m_xBtnForward->set_sensitive(false); //new
+ }
+ }
+ else if (&rBtn == m_xBtnBackward.get())
+ {
+ m_bEditFlag = false;
+ m_xBtnForward->set_sensitive(true);
+ EditNextFunc( false );
+ }
+}
+
+// Functions for 1. Page
+
+// Handler for Listboxes
+
+IMPL_LINK_NOARG( FormulaDlg_Impl, DblClkHdl, FuncPage&, void)
+{
+ sal_Int32 nFunc = m_xFuncPage->GetFunction();
+
+ // ex-UpdateLRUList
+ const IFunctionDescription* pDesc = m_xFuncPage->GetFuncDesc(nFunc);
+ m_pHelper->insertEntryToLRUList(pDesc);
+
+ OUString aFuncName = m_xFuncPage->GetSelFunctionName() + "()";
+ m_pHelper->setCurrentFormula(aFuncName);
+ m_xMEdit->replace_selection(aFuncName);
+
+ int nStartPos, nEndPos;
+ m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
+ if (nStartPos > nEndPos)
+ std::swap(nStartPos, nEndPos);
+
+ nEndPos = nEndPos - 1;
+ m_xMEdit->select_region(nStartPos, nEndPos);
+
+ FormulaHdl(*m_xMEdit);
+
+ nStartPos = nEndPos;
+ m_xMEdit->select_region(nStartPos, nEndPos);
+
+ if (m_nArgs == 0)
+ {
+ BtnHdl(*m_xBtnBackward);
+ }
+
+ m_xParaWin->SetEdFocus();
+ m_xBtnForward->set_sensitive(false); //@New
+}
+
+// Functions for right Page
+
+void FormulaDlg_Impl::SetData( sal_Int32 nFStart, sal_Int32 nNextFStart, sal_Int32 nNextFEnd, sal_Int32& PrivStart, sal_Int32& PrivEnd)
+{
+ sal_Int32 nFEnd;
+
+ // Notice and set new selection
+ m_pHelper->getSelection( nFStart, nFEnd );
+ m_pHelper->setSelection( nNextFStart, nNextFEnd );
+ if (!m_bEditFlag)
+ m_xMEdit->set_text(m_pHelper->getCurrentFormula());
+
+
+ m_pHelper->getSelection( PrivStart, PrivEnd);
+ if (!m_bEditFlag)
+ {
+ m_xMEdit->select_region(PrivStart, PrivEnd);
+ UpdateOldSel();
+ }
+
+ FormEditData* pData = m_pHelper->getFormEditData();
+ pData->SetFStart( nNextFStart );
+ pData->SetOffset( 0 );
+
+ FillDialog();
+}
+
+void FormulaDlg_Impl::EditThisFunc(sal_Int32 nFStart)
+{
+ FormEditData* pData = m_pHelper->getFormEditData();
+ if (!pData)
+ return;
+
+ OUString aFormula = m_pHelper->getCurrentFormula();
+
+ if (nFStart == NOT_FOUND)
+ {
+ nFStart = pData->GetFStart();
+ }
+ else
+ {
+ pData->SetFStart(nFStart);
+ }
+
+ sal_Int32 nNextFStart = nFStart;
+ sal_Int32 nNextFEnd = 0;
+
+ bool bFound;
+
+ bFound = m_aFormulaHelper.GetNextFunc( aFormula, false, nNextFStart, &nNextFEnd);
+ if ( bFound )
+ {
+ sal_Int32 PrivStart, PrivEnd;
+ SetData( nFStart, nNextFStart, nNextFEnd, PrivStart, PrivEnd);
+ m_pHelper->showReference( aFormula.copy( PrivStart, PrivEnd-PrivStart));
+ }
+ else
+ {
+ ClearAllParas();
+ }
+}
+
+bool FormulaDlg_Impl::EditNextFunc( bool bForward, sal_Int32 nFStart )
+{
+ FormEditData* pData = m_pHelper->getFormEditData();
+ if (!pData)
+ return false;
+
+ OUString aFormula = m_pHelper->getCurrentFormula();
+
+ if (nFStart == NOT_FOUND)
+ {
+ nFStart = pData->GetFStart();
+ }
+ else
+ {
+ pData->SetFStart(nFStart);
+ }
+
+ sal_Int32 nNextFStart = 0;
+ sal_Int32 nNextFEnd = 0;
+
+ bool bFound;
+ if ( bForward )
+ {
+ nNextFStart = m_aFormulaHelper.GetArgStart( aFormula, nFStart, 0 );
+ bFound = m_aFormulaHelper.GetNextFunc( aFormula, false, nNextFStart, &nNextFEnd);
+ }
+ else
+ {
+ nNextFStart = nFStart;
+ bFound = m_aFormulaHelper.GetNextFunc( aFormula, true, nNextFStart, &nNextFEnd);
+ }
+
+ if ( bFound )
+ {
+ sal_Int32 PrivStart, PrivEnd;
+ SetData( nFStart, nNextFStart, nNextFEnd, PrivStart, PrivEnd);
+ }
+
+ return bFound;
+}
+
+OUString FormulaDlg_Impl::GetPrevFuncExpression( bool bStartFromEnd )
+{
+ OUString aExpression;
+
+ OUString aFormula( m_pHelper->getCurrentFormula());
+ if (aFormula.isEmpty())
+ return aExpression;
+
+ if (bStartFromEnd || m_nFuncExpStart >= aFormula.getLength())
+ m_nFuncExpStart = aFormula.getLength() - 1;
+
+ sal_Int32 nFStart = m_nFuncExpStart;
+ sal_Int32 nFEnd = 0;
+ if (m_aFormulaHelper.GetNextFunc( aFormula, true, nFStart, &nFEnd))
+ {
+ aExpression = aFormula.copy( nFStart, nFEnd - nFStart); // nFEnd is exclusive
+ m_nFuncExpStart = nFStart;
+ }
+
+ return aExpression;
+}
+
+void FormulaDlg_Impl::SaveArg( sal_uInt16 nEd )
+{
+ if (nEd >= m_nArgs)
+ return;
+
+ for (sal_uInt16 i = 0; i <= nEd; i++)
+ {
+ if ( m_aArguments[i].isEmpty() )
+ m_aArguments[i] = " ";
+ }
+ if (!m_xParaWin->GetArgument(nEd).isEmpty())
+ m_aArguments[nEd] = m_xParaWin->GetArgument(nEd);
+
+ sal_uInt16 nClearPos = nEd+1;
+ for (sal_Int32 i = nEd+1; i < m_nArgs; i++)
+ {
+ if ( !m_xParaWin->GetArgument(i).isEmpty() )
+ {
+ nClearPos = i+1;
+ }
+ }
+
+ for (sal_Int32 i = nClearPos; i < m_nArgs; i++)
+ {
+ m_aArguments[i].clear();
+ }
+}
+
+IMPL_LINK( FormulaDlg_Impl, FxHdl, ParaWin&, rPtr, void )
+{
+ if (&rPtr != m_xParaWin.get())
+ return;
+
+ m_xBtnForward->set_sensitive(true); //@ In order to be able to input another function.
+ m_xTabCtrl->set_current_page("function");
+
+ OUString aUndoStr = m_pHelper->getCurrentFormula(); // it will be added before a ";"
+ FormEditData* pData = m_pHelper->getFormEditData();
+ if (!pData)
+ return;
+
+ sal_uInt16 nArgNo = m_xParaWin->GetActiveLine();
+ sal_uInt16 nEdFocus = nArgNo;
+
+ SaveArg(nArgNo);
+ UpdateSelection();
+
+ sal_Int32 nFormulaStrPos = pData->GetFStart();
+
+ OUString aFormula = m_pHelper->getCurrentFormula();
+ sal_Int32 n1 = m_aFormulaHelper.GetArgStart( aFormula, nFormulaStrPos, nEdFocus + pData->GetOffset() );
+
+ pData->SaveValues();
+ pData->SetMode( FormulaDlgMode::Formula );
+ pData->SetFStart( n1 );
+ pData->SetUndoStr( aUndoStr );
+ ClearAllParas();
+
+ FillDialog(false);
+ m_xFuncPage->SetFocus(); //There Parawin is not visible anymore
+}
+
+IMPL_LINK( FormulaDlg_Impl, ModifyHdl, ParaWin&, rPtr, void )
+{
+ if (&rPtr == m_xParaWin.get())
+ {
+ SaveArg(m_xParaWin->GetActiveLine());
+ UpdateValues();
+
+ UpdateSelection();
+ CalcStruct(m_xMEdit->get_text());
+ }
+}
+
+IMPL_LINK_NOARG( FormulaDlg_Impl, FormulaHdl, weld::TextView&, void)
+{
+
+ FormEditData* pData = m_pHelper->getFormEditData();
+ if (!pData)
+ return;
+
+ m_bEditFlag = true;
+ OUString aInputFormula = m_pHelper->getCurrentFormula();
+ OUString aString = m_xMEdit->get_text();
+
+ int nStartPos, nEndPos;
+ m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
+ if (nStartPos > nEndPos)
+ std::swap(nStartPos, nEndPos);
+
+ if (aString.isEmpty()) // in case everything was cleared
+ {
+ aString += "=";
+ m_xMEdit->set_text(aString);
+ nStartPos = 1;
+ nEndPos = 1;
+ m_xMEdit->select_region(nStartPos, nEndPos);
+ }
+ else if (aString[0]!='=') // in case it's replaced
+ {
+ aString = "=" + aString;
+ m_xMEdit->set_text(aString);
+ nStartPos += 1;
+ nEndPos += 1;
+ m_xMEdit->select_region(nStartPos, nEndPos);
+ }
+
+ m_pHelper->setSelection( 0, aInputFormula.getLength());
+ m_pHelper->setCurrentFormula(aString);
+ m_pHelper->setSelection(nStartPos, nEndPos);
+
+ sal_Int32 nPos = nStartPos - 1;
+
+ OUString aStrResult;
+
+ if ( CalcValue( m_pHelper->getCurrentFormula(), aStrResult ) )
+ m_xWndFormResult->set_text( aStrResult );
+ else
+ {
+ aStrResult.clear();
+ m_xWndFormResult->set_text( aStrResult );
+ }
+ CalcStruct(aString);
+
+ nPos = GetFunctionPos(nPos);
+
+ if (nPos < nStartPos - 1)
+ {
+ sal_Int32 nPos1 = aString.indexOf( '(', nPos);
+ EditNextFunc( false, nPos1);
+ }
+ else
+ {
+ ClearAllParas();
+ }
+
+ m_pHelper->setSelection(nStartPos, nEndPos);
+ m_bEditFlag = false;
+}
+
+void FormulaDlg_Impl::FormulaCursor()
+{
+ FormEditData* pData = m_pHelper->getFormEditData();
+ if (!pData)
+ return;
+
+ m_bEditFlag = true;
+
+ OUString aString = m_xMEdit->get_text();
+
+ int nStartPos, nEndPos;
+ m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
+ if (nStartPos > nEndPos)
+ std::swap(nStartPos, nEndPos);
+
+ m_pHelper->setSelection(nStartPos, nEndPos);
+
+ if (nStartPos == 0)
+ {
+ nStartPos = 1;
+ m_xMEdit->select_region(nStartPos, nEndPos);
+ }
+ if (nStartPos != aString.getLength())
+ {
+ sal_Int32 nPos = nStartPos;
+
+ sal_Int32 nFStart = GetFunctionPos(nPos - 1);
+
+ if (nFStart < nPos)
+ {
+ sal_Int32 nPos1 = m_aFormulaHelper.GetFunctionEnd( aString, nFStart);
+
+ if (nPos1 > nPos)
+ {
+ EditThisFunc(nFStart);
+ }
+ else
+ {
+ sal_Int32 n = nPos;
+ short nCount = 1;
+ while(n > 0)
+ {
+ if (aString[n]==')')
+ nCount++;
+ else if (aString[n]=='(')
+ nCount--;
+ if (nCount == 0)
+ break;
+ n--;
+ }
+ if (nCount == 0)
+ {
+ nFStart = m_aFormulaHelper.GetFunctionStart( aString, n, true);
+ EditThisFunc(nFStart);
+ }
+ else
+ {
+ ClearAllParas();
+ }
+ }
+ }
+ else
+ {
+ ClearAllParas();
+ }
+ }
+ m_pHelper->setSelection(nStartPos, nEndPos);
+
+ m_bEditFlag = false;
+}
+
+void FormulaDlg_Impl::UpdateOldSel()
+{
+ m_xMEdit->get_selection_bounds(m_nSelectionStart, m_nSelectionEnd);
+ if (m_nSelectionStart > m_nSelectionEnd)
+ std::swap(m_nSelectionStart, m_nSelectionEnd);
+}
+
+IMPL_LINK_NOARG( FormulaDlg_Impl, FormulaCursorHdl, weld::TextView&, void)
+{
+ int nStartPos, nEndPos;
+ m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
+ if (nStartPos > nEndPos)
+ std::swap(nStartPos, nEndPos);
+
+ if (nStartPos != m_nSelectionStart || nEndPos != m_nSelectionEnd)
+ {
+ m_nSelectionStart = nStartPos;
+ m_nSelectionEnd = nEndPos;
+ FormulaCursor();
+ }
+}
+
+void FormulaDlg_Impl::UpdateSelection()
+{
+ m_pHelper->setSelection( m_aFuncSel.Min(), m_aFuncSel.Max());
+ if (m_pFuncDesc)
+ {
+ m_pHelper->setCurrentFormula( m_pFuncDesc->getFormula( m_aArguments ) );
+ m_nArgs = m_pFuncDesc->getSuppressedArgumentCount();
+ }
+ else
+ {
+ m_pHelper->setCurrentFormula("");
+ m_nArgs = 0;
+ }
+
+ m_xMEdit->set_text(m_pHelper->getCurrentFormula());
+ sal_Int32 PrivStart, PrivEnd;
+ m_pHelper->getSelection( PrivStart, PrivEnd);
+ m_aFuncSel.Min() = PrivStart;
+ m_aFuncSel.Max() = PrivEnd;
+
+ OUString aFormula = m_xMEdit->get_text();
+ sal_Int32 nArgPos = m_aFormulaHelper.GetArgStart( aFormula, PrivStart, 0);
+
+ sal_uInt16 nPos = m_xParaWin->GetActiveLine();
+ if (nPos >= m_aArguments.size())
+ {
+ SAL_WARN("formula.ui","FormulaDlg_Impl::UpdateSelection - shot in foot: nPos " <<
+ nPos << " >= m_aArguments.size() " << m_aArguments.size() <<
+ " for aFormula '" << aFormula << "'");
+ nPos = m_aArguments.size();
+ if (nPos)
+ --nPos;
+ }
+
+ for (sal_uInt16 i = 0; i < nPos; i++)
+ {
+ nArgPos += (m_aArguments[i].getLength() + 1);
+ }
+ sal_Int32 nLength = (nPos < m_aArguments.size()) ? m_aArguments[nPos].getLength() : 0;
+
+ m_pHelper->setSelection(nArgPos, nArgPos + nLength);
+ m_xMEdit->select_region(nArgPos, nArgPos + nLength);
+ UpdateOldSel();
+}
+
+::std::pair<RefButton*, RefEdit*> FormulaDlg_Impl::RefInputStartBefore(RefEdit* pEdit, RefButton* pButton)
+{
+ m_pTheRefEdit = pEdit;
+ m_pTheRefButton = pButton;
+
+ Selection aOrigSelection;
+ if (m_pTheRefEdit)
+ {
+ // grab selection before showing next widget in case the selection is blown away
+ // by it appearing
+ aOrigSelection = m_pTheRefEdit->GetSelection();
+ }
+
+ // because its initially hidden, give it its optimal size so clicking the
+ // refbutton has an initial size to work when retro-fitting this to .ui
+ m_xEdRef->GetWidget()->set_size_request(m_xEdRef->GetWidget()->get_preferred_size().Width(), -1);
+ m_xEdRef->GetWidget()->show();
+
+ if ( m_pTheRefEdit )
+ {
+ m_xEdRef->SetRefString(m_pTheRefEdit->GetText());
+ m_xEdRef->SetSelection(aOrigSelection);
+ m_xEdRef->GetWidget()->set_help_id(m_pTheRefEdit->GetWidget()->get_help_id());
+ }
+
+ m_xRefBtn->GetWidget()->set_visible(pButton != nullptr);
+
+ ::std::pair<RefButton*, RefEdit*> aPair;
+ aPair.first = pButton ? m_xRefBtn.get() : nullptr;
+ aPair.second = m_xEdRef.get();
+ return aPair;
+}
+
+void FormulaDlg_Impl::RefInputStartAfter()
+{
+ m_xRefBtn->SetEndImage();
+
+ if (!m_pTheRefEdit)
+ return;
+
+ OUString aStr = m_aTitle2 + " " + m_xFtEditName->get_label() + "( ";
+
+ if ( m_xParaWin->GetActiveLine() > 0 )
+ aStr += "...; ";
+ aStr += m_xParaWin->GetActiveArgName();
+ if ( m_xParaWin->GetActiveLine() + 1 < m_nArgs )
+ aStr += "; ...";
+ aStr += " )";
+
+ m_rDialog.set_title(m_rDialog.strip_mnemonic(aStr));
+}
+
+void FormulaDlg_Impl::RefInputDoneAfter( bool bForced )
+{
+ m_xRefBtn->SetStartImage();
+ if (!bForced && m_xRefBtn->GetWidget()->get_visible())
+ return;
+
+ m_xEdRef->GetWidget()->hide();
+ m_xRefBtn->GetWidget()->hide();
+ if ( m_pTheRefEdit )
+ {
+ m_pTheRefEdit->SetRefString( m_xEdRef->GetText() );
+ m_pTheRefEdit->GrabFocus();
+
+ if ( m_pTheRefButton )
+ m_pTheRefButton->SetStartImage();
+
+ sal_uInt16 nPrivActiv = m_xParaWin->GetActiveLine();
+ m_xParaWin->SetArgument( nPrivActiv, m_xEdRef->GetText() );
+ ModifyHdl( *m_xParaWin );
+ m_pTheRefEdit = nullptr;
+ }
+ m_rDialog.set_title(m_aTitle1);
+}
+
+RefEdit* FormulaDlg_Impl::GetCurrRefEdit()
+{
+ return m_xEdRef->GetWidget()->get_visible() ? m_xEdRef.get() : m_xParaWin->GetActiveEdit();
+}
+
+void FormulaDlg_Impl::Update()
+{
+ FormEditData* pData = m_pHelper->getFormEditData();
+ const OUString sExpression = m_xMEdit->get_text();
+ m_aOldFormula.clear();
+ UpdateTokenArray(sExpression);
+ FormulaCursor();
+ CalcStruct(sExpression);
+ if (pData->GetMode() == FormulaDlgMode::Formula)
+ m_xTabCtrl->set_current_page("function");
+ else
+ m_xTabCtrl->set_current_page("struct");
+ m_xBtnMatrix->set_active(pData->GetMatrixFlag());
+}
+
+void FormulaDlg_Impl::Update(const OUString& _sExp)
+{
+ CalcStruct(_sExp);
+ FillDialog();
+ FuncSelHdl(*m_xFuncPage);
+}
+
+void FormulaDlg_Impl::SetMeText(const OUString& _sText)
+{
+ FormEditData* pData = m_pHelper->getFormEditData();
+ m_xMEdit->set_text(_sText);
+ auto aSelection = pData->GetSelection();
+ m_xMEdit->select_region(aSelection.Min(), aSelection.Max());
+ UpdateOldSel();
+}
+
+FormulaDlgMode FormulaDlg_Impl::SetMeText( const OUString& _sText, sal_Int32 PrivStart, sal_Int32 PrivEnd, bool bMatrix, bool _bSelect, bool _bUpdate)
+{
+ FormulaDlgMode eMode = FormulaDlgMode::Formula;
+ if (!m_bEditFlag)
+ m_xMEdit->set_text(_sText);
+
+ if ( _bSelect || !m_bEditFlag )
+ m_xMEdit->select_region(PrivStart, PrivEnd);
+ if ( _bUpdate )
+ {
+ UpdateOldSel();
+ int nStartPos, nEndPos;
+ m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
+ if (nStartPos > nEndPos)
+ std::swap(nStartPos, nEndPos);
+ m_pHelper->showReference(m_xMEdit->get_text().copy(nStartPos, nEndPos - nStartPos));
+ eMode = FormulaDlgMode::Edit;
+
+ m_xBtnMatrix->set_active( bMatrix );
+ } // if ( _bUpdate )
+ return eMode;
+}
+
+bool FormulaDlg_Impl::CheckMatrix(OUString& aFormula)
+{
+ m_xMEdit->grab_focus();
+ sal_Int32 nLen = aFormula.getLength();
+ bool bMatrix = nLen > 3 // Matrix-Formula
+ && aFormula[0] == '{'
+ && aFormula[1] == '='
+ && aFormula[nLen-1] == '}';
+ if ( bMatrix )
+ {
+ aFormula = aFormula.copy( 1, aFormula.getLength()-2 );
+ m_xBtnMatrix->set_active( bMatrix );
+ m_xBtnMatrix->set_sensitive(false);
+ } // if ( bMatrix )
+
+ m_xTabCtrl->set_current_page("struct");
+ return bMatrix;
+}
+
+IMPL_LINK_NOARG( FormulaDlg_Impl, StructSelHdl, StructPage&, void)
+{
+ m_bStructUpdate = false;
+ if (m_xStructPage->IsVisible())
+ m_xBtnForward->set_sensitive(false); //@New
+ m_bStructUpdate = true;
+}
+
+IMPL_LINK_NOARG( FormulaDlg_Impl, MatrixHdl, weld::Toggleable&, void)
+{
+ m_bUserMatrixFlag = true;
+ UpdateValues(true);
+}
+
+IMPL_LINK_NOARG( FormulaDlg_Impl, FuncSelHdl, FuncPage&, void)
+{
+ if ( (m_xFuncPage->GetFunctionEntryCount() > 0)
+ && (m_xFuncPage->GetFunction() != -1) )
+ {
+ const IFunctionDescription* pDesc = m_xFuncPage->GetFuncDesc( m_xFuncPage->GetFunction() );
+
+ if (pDesc != m_pFuncDesc)
+ m_xBtnForward->set_sensitive(true); //new
+
+ if (pDesc)
+ {
+ pDesc->initArgumentInfo(); // full argument info is needed
+
+ OUString aSig = pDesc->getSignature();
+ m_xFtHeadLine->set_label( pDesc->getFunctionName() );
+ m_xFtFuncName->set_label( aSig );
+ m_xFtFuncDesc->set_label( pDesc->getDescription() );
+ }
+ }
+ else
+ {
+ m_xFtHeadLine->set_label( OUString() );
+ m_xFtFuncName->set_label( OUString() );
+ m_xFtFuncDesc->set_label( OUString() );
+ }
+}
+
+void FormulaDlg_Impl::UpdateParaWin( const Selection& _rSelection, const OUString& _sRefStr)
+{
+ Selection theSel = _rSelection;
+ m_xEdRef->GetWidget()->replace_selection(_sRefStr);
+ theSel.Max() = theSel.Min() + _sRefStr.getLength();
+ m_xEdRef->SetSelection( theSel );
+
+
+ // Manual Update of the results' fields:
+
+ sal_uInt16 nPrivActiv = m_xParaWin->GetActiveLine();
+ m_xParaWin->SetArgument( nPrivActiv, m_xEdRef->GetText());
+ m_xParaWin->UpdateParas();
+
+ RefEdit* pEd = GetCurrRefEdit();
+ if (pEd)
+ pEd->SetSelection( theSel );
+}
+
+bool FormulaDlg_Impl::UpdateParaWin(Selection& _rSelection)
+{
+ OUString aStrEd;
+ RefEdit* pEd = GetCurrRefEdit();
+ if (pEd && !m_pTheRefEdit)
+ {
+ _rSelection = pEd->GetSelection();
+ _rSelection.Justify();
+ aStrEd = pEd->GetText();
+ m_xEdRef->SetRefString(aStrEd);
+ m_xEdRef->SetSelection( _rSelection );
+ }
+ else
+ {
+ _rSelection = m_xEdRef->GetSelection();
+ _rSelection.Justify();
+ aStrEd = m_xEdRef->GetText();
+ }
+ return m_pTheRefEdit == nullptr;
+}
+
+void FormulaDlg_Impl::SetEdSelection()
+{
+ RefEdit* pEd = GetCurrRefEdit()/*aScParaWin.GetActiveEdit()*/;
+ if (pEd)
+ {
+ Selection theSel = m_xEdRef->GetSelection();
+ // Edit may have the focus -> call ModifyHdl in addition
+ // to what's happening in GetFocus
+ pEd->GetModifyHdl().Call(*pEd);
+ pEd->GrabFocus();
+ pEd->SetSelection(theSel);
+ } // if ( pEd )
+}
+
+FormulaModalDialog::FormulaModalDialog(weld::Window* pParent,
+ IFunctionManager const * _pFunctionMgr,
+ IControlReferenceHandler* _pDlg)
+ : GenericDialogController(pParent, "formula/ui/formuladialog.ui", "FormulaDialog")
+ , m_pImpl(new FormulaDlg_Impl(*m_xDialog, *m_xBuilder, false/*_bSupportFunctionResult*/,
+ false/*_bSupportResult*/, false/*_bSupportMatrix*/,
+ this, _pFunctionMgr, _pDlg))
+{
+ m_xDialog->set_title(m_pImpl->m_aTitle1);
+}
+
+FormulaModalDialog::~FormulaModalDialog() { }
+
+void FormulaModalDialog::Update(const OUString& _sExp)
+{
+ m_pImpl->Update(_sExp);
+}
+
+void FormulaModalDialog::SetMeText(const OUString& _sText)
+{
+ m_pImpl->SetMeText(_sText);
+}
+
+void FormulaModalDialog::CheckMatrix(OUString& aFormula)
+{
+ m_pImpl->CheckMatrix(aFormula);
+}
+
+void FormulaModalDialog::Update()
+{
+ m_pImpl->Update();
+}
+
+::std::pair<RefButton*, RefEdit*> FormulaModalDialog::RefInputStartBefore( RefEdit* pEdit, RefButton* pButton )
+{
+ return m_pImpl->RefInputStartBefore( pEdit, pButton );
+}
+
+void FormulaModalDialog::RefInputStartAfter()
+{
+ m_pImpl->RefInputStartAfter();
+}
+
+void FormulaModalDialog::RefInputDoneAfter()
+{
+ m_pImpl->RefInputDoneAfter( true/*bForced*/ );
+}
+
+void FormulaModalDialog::StoreFormEditData(FormEditData* pData)
+{
+ m_pImpl->StoreFormEditData(pData);
+}
+
+// Initialisation / General functions for Dialog
+FormulaDlg::FormulaDlg(SfxBindings* pB, SfxChildWindow* pCW,
+ weld::Window* pParent,
+ IFunctionManager const * _pFunctionMgr, IControlReferenceHandler* _pDlg)
+ : SfxModelessDialogController( pB, pCW, pParent, "formula/ui/formuladialog.ui", "FormulaDialog")
+ , m_pImpl(new FormulaDlg_Impl(*m_xDialog, *m_xBuilder, true/*_bSupportFunctionResult*/
+ , true/*_bSupportResult*/
+ , true/*_bSupportMatrix*/
+ , this, _pFunctionMgr, _pDlg))
+{
+ m_xDialog->set_title(m_pImpl->m_aTitle1);
+}
+
+FormulaDlg::~FormulaDlg()
+{
+}
+
+void FormulaDlg::Update(const OUString& _sExp)
+{
+ m_pImpl->Update(_sExp);
+}
+
+void FormulaDlg::SetMeText(const OUString& _sText)
+{
+ m_pImpl->SetMeText(_sText);
+}
+
+FormulaDlgMode FormulaDlg::SetMeText( const OUString& _sText, sal_Int32 PrivStart, sal_Int32 PrivEnd, bool bMatrix, bool _bSelect, bool _bUpdate)
+{
+ return m_pImpl->SetMeText( _sText, PrivStart, PrivEnd, bMatrix, _bSelect, _bUpdate);
+}
+
+bool FormulaDlg::CheckMatrix(OUString& aFormula)
+{
+ return m_pImpl->CheckMatrix(aFormula);
+}
+
+OUString FormulaDlg::GetMeText() const
+{
+ return m_pImpl->m_xMEdit->get_text();
+}
+
+void FormulaDlg::Update()
+{
+ m_pImpl->Update();
+}
+
+void FormulaDlg::DoEnter()
+{
+ m_pImpl->DoEnter(false);
+}
+
+::std::pair<RefButton*, RefEdit*> FormulaDlg::RefInputStartBefore( RefEdit* pEdit, RefButton* pButton )
+{
+ return m_pImpl->RefInputStartBefore( pEdit, pButton );
+}
+
+void FormulaDlg::RefInputStartAfter()
+{
+ m_pImpl->RefInputStartAfter();
+}
+
+void FormulaDlg::RefInputDoneAfter( bool bForced )
+{
+ m_pImpl->RefInputDoneAfter( bForced );
+}
+
+void FormulaDlg::disableOk()
+{
+ m_pImpl->m_xBtnEnd->set_sensitive(false);
+}
+
+void FormulaDlg::StoreFormEditData(FormEditData* pData)
+{
+ m_pImpl->StoreFormEditData(pData);
+}
+
+const IFunctionDescription* FormulaDlg::getCurrentFunctionDescription() const
+{
+ SAL_WARN_IF( (m_pImpl->m_pFuncDesc && m_pImpl->m_pFuncDesc->getSuppressedArgumentCount() != m_pImpl->m_nArgs),
+ "formula.ui", "FormulaDlg::getCurrentFunctionDescription: getSuppressedArgumentCount " <<
+ m_pImpl->m_pFuncDesc->getSuppressedArgumentCount() << " != m_nArgs " << m_pImpl->m_nArgs << " for " <<
+ m_pImpl->m_pFuncDesc->getFunctionName());
+ return m_pImpl->m_pFuncDesc;
+}
+
+void FormulaDlg::UpdateParaWin( const Selection& _rSelection, const OUString& _sRefStr)
+{
+ m_pImpl->UpdateParaWin( _rSelection, _sRefStr);
+}
+
+bool FormulaDlg::UpdateParaWin(Selection& _rSelection)
+{
+ return m_pImpl->UpdateParaWin(_rSelection);
+}
+
+RefEdit* FormulaDlg::GetActiveEdit()
+{
+ return m_pImpl->m_xParaWin->GetActiveEdit();
+}
+
+const FormulaHelper& FormulaDlg::GetFormulaHelper() const
+{
+ return m_pImpl->GetFormulaHelper();
+}
+
+void FormulaDlg::SetEdSelection()
+{
+ m_pImpl->SetEdSelection();
+}
+
+void FormEditData::SaveValues()
+{
+ Reset();
+}
+
+void FormEditData::Reset()
+{
+ nMode = FormulaDlgMode::Formula;
+ nFStart = 0;
+ nOffset = 0;
+ bMatrix = false;
+ aSelection.Min() = 0;
+ aSelection.Max() = 0;
+ aUndoStr.clear();
+}
+
+FormEditData& FormEditData::operator=( const FormEditData& r )
+{
+ nMode = r.nMode;
+ nFStart = r.nFStart;
+ nOffset = r.nOffset;
+ aUndoStr = r.aUndoStr;
+ bMatrix = r.bMatrix ;
+ aSelection = r.aSelection;
+ return *this;
+}
+
+FormEditData::FormEditData()
+{
+ Reset();
+}
+
+FormEditData::~FormEditData()
+{
+}
+
+FormEditData::FormEditData( const FormEditData& r )
+{
+ *this = r;
+}
+
+
+} // formula
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/formula/source/ui/dlg/funcpage.cxx b/formula/source/ui/dlg/funcpage.cxx
new file mode 100644
index 000000000..553517ce7
--- /dev/null
+++ b/formula/source/ui/dlg/funcpage.cxx
@@ -0,0 +1,257 @@
+/* -*- 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 <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <formula/IFunctionDescription.hxx>
+
+#include "funcpage.hxx"
+#include <unotools/syslocale.hxx>
+#include <unotools/charclass.hxx>
+
+namespace formula
+{
+IMPL_LINK(FuncPage, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ if (rKEvt.GetCharCode() == ' ')
+ {
+ aDoubleClickLink.Call(*this);
+ return true;
+ }
+ return false;
+}
+
+FuncPage::FuncPage(weld::Container* pParent, const IFunctionManager* _pFunctionManager)
+ : m_xBuilder(Application::CreateBuilder(pParent, "formula/ui/functionpage.ui"))
+ , m_xContainer(m_xBuilder->weld_container("FunctionPage"))
+ , m_xLbCategory(m_xBuilder->weld_combo_box("category"))
+ , m_xLbFunction(m_xBuilder->weld_tree_view("function"))
+ , m_xLbFunctionSearchString(m_xBuilder->weld_entry("search"))
+ , m_pFunctionManager(_pFunctionManager)
+{
+ m_xLbFunction->make_sorted();
+ m_aHelpId = m_xLbFunction->get_help_id();
+
+ m_pFunctionManager->fillLastRecentlyUsedFunctions(aLRUList);
+
+ const sal_uInt32 nCategoryCount = m_pFunctionManager->getCount();
+ for (sal_uInt32 j = 0; j < nCategoryCount; ++j)
+ {
+ const IFunctionCategory* pCategory = m_pFunctionManager->getCategory(j);
+ OUString sId(weld::toId(pCategory));
+ m_xLbCategory->append(sId, pCategory->getName());
+ }
+
+ m_xLbCategory->set_active(1);
+ OUString searchStr = m_xLbFunctionSearchString->get_text();
+ UpdateFunctionList(searchStr);
+ // lock to its initial size
+ m_xLbFunction->set_size_request(m_xLbFunction->get_preferred_size().Width(),
+ m_xLbFunction->get_height_rows(15));
+ m_xLbCategory->connect_changed(LINK(this, FuncPage, SelComboBoxHdl));
+ m_xLbFunction->connect_changed(LINK(this, FuncPage, SelTreeViewHdl));
+ m_xLbFunction->connect_row_activated(LINK(this, FuncPage, DblClkHdl));
+ m_xLbFunction->connect_key_press(LINK(this, FuncPage, KeyInputHdl));
+ m_xLbFunctionSearchString->connect_changed(LINK(this, FuncPage, ModifyHdl));
+
+ m_xLbFunctionSearchString->grab_focus();
+}
+
+FuncPage::~FuncPage() {}
+
+void FuncPage::impl_addFunctions(const IFunctionCategory* _pCategory)
+{
+ const sal_uInt32 nCount = _pCategory->getCount();
+ for (sal_uInt32 i = 0; i < nCount; ++i)
+ {
+ TFunctionDesc pDesc(_pCategory->getFunction(i));
+ if (!pDesc->isHidden())
+ {
+ OUString sId(weld::toId(pDesc));
+ m_xLbFunction->append(sId, pDesc->getFunctionName());
+ }
+ }
+}
+
+//aStr is non-empty when user types in the search box to search some function
+void FuncPage::UpdateFunctionList(const OUString& aStr)
+{
+ m_xLbFunction->clear();
+ m_xLbFunction->freeze();
+
+ const sal_Int32 nSelPos = m_xLbCategory->get_active();
+
+ if (aStr.isEmpty() || nSelPos == 0)
+ {
+ const IFunctionCategory* pCategory
+ = weld::fromId<const IFunctionCategory*>(m_xLbCategory->get_id(nSelPos));
+
+ if (nSelPos > 0)
+ {
+ if (pCategory == nullptr)
+ {
+ const sal_uInt32 nCount = m_pFunctionManager->getCount();
+ for (sal_uInt32 i = 0; i < nCount; ++i)
+ {
+ impl_addFunctions(m_pFunctionManager->getCategory(i));
+ }
+ }
+ else
+ {
+ impl_addFunctions(pCategory);
+ }
+ }
+ else // LRU-List
+ {
+ for (auto const& elem : aLRUList)
+ {
+ if (elem) // may be null if a function is no longer available
+ {
+ OUString sId(weld::toId(elem));
+ m_xLbFunction->append(sId, elem->getFunctionName());
+ }
+ }
+ }
+ }
+ else
+ {
+ SvtSysLocale aSysLocale;
+ const CharClass& rCharClass = aSysLocale.GetCharClass();
+ const OUString aSearchStr(rCharClass.uppercase(aStr));
+
+ const sal_uInt32 nCategoryCount = m_pFunctionManager->getCount();
+ // Category listbox holds additional entries for Last Used and All, so
+ // the offset should be two but hard coded numbers are ugly...
+ const sal_Int32 nCategoryOffset = m_xLbCategory->get_count() - nCategoryCount;
+ // If a real category (not Last Used or All) is selected, list only
+ // functions of that category. Else list all, LRU is handled above.
+ sal_Int32 nCatBeg = (nSelPos == -1 ? -1 : nSelPos - nCategoryOffset);
+ sal_uInt32 nCatEnd;
+ if (nCatBeg < 0)
+ {
+ nCatBeg = 0;
+ nCatEnd = nCategoryCount;
+ }
+ else
+ {
+ nCatEnd = nCatBeg + 1;
+ }
+ for (sal_uInt32 i = nCatBeg; i < nCatEnd; ++i)
+ {
+ const IFunctionCategory* pCategory = m_pFunctionManager->getCategory(i);
+ const sal_uInt32 nFunctionCount = pCategory->getCount();
+ for (sal_uInt32 j = 0; j < nFunctionCount; ++j)
+ {
+ TFunctionDesc pDesc(pCategory->getFunction(j));
+ if (rCharClass.uppercase(pDesc->getFunctionName()).indexOf(aSearchStr) >= 0)
+ {
+ if (!pDesc->isHidden())
+ {
+ OUString sId(weld::toId(pDesc));
+ m_xLbFunction->append(sId, pDesc->getFunctionName());
+ }
+ }
+ }
+ }
+ }
+
+ m_xLbFunction->thaw();
+ // Ensure no function is selected so the Next button doesn't overwrite a
+ // function that is not in the list with an arbitrary selected one.
+ m_xLbFunction->unselect_all();
+
+ if (IsVisible())
+ SelTreeViewHdl(*m_xLbFunction);
+}
+
+IMPL_LINK_NOARG(FuncPage, SelComboBoxHdl, weld::ComboBox&, void)
+{
+ OUString searchStr = m_xLbFunctionSearchString->get_text();
+ m_xLbFunction->set_help_id(m_aHelpId);
+ UpdateFunctionList(searchStr);
+}
+
+IMPL_LINK_NOARG(FuncPage, SelTreeViewHdl, weld::TreeView&, void)
+{
+ const IFunctionDescription* pDesc = GetFuncDesc(GetFunction());
+ if (pDesc)
+ {
+ const OString sHelpId = pDesc->getHelpId();
+ if (!sHelpId.isEmpty())
+ m_xLbFunction->set_help_id(sHelpId);
+ }
+ aSelectionLink.Call(*this);
+}
+
+IMPL_LINK_NOARG(FuncPage, DblClkHdl, weld::TreeView&, bool)
+{
+ aDoubleClickLink.Call(*this);
+ return true;
+}
+
+IMPL_LINK_NOARG(FuncPage, ModifyHdl, weld::Entry&, void)
+{
+ // While typing select All category.
+ m_xLbCategory->set_active(1);
+ OUString searchStr = m_xLbFunctionSearchString->get_text();
+ UpdateFunctionList(searchStr);
+}
+
+void FuncPage::SetCategory(sal_Int32 nCat)
+{
+ m_xLbCategory->set_active(nCat);
+ UpdateFunctionList(OUString());
+}
+
+sal_Int32 FuncPage::GetFuncPos(const IFunctionDescription* _pDesc)
+{
+ return m_xLbFunction->find_id(weld::toId(_pDesc));
+}
+
+void FuncPage::SetFunction(sal_Int32 nFunc)
+{
+ if (nFunc == -1)
+ m_xLbFunction->unselect_all();
+ else
+ m_xLbFunction->select(nFunc);
+}
+
+void FuncPage::SetFocus() { m_xLbFunction->grab_focus(); }
+
+sal_Int32 FuncPage::GetCategory() const { return m_xLbCategory->get_active(); }
+
+sal_Int32 FuncPage::GetCategoryEntryCount() const { return m_xLbCategory->get_count(); }
+
+sal_Int32 FuncPage::GetFunction() const { return m_xLbFunction->get_selected_index(); }
+
+sal_Int32 FuncPage::GetFunctionEntryCount() const { return m_xLbFunction->n_children(); }
+
+OUString FuncPage::GetSelFunctionName() const { return m_xLbFunction->get_selected_text(); }
+
+const IFunctionDescription* FuncPage::GetFuncDesc(sal_Int32 nPos) const
+{
+ if (nPos == -1)
+ return nullptr;
+ // not pretty, but hopefully rare
+ return weld::fromId<const IFunctionDescription*>(m_xLbFunction->get_id(nPos));
+}
+
+} // formula
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/formula/source/ui/dlg/funcpage.hxx b/formula/source/ui/dlg/funcpage.hxx
new file mode 100644
index 000000000..6254dfc8a
--- /dev/null
+++ b/formula/source/ui/dlg/funcpage.hxx
@@ -0,0 +1,87 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+#include <vector>
+
+namespace formula
+{
+
+class IFunctionDescription;
+class IFunctionManager;
+class IFunctionCategory;
+
+typedef const IFunctionDescription* TFunctionDesc;
+
+class FuncPage final
+{
+private:
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Container> m_xContainer;
+
+ std::unique_ptr<weld::ComboBox> m_xLbCategory;
+ std::unique_ptr<weld::TreeView> m_xLbFunction;
+ std::unique_ptr<weld::Entry> m_xLbFunctionSearchString;
+
+ Link<FuncPage&,void> aDoubleClickLink;
+ Link<FuncPage&,void> aSelectionLink;
+ const IFunctionManager* m_pFunctionManager;
+
+ ::std::vector< TFunctionDesc > aLRUList;
+ OString m_aHelpId;
+
+ void impl_addFunctions(const IFunctionCategory* _pCategory);
+
+ DECL_LINK(SelComboBoxHdl, weld::ComboBox&, void);
+ DECL_LINK(SelTreeViewHdl, weld::TreeView&, void);
+ DECL_LINK(DblClkHdl, weld::TreeView&, bool);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(ModifyHdl, weld::Entry&, void);
+
+ void UpdateFunctionList(const OUString&);
+
+public:
+
+ FuncPage(weld::Container* pContainer, const IFunctionManager* _pFunctionManager);
+ ~FuncPage();
+
+ void SetCategory(sal_Int32 nCat);
+ void SetFunction(sal_Int32 nFunc);
+ void SetFocus();
+ sal_Int32 GetCategory() const;
+ sal_Int32 GetCategoryEntryCount() const;
+ sal_Int32 GetFunction() const;
+ sal_Int32 GetFunctionEntryCount() const;
+
+ sal_Int32 GetFuncPos(const IFunctionDescription* _pDesc);
+ const IFunctionDescription* GetFuncDesc( sal_Int32 nPos ) const;
+ OUString GetSelFunctionName() const;
+
+ void SetDoubleClickHdl( const Link<FuncPage&,void>& rLink ) { aDoubleClickLink = rLink; }
+
+ void SetSelectHdl( const Link<FuncPage&,void>& rLink ) { aSelectionLink = rLink; }
+
+ bool IsVisible() const { return m_xContainer->get_visible(); }
+};
+
+} // formula
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/formula/source/ui/dlg/funcutl.cxx b/formula/source/ui/dlg/funcutl.cxx
new file mode 100644
index 000000000..58c2492c5
--- /dev/null
+++ b/formula/source/ui/dlg/funcutl.cxx
@@ -0,0 +1,486 @@
+/* -*- 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 <vcl/event.hxx>
+
+#include <formula/funcutl.hxx>
+#include <formula/IControlReferenceHandler.hxx>
+#include <vcl/svapp.hxx>
+#include "ControlHelper.hxx"
+#include "parawin.hxx"
+#include <strings.hrc>
+#include <bitmaps.hlst>
+#include <core_resource.hxx>
+
+namespace formula
+{
+
+ArgEdit::ArgEdit(std::unique_ptr<weld::Entry> xControl)
+ : RefEdit(std::move(xControl))
+ , pEdPrev(nullptr)
+ , pEdNext(nullptr)
+ , pSlider(nullptr)
+ , pParaWin(nullptr)
+ , nArgs(0)
+{
+}
+
+void ArgEdit::Init(ArgEdit* pPrevEdit, ArgEdit* pNextEdit,
+ weld::ScrolledWindow& rArgSlider,
+ ParaWin& rParaWin, sal_uInt16 nArgCount)
+{
+ pEdPrev = pPrevEdit;
+ pEdNext = pNextEdit;
+ pSlider = &rArgSlider;
+ pParaWin = &rParaWin;
+ nArgs = nArgCount;
+}
+
+// Cursor control for Edit Fields in Argument Dialog
+bool ArgEdit::KeyInput(const KeyEvent& rKEvt)
+{
+ vcl::KeyCode aCode = rKEvt.GetKeyCode();
+ bool bUp = (aCode.GetCode() == KEY_UP);
+ bool bDown = (aCode.GetCode() == KEY_DOWN);
+
+ if ( pSlider
+ && ( !aCode.IsShift() && !aCode.IsMod1() && !aCode.IsMod2() )
+ && ( bUp || bDown ) )
+ {
+ if ( nArgs > 1 )
+ {
+ ArgEdit* pEd = nullptr;
+ int nThumb = pSlider->vadjustment_get_value();
+ bool bDoScroll = false;
+ bool bChangeFocus = false;
+
+ if ( bDown )
+ {
+ if ( nArgs > 4 )
+ {
+ if ( !pEdNext )
+ {
+ nThumb++;
+ bDoScroll = ( nThumb+3 < static_cast<tools::Long>(nArgs) );
+ }
+ else
+ {
+ pEd = pEdNext;
+ bChangeFocus = true;
+ }
+ }
+ else if ( pEdNext )
+ {
+ pEd = pEdNext;
+ bChangeFocus = true;
+ }
+ }
+ else // if ( bUp )
+ {
+ if ( nArgs > 4 )
+ {
+ if ( !pEdPrev )
+ {
+ nThumb--;
+ bDoScroll = ( nThumb >= 0 );
+ }
+ else
+ {
+ pEd = pEdPrev;
+ bChangeFocus = true;
+ }
+ }
+ else if ( pEdPrev )
+ {
+ pEd = pEdPrev;
+ bChangeFocus = true;
+ }
+ }
+
+ if ( bDoScroll )
+ {
+ pSlider->vadjustment_set_value( nThumb );
+ pParaWin->SliderMoved();
+ }
+ else if ( bChangeFocus )
+ {
+ pEd->GrabFocus();
+ }
+ }
+ return true;
+ }
+ return RefEdit::KeyInput(rKEvt);
+}
+
+ArgInput::ArgInput()
+{
+ pFtArg=nullptr;
+ pBtnFx=nullptr;
+ pEdArg=nullptr;
+ pRefBtn=nullptr;
+}
+
+void ArgInput::InitArgInput(weld::Label* pftArg, weld::Button* pbtnFx,
+ ArgEdit* pedArg, RefButton* prefBtn)
+{
+ pFtArg =pftArg;
+ pBtnFx =pbtnFx;
+ pEdArg =pedArg;
+ pRefBtn=prefBtn;
+
+ if(pBtnFx!=nullptr)
+ {
+ pBtnFx->connect_clicked( LINK( this, ArgInput, FxBtnClickHdl ) );
+ pBtnFx->connect_focus_in( LINK( this, ArgInput, FxBtnFocusHdl ) );
+ }
+ if(pEdArg!=nullptr)
+ {
+ pEdArg->SetGetFocusHdl ( LINK( this, ArgInput, EdFocusHdl ) );
+ pEdArg->SetModifyHdl ( LINK( this, ArgInput, EdModifyHdl ) );
+ }
+}
+
+// Sets the Name for the Argument
+void ArgInput::SetArgName(const OUString &aArg)
+{
+ if (pFtArg)
+ pFtArg->set_label(aArg );
+}
+
+// Returns the Name for the Argument
+OUString ArgInput::GetArgName() const
+{
+ OUString aPrivArgName;
+ if (pFtArg)
+ aPrivArgName = pFtArg->get_label();
+ return aPrivArgName;
+}
+
+//Sets the Name for the Argument
+void ArgInput::SetArgNameFont(const vcl::Font &aFont)
+{
+ if (pFtArg)
+ pFtArg->set_font(aFont);
+}
+
+//Sets up the Selection for the EditBox.
+void ArgInput::SelectAll()
+{
+ if (pEdArg)
+ pEdArg->SelectAll();
+}
+
+//Sets the Value for the Argument
+void ArgInput::SetArgVal(const OUString &rVal)
+{
+ if (pEdArg)
+ pEdArg->SetRefString(rVal);
+}
+
+//Returns the Value for the Argument
+OUString ArgInput::GetArgVal() const
+{
+ OUString aResult;
+ if (pEdArg)
+ aResult=pEdArg->GetText();
+ return aResult;
+}
+
+//Hides the Controls
+void ArgInput::Hide()
+{
+ if (pFtArg && pBtnFx && pEdArg && pRefBtn)
+ {
+ pFtArg->hide();
+ pBtnFx->hide();
+ pEdArg->GetWidget()->hide();
+ pRefBtn->GetWidget()->hide();
+ }
+}
+
+//Casts the Controls again.
+void ArgInput::Show()
+{
+ if (pFtArg && pBtnFx && pEdArg && pRefBtn)
+ {
+ pFtArg->show();
+ pBtnFx->show();
+ pEdArg->GetWidget()->show();
+ pRefBtn->GetWidget()->show();
+ }
+}
+
+void ArgInput::UpdateAccessibleNames()
+{
+ OUString aArgName = ":" + pFtArg->get_label();
+
+ OUString aName = pBtnFx->get_tooltip_text() + aArgName;
+ pBtnFx->set_accessible_name(aName);
+
+ aName = pRefBtn->GetWidget()->get_tooltip_text() + aArgName;
+ pRefBtn->GetWidget()->set_accessible_name(aName);
+}
+
+IMPL_LINK(ArgInput, FxBtnClickHdl, weld::Button&, rBtn, void)
+{
+ if (&rBtn == pBtnFx)
+ aFxClickLink.Call(*this);
+}
+
+IMPL_LINK( ArgInput, FxBtnFocusHdl, weld::Widget&, rControl, void )
+{
+ if (&rControl == pBtnFx)
+ aFxFocusLink.Call(*this);
+}
+
+IMPL_LINK( ArgInput, EdFocusHdl, RefEdit&, rControl, void )
+{
+ if (&rControl == pEdArg)
+ aEdFocusLink.Call(*this);
+}
+
+IMPL_LINK( ArgInput, EdModifyHdl, RefEdit&, rEdit, void )
+{
+ if (&rEdit == pEdArg)
+ aEdModifyLink.Call(*this);
+}
+
+RefEdit::RefEdit(std::unique_ptr<weld::Entry> xControl)
+ : xEntry(std::move(xControl))
+ , aIdle("formula RefEdit Idle")
+ , pAnyRefDlg(nullptr)
+ , pLabelWidget(nullptr)
+ , mpFocusInEvent(nullptr)
+ , mpFocusOutEvent(nullptr)
+{
+ xEntry->connect_focus_in(LINK(this, RefEdit, GetFocusHdl));
+ xEntry->connect_focus_out(LINK(this, RefEdit, LoseFocusHdl));
+ xEntry->connect_key_press(LINK(this, RefEdit, KeyInputHdl));
+ xEntry->connect_changed(LINK(this, RefEdit, Modify));
+ aIdle.SetInvokeHandler( LINK( this, RefEdit, UpdateHdl ) );
+}
+
+RefEdit::~RefEdit()
+{
+ if (mpFocusInEvent)
+ Application::RemoveUserEvent(mpFocusInEvent);
+ if (mpFocusOutEvent)
+ Application::RemoveUserEvent(mpFocusOutEvent);
+ aIdle.ClearInvokeHandler();
+ aIdle.Stop();
+}
+
+void RefEdit::SetRefString( const OUString& rStr )
+{
+ // Prevent unwanted side effects by setting only a differing string.
+ // See commit message for reasons.
+ if (xEntry->get_text() != rStr)
+ xEntry->set_text(rStr);
+}
+
+void RefEdit::SetRefValid(bool bValid)
+{
+ xEntry->set_message_type(bValid ? weld::EntryMessageType::Normal : weld::EntryMessageType::Error);
+}
+
+void RefEdit::SetText(const OUString& rStr)
+{
+ xEntry->set_text(rStr);
+ UpdateHdl( &aIdle );
+}
+
+void RefEdit::StartUpdateData()
+{
+ aIdle.Start();
+}
+
+void RefEdit::SetReferences(IControlReferenceHandler* pDlg, weld::Label* pLabel)
+{
+ pAnyRefDlg = pDlg;
+ pLabelWidget = pLabel;
+
+ if( pDlg )
+ {
+ aIdle.SetInvokeHandler(LINK(this, RefEdit, UpdateHdl));
+ }
+ else
+ {
+ aIdle.ClearInvokeHandler();
+ aIdle.Stop();
+ }
+}
+
+IMPL_LINK_NOARG(RefEdit, Modify, weld::Entry&, void)
+{
+ maModifyHdl.Call(*this);
+ if (pAnyRefDlg)
+ pAnyRefDlg->HideReference();
+}
+
+IMPL_LINK(RefEdit, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ return KeyInput(rKEvt);
+}
+
+bool RefEdit::KeyInput(const KeyEvent& rKEvt)
+{
+ const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
+ if (pAnyRefDlg && !rKeyCode.GetModifier() && rKeyCode.GetCode() == KEY_F2)
+ {
+ pAnyRefDlg->ReleaseFocus( this );
+ return true;
+ }
+
+ switch (rKeyCode.GetCode())
+ {
+ case KEY_RETURN:
+ case KEY_ESCAPE:
+ return maActivateHdl.Call(*GetWidget());
+ }
+
+ return false;
+}
+
+void RefEdit::GetFocus()
+{
+ maGetFocusHdl.Call(*this);
+ StartUpdateData();
+}
+
+void RefEdit::LoseFocus()
+{
+ maLoseFocusHdl.Call(*this);
+ if( pAnyRefDlg )
+ pAnyRefDlg->HideReference();
+}
+
+IMPL_LINK_NOARG(RefEdit, GetFocusHdl, weld::Widget&, void)
+{
+ // in e.g. function wizard RefEdits we want to select all when we get focus
+ // but in the gtk case there are pending gtk handlers which change selection
+ // after our handler, so post our focus in event to happen after those complete
+ if (mpFocusInEvent)
+ Application::RemoveUserEvent(mpFocusInEvent);
+ mpFocusInEvent = Application::PostUserEvent(LINK(this, RefEdit, AsyncFocusInHdl));
+}
+
+IMPL_LINK_NOARG(RefEdit, LoseFocusHdl, weld::Widget&, void)
+{
+ // tdf#127262 because focus in is async, focus out must not appear out
+ // of sequence to focus in
+ if (mpFocusOutEvent)
+ Application::RemoveUserEvent(mpFocusOutEvent);
+ mpFocusOutEvent = Application::PostUserEvent(LINK(this, RefEdit, AsyncFocusOutHdl));
+}
+
+IMPL_LINK_NOARG(RefEdit, AsyncFocusInHdl, void*, void)
+{
+ mpFocusInEvent = nullptr;
+ GetFocus();
+}
+
+IMPL_LINK_NOARG(RefEdit, AsyncFocusOutHdl, void*, void)
+{
+ mpFocusOutEvent = nullptr;
+ LoseFocus();
+}
+
+IMPL_LINK_NOARG(RefEdit, UpdateHdl, Timer *, void)
+{
+ if( pAnyRefDlg )
+ pAnyRefDlg->ShowReference(xEntry->get_text());
+}
+
+RefButton::RefButton(std::unique_ptr<weld::Button> xControl)
+ : xButton(std::move(xControl))
+ , pAnyRefDlg( nullptr )
+ , pRefEdit( nullptr )
+{
+ xButton->connect_focus_in(LINK(this, RefButton, GetFocus));
+ xButton->connect_focus_out(LINK(this, RefButton, LoseFocus));
+ xButton->connect_key_press(LINK(this, RefButton, KeyInput));
+ xButton->connect_clicked(LINK(this, RefButton, Click));
+ SetStartImage();
+}
+
+RefButton::~RefButton()
+{
+}
+
+void RefButton::SetStartImage()
+{
+ xButton->set_from_icon_name(RID_BMP_REFBTN1);
+ xButton->set_tooltip_text(ForResId(RID_STR_SHRINK));
+}
+
+void RefButton::SetEndImage()
+{
+ xButton->set_from_icon_name(RID_BMP_REFBTN2);
+ xButton->set_tooltip_text(ForResId(RID_STR_EXPAND));
+}
+
+void RefButton::SetReferences( IControlReferenceHandler* pDlg, RefEdit* pEdit )
+{
+ pAnyRefDlg = pDlg;
+ pRefEdit = pEdit;
+}
+
+IMPL_LINK_NOARG(RefButton, Click, weld::Button&, void)
+{
+ maClickHdl.Call(*this);
+ if( pAnyRefDlg )
+ pAnyRefDlg->ToggleCollapsed( pRefEdit, this );
+}
+
+IMPL_LINK(RefButton, KeyInput, const KeyEvent&, rKEvt, bool)
+{
+ const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
+ if (pAnyRefDlg && !rKeyCode.GetModifier() && rKeyCode.GetCode() == KEY_F2)
+ {
+ pAnyRefDlg->ReleaseFocus( pRefEdit );
+ return true;
+ }
+
+ switch (rKeyCode.GetCode())
+ {
+ case KEY_RETURN:
+ case KEY_ESCAPE:
+ return maActivateHdl.Call(*GetWidget());
+ }
+
+ return false;
+}
+
+IMPL_LINK_NOARG(RefButton, GetFocus, weld::Widget&, void)
+{
+ maGetFocusHdl.Call(*this);
+ if (pRefEdit)
+ pRefEdit->StartUpdateData();
+}
+
+IMPL_LINK_NOARG(RefButton, LoseFocus, weld::Widget&, void)
+{
+ maLoseFocusHdl.Call(*this);
+ if (pRefEdit)
+ pRefEdit->DoModify();
+}
+
+} // formula
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/formula/source/ui/dlg/parawin.cxx b/formula/source/ui/dlg/parawin.cxx
new file mode 100644
index 000000000..1eaba4d19
--- /dev/null
+++ b/formula/source/ui/dlg/parawin.cxx
@@ -0,0 +1,600 @@
+/* -*- 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>
+
+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, "formula/ui/parameter.ui"))
+ , m_xContainer(m_xBuilder->weld_container("ParameterPage"))
+ , m_xSlider(m_xBuilder->weld_scrolled_window("scrollbar", true))
+ , m_xParamGrid(m_xBuilder->weld_widget("paramgrid"))
+ , m_xGrid(m_xBuilder->weld_widget("grid"))
+ , m_xFtEditDesc(m_xBuilder->weld_label("editdesc"))
+ , m_xFtArgName(m_xBuilder->weld_label("parname"))
+ , m_xFtArgDesc(m_xBuilder->weld_label("pardesc"))
+ , m_xBtnFx1(m_xBuilder->weld_button("FX1"))
+ , m_xBtnFx2(m_xBuilder->weld_button("FX2"))
+ , m_xBtnFx3(m_xBuilder->weld_button("FX3"))
+ , m_xBtnFx4(m_xBuilder->weld_button("FX4"))
+ , m_xFtArg1(m_xBuilder->weld_label("FT_ARG1"))
+ , m_xFtArg2(m_xBuilder->weld_label("FT_ARG2"))
+ , m_xFtArg3(m_xBuilder->weld_label("FT_ARG3"))
+ , m_xFtArg4(m_xBuilder->weld_label("FT_ARG4"))
+ , m_xEdArg1(new ArgEdit(m_xBuilder->weld_entry("ED_ARG1")))
+ , m_xEdArg2(new ArgEdit(m_xBuilder->weld_entry("ED_ARG2")))
+ , m_xEdArg3(new ArgEdit(m_xBuilder->weld_entry("ED_ARG3")))
+ , m_xEdArg4(new ArgEdit(m_xBuilder->weld_entry("ED_ARG4")))
+ , m_xRefBtn1(new RefButton(m_xBuilder->weld_button("RB_ARG1")))
+ , m_xRefBtn2(new RefButton(m_xBuilder->weld_button("RB_ARG2")))
+ , m_xRefBtn3(new RefButton(m_xBuilder->weld_button("RB_ARG3")))
+ , m_xRefBtn4(new RefButton(m_xBuilder->weld_button("RB_ARG4")))
+{
+ // Space for three lines of text in function description.
+ m_xFtEditDesc->set_label("X\nX\nX\n");
+ auto nEditHeight = m_xFtEditDesc->get_preferred_size().Height();
+ m_xFtEditDesc->set_size_request(-1, nEditHeight);
+ m_xFtEditDesc->set_label("");
+ // Space for two lines of text in parameter description.
+ m_xFtArgDesc->set_label("X\nX\n");
+ auto nArgHeight = m_xFtArgDesc->get_preferred_size().Height();
+ m_xFtArgDesc->set_size_request(-1, nArgHeight);
+ m_xFtArgDesc->set_label("");
+
+ 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 )
+ aArgName += OUString::number( (nArg-nVarArgsStart)/2 + 1 );
+ 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 )
+ {
+ OUString aArgName = pFuncDesc->getParameterName(nRealArg) +
+ OUString::number( (nArg-nVarArgsStart)/2 + 1 );
+ 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);
+ OString 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 < SAL_N_ELEMENTS(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: */
diff --git a/formula/source/ui/dlg/parawin.hxx b/formula/source/ui/dlg/parawin.hxx
new file mode 100644
index 000000000..b2fe7ece6
--- /dev/null
+++ b/formula/source/ui/dlg/parawin.hxx
@@ -0,0 +1,145 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <formula/funcutl.hxx>
+#include <vcl/weld.hxx>
+#include "ControlHelper.hxx"
+#include <vector>
+
+namespace formula
+{
+
+#define NOT_FOUND 0xffff
+
+class IFunctionDescription;
+class IControlReferenceHandler;
+
+class ParaWin
+{
+private:
+ Link<ParaWin&,void> aFxLink;
+ Link<ParaWin&,void> aArgModifiedLink;
+
+ ::std::vector<sal_uInt16> aVisibleArgMapping;
+ const IFunctionDescription* pFuncDesc;
+ IControlReferenceHandler* pMyParent;
+ sal_uInt16 nArgs; // unsuppressed arguments, may be >= VAR_ARGS to indicate repeating parameters
+ sal_uInt16 nMaxArgs; // max arguments, limited to supported number of arguments
+ vcl::Font aFntBold;
+ vcl::Font aFntLight;
+
+ OUString m_sOptional;
+ OUString m_sRequired;
+
+ sal_uInt16 nEdFocus;
+ sal_uInt16 nActiveLine;
+
+ ArgInput aArgInput[4];
+ OUString aDefaultString;
+ ::std::vector<OUString> aParaArray;
+
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Container> m_xContainer;
+
+ std::unique_ptr<weld::ScrolledWindow> m_xSlider;
+ std::unique_ptr<weld::Widget> m_xParamGrid;
+ std::unique_ptr<weld::Widget> m_xGrid;
+
+ std::unique_ptr<weld::Label> m_xFtEditDesc;
+ std::unique_ptr<weld::Label> m_xFtArgName;
+ std::unique_ptr<weld::Label> m_xFtArgDesc;
+
+ std::unique_ptr<weld::Button> m_xBtnFx1;
+ std::unique_ptr<weld::Button> m_xBtnFx2;
+ std::unique_ptr<weld::Button> m_xBtnFx3;
+ std::unique_ptr<weld::Button> m_xBtnFx4;
+
+ std::unique_ptr<weld::Label> m_xFtArg1;
+ std::unique_ptr<weld::Label> m_xFtArg2;
+ std::unique_ptr<weld::Label> m_xFtArg3;
+ std::unique_ptr<weld::Label> m_xFtArg4;
+
+ std::unique_ptr<ArgEdit> m_xEdArg1;
+ std::unique_ptr<ArgEdit> m_xEdArg2;
+ std::unique_ptr<ArgEdit> m_xEdArg3;
+ std::unique_ptr<ArgEdit> m_xEdArg4;
+
+ std::unique_ptr<RefButton> m_xRefBtn1;
+ std::unique_ptr<RefButton> m_xRefBtn2;
+ std::unique_ptr<RefButton> m_xRefBtn3;
+ std::unique_ptr<RefButton> m_xRefBtn4;
+
+ DECL_LINK( ScrollHdl, weld::ScrolledWindow&, void);
+ DECL_LINK( ModifyHdl, ArgInput&, void );
+ DECL_LINK( GetEdFocusHdl, ArgInput&, void );
+ DECL_LINK( GetFxFocusHdl, ArgInput&, void );
+ DECL_LINK( GetFxHdl, ArgInput&, void );
+
+ void ArgumentModified();
+
+ void InitArgInput(sal_uInt16 nPos, weld::Label& rFtArg, weld::Button& rBtnFx,
+ ArgEdit& rEdArg, RefButton& rRefBtn);
+
+ void SetArgumentDesc(const OUString& aText);
+ void SetArgumentText(const OUString& aText);
+
+
+ void SetArgName (sal_uInt16 no,const OUString &aArg);
+ void SetArgNameFont (sal_uInt16 no,const vcl::Font&);
+
+ void UpdateArgDesc( sal_uInt16 nArg );
+ void UpdateArgInput( sal_uInt16 nOffset, sal_uInt16 i );
+
+public:
+ ParaWin(weld::Container* pParent, IControlReferenceHandler* _pDlg);
+ ~ParaWin();
+
+ void SetFunctionDesc(const IFunctionDescription* pFDesc);
+ void SetArgumentOffset(sal_uInt16 nOffset);
+ void SetEditDesc(const OUString& aText);
+ void UpdateParas();
+ void ClearAll();
+
+ sal_uInt16 GetActiveLine() const { return nActiveLine;}
+ void SetActiveLine(sal_uInt16 no);
+ RefEdit* GetActiveEdit();
+ OUString GetActiveArgName() const;
+
+ OUString GetArgument(sal_uInt16 no);
+ void SetArgument(sal_uInt16 no, std::u16string_view aString);
+ void SetArgumentFonts(const vcl::Font& aBoldFont,const vcl::Font& aLightFont);
+
+ void SetEdFocus(); // visible edit lines
+ sal_uInt16 GetSliderPos() const;
+ void SetSliderPos(sal_uInt16 nSliderPos);
+
+ void SetArgModifiedHdl( const Link<ParaWin&,void>& rLink ) { aArgModifiedLink = rLink; }
+ void SetFxHdl( const Link<ParaWin&,void>& rLink ) { aFxLink = rLink; }
+
+ void SliderMoved();
+
+ void Show() { m_xContainer->show(); }
+};
+
+
+} // formula
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/formula/source/ui/dlg/structpg.cxx b/formula/source/ui/dlg/structpg.cxx
new file mode 100644
index 000000000..6cfc34a96
--- /dev/null
+++ b/formula/source/ui/dlg/structpg.cxx
@@ -0,0 +1,154 @@
+/* -*- 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 <vcl/svapp.hxx>
+
+#include "structpg.hxx"
+#include <formula/formula.hxx>
+#include <formula/token.hxx>
+#include <bitmaps.hlst>
+
+namespace formula
+{
+
+void StructPage::SetActiveFlag(bool bFlag)
+{
+ bActiveFlag = bFlag;
+}
+
+StructPage::StructPage(weld::Container* pParent)
+ : m_xBuilder(Application::CreateBuilder(pParent, "formula/ui/structpage.ui"))
+ , m_xContainer(m_xBuilder->weld_container("StructPage"))
+ , m_xTlbStruct(m_xBuilder->weld_tree_view("struct"))
+ , maImgEnd(BMP_STR_END)
+ , maImgError(BMP_STR_ERROR)
+ , pSelectedToken(nullptr)
+ , bActiveFlag(false)
+{
+ m_xTlbStruct->set_size_request(m_xTlbStruct->get_approximate_digit_width() * 20,
+ m_xTlbStruct->get_height_rows(17));
+
+ m_xTlbStruct->connect_changed(LINK( this, StructPage, SelectHdl ) );
+}
+
+StructPage::~StructPage()
+{
+}
+
+void StructPage::ClearStruct()
+{
+ SetActiveFlag(false);
+ m_xTlbStruct->clear();
+}
+
+bool StructPage::InsertEntry(const OUString& rText, const weld::TreeIter* pParent,
+ sal_uInt16 nFlag, int nPos,
+ const FormulaToken* pIFormulaToken,
+ weld::TreeIter& rRet)
+{
+ SetActiveFlag(false);
+
+ OUString sId(weld::toId(pIFormulaToken));
+
+ bool bEntry = false;
+ switch (nFlag)
+ {
+ case STRUCT_FOLDER:
+ m_xTlbStruct->insert(pParent, nPos, &rText, &sId, nullptr, nullptr,
+ false, &rRet);
+ m_xTlbStruct->set_image(rRet, BMP_STR_OPEN);
+ bEntry = true;
+ break;
+ case STRUCT_END:
+ m_xTlbStruct->insert(pParent, nPos, &rText, &sId, nullptr, nullptr,
+ false, &rRet);
+ m_xTlbStruct->set_image(rRet, maImgEnd);
+ bEntry = true;
+ break;
+ case STRUCT_ERROR:
+ m_xTlbStruct->insert(pParent, nPos, &rText, &sId, nullptr, nullptr,
+ false, &rRet);
+ m_xTlbStruct->set_image(rRet, maImgError);
+ bEntry = true;
+ break;
+ }
+
+ if (bEntry && pParent)
+ m_xTlbStruct->expand_row(*pParent);
+ return bEntry;
+}
+
+OUString StructPage::GetEntryText(const weld::TreeIter* pEntry) const
+{
+ OUString aString;
+ if (pEntry)
+ aString = m_xTlbStruct->get_text(*pEntry);
+ return aString;
+}
+
+const FormulaToken* StructPage::GetFunctionEntry(const weld::TreeIter* pEntry)
+{
+ if (!pEntry)
+ return nullptr;
+
+ const FormulaToken * pToken = weld::fromId<const FormulaToken*>(m_xTlbStruct->get_id(*pEntry));
+ if (pToken)
+ {
+ if ( !(pToken->IsFunction() || pToken->GetParamCount() > 1 ) )
+ {
+ std::unique_ptr<weld::TreeIter> xParent(m_xTlbStruct->make_iterator(pEntry));
+ if (!m_xTlbStruct->iter_parent(*xParent))
+ return nullptr;
+ return GetFunctionEntry(xParent.get());
+ }
+ else
+ {
+ return pToken;
+ }
+ }
+ return nullptr;
+}
+
+IMPL_LINK(StructPage, SelectHdl, weld::TreeView&, rTlb, void)
+{
+ if (!GetActiveFlag())
+ return;
+
+ if (&rTlb == m_xTlbStruct.get())
+ {
+ std::unique_ptr<weld::TreeIter> xCurEntry(m_xTlbStruct->make_iterator());
+ if (m_xTlbStruct->get_cursor(xCurEntry.get()))
+ {
+ pSelectedToken = weld::fromId<const FormulaToken*>(m_xTlbStruct->get_id(*xCurEntry));
+ if (pSelectedToken)
+ {
+ if ( !(pSelectedToken->IsFunction() || pSelectedToken->GetParamCount() > 1) )
+ {
+ pSelectedToken = GetFunctionEntry(xCurEntry.get());
+ }
+ }
+ }
+ }
+
+ aSelLink.Call(*this);
+}
+
+} // formula
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/formula/source/ui/dlg/structpg.hxx b/formula/source/ui/dlg/structpg.hxx
new file mode 100644
index 000000000..116403189
--- /dev/null
+++ b/formula/source/ui/dlg/structpg.hxx
@@ -0,0 +1,74 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+
+namespace formula
+{
+
+class FormulaToken;
+
+
+class StructPage final
+{
+private:
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Container> m_xContainer;
+ std::unique_ptr<weld::TreeView> m_xTlbStruct;
+
+ Link<StructPage&,void> aSelLink;
+
+ OUString maImgEnd;
+ OUString maImgError;
+
+ const FormulaToken* pSelectedToken;
+ bool bActiveFlag;
+
+ DECL_LINK(SelectHdl, weld::TreeView&, void);
+
+ const FormulaToken* GetFunctionEntry(const weld::TreeIter* pEntry);
+
+ void SetActiveFlag(bool bFlag);
+ bool GetActiveFlag() const { return bActiveFlag;}
+
+public:
+
+ explicit StructPage(weld::Container* pParent);
+ ~StructPage();
+
+ void ClearStruct();
+ bool InsertEntry(const OUString& rText, const weld::TreeIter* pParent,
+ sal_uInt16 nFlag, int nPos,
+ const FormulaToken* pIFormulaToken,
+ weld::TreeIter& rRet);
+
+ OUString GetEntryText(const weld::TreeIter* pEntry) const;
+
+ void SetSelectionHdl( const Link<StructPage&,void>& rLink ) { aSelLink = rLink; }
+
+ weld::TreeView& GetTlbStruct() const { return *m_xTlbStruct; }
+
+ bool IsVisible() const { return m_xContainer->get_visible(); }
+};
+
+} // formula
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */