diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /formula/source/ui | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'formula/source/ui')
-rw-r--r-- | formula/source/ui/dlg/ControlHelper.hxx | 106 | ||||
-rw-r--r-- | formula/source/ui/dlg/FormulaHelper.cxx | 417 | ||||
-rw-r--r-- | formula/source/ui/dlg/formula.cxx | 1960 | ||||
-rw-r--r-- | formula/source/ui/dlg/funcpage.cxx | 257 | ||||
-rw-r--r-- | formula/source/ui/dlg/funcpage.hxx | 87 | ||||
-rw-r--r-- | formula/source/ui/dlg/funcutl.cxx | 486 | ||||
-rw-r--r-- | formula/source/ui/dlg/parawin.cxx | 600 | ||||
-rw-r--r-- | formula/source/ui/dlg/parawin.hxx | 145 | ||||
-rw-r--r-- | formula/source/ui/dlg/structpg.cxx | 154 | ||||
-rw-r--r-- | formula/source/ui/dlg/structpg.hxx | 74 |
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: */ |