1959 lines
61 KiB
C++
1959 lines
61 KiB
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 <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::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::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_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_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& 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_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_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_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 );
|
|
}
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
if ( (m_xFuncPage->GetFunctionEntryCount() > 0)
|
|
&& (m_xFuncPage->GetFunction() != -1) )
|
|
{
|
|
const IFunctionDescription* pDesc = m_xFuncPage->GetFuncDesc();
|
|
|
|
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.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: */
|