Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/formula/source/ui/dlg/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 62 kB image not shown  

Quelle  formula.cxx   Sprache: C

 
/* -*- 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 <comphelper/diagnose_ex.hxx>

#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 <bitmaps.hlst>
#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&&nbsp;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( FavToggleHdl, 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::optional<FormulaTokenArrayPlainIterator>         m_oTokenArrayIterator;
    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;

    OUString                m_aEditHelpId;

    OUString                 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::Button> m_xBtnFavorites;

    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(u"tabcontrol"_ustr))
    , m_xParaWinBox(rBuilder.weld_container(u"BOX"_ustr))
    , m_xFtHeadLine(rBuilder.weld_label(u"headline"_ustr))
    , m_xFtFuncName(rBuilder.weld_label(u"funcname"_ustr))
    , m_xFtFuncDesc(rBuilder.weld_label(u"funcdesc"_ustr))
    , m_xBtnFavorites(rBuilder.weld_button(u"favorites"_ustr))
    , m_xFtEditName(rBuilder.weld_label(u"editname"_ustr))
    , m_xFtResult(rBuilder.weld_label(u"label2"_ustr))
    , m_xWndResult(rBuilder.weld_entry(u"result"_ustr))
    , m_xFtFormula(rBuilder.weld_label(u"formula"_ustr))
    , m_xMEdit(rBuilder.weld_text_view(u"ed_formula"_ustr))
    , m_xBtnMatrix(rBuilder.weld_check_button(u"array"_ustr))
    , m_xBtnCancel(rBuilder.weld_button(u"cancel"_ustr))
    , m_xBtnBackward(rBuilder.weld_button(u"back"_ustr))
    , m_xBtnForward(rBuilder.weld_button(u"next"_ustr))
    , m_xBtnEnd(rBuilder.weld_button(u"ok"_ustr))
    , m_xFtFormResult(rBuilder.weld_label(u"label1"_ustr))
    , m_xWndFormResult(rBuilder.weld_entry(u"formula_result"_ustr))
    , m_xEdRef(new RefEdit(rBuilder.weld_entry(u"ED_REF"_ustr)))
    , m_xRefBtn(new RefButton(rBuilder.weld_button(u"RB_REF"_ustr)))
{
    auto nWidth = m_xMEdit->get_approximate_digit_width() * 62;

    //Space for two lines of text
    m_xFtHeadLine->set_label(u"X\nX\n"_ustr);
    auto nHeight = m_xFtHeadLine->get_preferred_size().Height();
    m_xFtHeadLine->set_size_request(nWidth, nHeight);
    m_xFtHeadLine->set_label(u""_ustr);

    m_xFtFuncName->set_label(u"X\nX\n"_ustr);
    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(u""_ustr);

    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(u"functiontab"_ustr), _pFunctionMgr));
    m_xStructPage.reset(new StructPage(m_xTabCtrl->get_page(u"structtab"_ustr)));
    m_xTabCtrl->set_current_page(u"functiontab"_ustr);

    m_aOldHelp = m_rDialog.get_help_id();                // HelpId from resource always for "Page 1"

    m_xBtnFavorites->connect_clicked(LINK(this, FormulaDlg_Impl, FavToggleHdl));
    m_xBtnFavorites->hide();

    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(u"functiontab"_ustr);
    m_xTabCtrl->remove_page(u"structtab"_ustr);

    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() == "functiontab")
        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 { u"("_ustr, u")"_ustr, u";"_ustr };
    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& rStrResultbool 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_oTokenArrayIterator->First(); pToken; pToken = m_oTokenArrayIterator->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_oTokenArrayIterator->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_oTokenArrayIterator->NextRPN();   /* TODO: what's this to be? ThisRPN()? */
            MakeTree( _pTree, pParent, _pToken, m_oTokenArrayIterator->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_oTokenArrayIterator->PrevRPN(), Count);
        }
    }
    catch (const uno::Exception&)
    {
        DBG_UNHANDLED_EXCEPTION("formula.ui");
    }
}

void FormulaDlg_Impl::fillTree(StructPage* _pTree)
{
    InitFormulaOpCodeMapper();
    FormulaToken* pToken = m_oTokenArrayIterator->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_oTokenArrayIterator.emplace(*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 )
    {
        // tdf#104487 - remember last used function category
        m_xFuncPage->SetCategory(FuncPage::GetRememeberdFunctionCategory());
        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_xBtnFavorites->hide();
            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 OUString 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(u""_ustr);
        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_xBtnFavorites->show();
        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();
        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 );
    }
}

IMPL_LINK_NOARG(FormulaDlg_Impl, FavToggleHdl, weld::Button&, void)
{
    const IFunctionDescription* pDesc = m_xFuncPage->GetFuncDesc();
    if (!pDesc)
        return;

    if (m_xFuncPage->IsFavourite(m_xFuncPage->GetFuncIndex()))
    {
        m_pHelper->insertOrEraseFavouritesListEntry(pDesc, false);
        m_xBtnFavorites->set_from_icon_name(BMP_STAR_EMPTY);
    }
    else
    {
        m_pHelper->insertOrEraseFavouritesListEntry(pDesc, true);
        m_xBtnFavorites->set_from_icon_name(BMP_STAR_FULL);
    }
    m_xFuncPage->UpdateFavouritesList();
    if (m_xFuncPage->GetCategory() == FAVOURITES_CATEGORY)
        m_xFuncPage->UpdateFunctionList(u""_ustr);
}

//                          Functions for 1. Page

// Handler for Listboxes

IMPL_LINK_NOARG( FormulaDlg_Impl, DblClkHdl, FuncPage&, void)
{
    //  ex-UpdateLRUList
    const IFunctionDescription* pDesc = m_xFuncPage->GetFuncDesc();
    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(u"functiontab"_ustr);

    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(u""_ustr);
        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(u"functiontab"_ustr);
    else
        m_xTabCtrl->set_current_page(u"structtab"_ustr);
    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(u"structtab"_ustr);
    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)
{
    const IFunctionDescription* pDesc = m_xFuncPage->GetFuncDesc();
    const sal_uInt16 nFIndex = m_xFuncPage->GetFuncIndex();

    m_xBtnFavorites->set_sensitive(true);
    if (pDesc)
    {
        if (pDesc != m_pFuncDesc)
            m_xBtnForward->set_sensitive(true); //new

        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() );

        if (m_xFuncPage->IsFavourite(nFIndex))
            m_xBtnFavorites->set_from_icon_name(BMP_STAR_FULL);
        else
            m_xBtnFavorites->set_from_icon_name(BMP_STAR_EMPTY);
    }
    else
    {
        m_xFtHeadLine->set_label( OUString() );
        m_xFtFuncName->set_label( OUString() );
        m_xFtFuncDesc->set_label( OUString() );
    }

    m_xBtnFavorites->set_visible(m_xFtHeadLine->is_visible()
                                 && m_xFtHeadLine->get_label() != u""_ustr);
    m_xBtnFavorites->set_sensitive(nFIndex != 0);
    m_xBtnFavorites->set_tooltip_text(nFIndex == 0 ? ForResId(FAV_DISABLED)
                                                   : ForResId(FAV_ENABLED));
}

void FormulaDlg_Impl::UpdateParaWin( const Selection& _rSelection, const OUString&&nbsp;_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.Normalize();
        aStrEd = pEd->GetText();
        m_xEdRef->SetRefString(aStrEd);
        m_xEdRef->SetSelection( _rSelection );
    }
    else
    {
        _rSelection = m_xEdRef->GetSelection();
        _rSelection.Normalize();
        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, u"formula/ui/formuladialog.ui"_ustr, u"FormulaDialog"_ustr)
    , 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, u"formula/ui/formuladialog.ui"_ustr, u"FormulaDialog"_ustr)
    , 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: */

Messung V0.5
C=93 H=93 G=92

¤ Dauer der Verarbeitung: 0.25 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.