/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include "funcpage.hxx" #include #include #include #include #include #include #include #include "structpg.hxx" #include "parawin.hxx" #include #include #include #include #include #include #include #include #include #include // For tab page #define TOKEN_OPEN 0 #define TOKEN_CLOSE 1 #define TOKEN_SEP 2 namespace formula { using namespace ::com::sun::star; class FormulaDlg_Impl { public: ::std::pair 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, 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::Button&, 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 m_pTokenArray; ::std::unique_ptr m_pTokenArrayIterator; mutable uno::Sequence< sheet::FormulaOpCodeMapEntry > m_aSpecialOpCodes; mutable uno::Sequence< sheet::FormulaToken > m_aSeparatorsOpCodes; mutable uno::Sequence< sheet::FormulaOpCodeMapEntry > m_aFunctionOpCodes; mutable const sheet::FormulaOpCodeMapEntry* m_pFunctionOpCodesEnd; ::std::map m_aTokenMap; IFormulaEditorHelper* m_pHelper; weld::Dialog& m_rDialog; OUString m_aOldFormula; bool m_bStructUpdate; bool m_bUserMatrixFlag; const OUString m_aTitle1; const OUString m_aTitle2; FormulaHelper m_aFormulaHelper; OString m_aEditHelpId; OString m_aOldHelp; bool m_bMakingTree; // in method of constructing tree bool m_bEditFlag; const IFunctionDescription* m_pFuncDesc; sal_Int32 m_nArgs; ::std::vector< OUString > m_aArguments; Selection m_aFuncSel; sal_Int32 m_nFuncExpStart; ///< current formula position for treeview results int m_nSelectionStart; int m_nSelectionEnd; RefEdit* m_pTheRefEdit; RefButton* m_pTheRefButton; std::unique_ptr m_xTabCtrl; std::unique_ptr m_xParaWinBox; std::unique_ptr m_xParaWin; std::unique_ptr m_xFtHeadLine; std::unique_ptr m_xFtFuncName; std::unique_ptr m_xFtFuncDesc; std::unique_ptr m_xFtEditName; std::unique_ptr m_xFtResult; std::unique_ptr m_xWndResult; std::unique_ptr m_xFtFormula; std::unique_ptr m_xMEdit; std::unique_ptr m_xBtnMatrix; std::unique_ptr m_xBtnCancel; std::unique_ptr m_xBtnBackward; std::unique_ptr m_xBtnForward; std::unique_ptr m_xBtnEnd; std::unique_ptr m_xFtFormResult; std::unique_ptr m_xWndFormResult; std::unique_ptr m_xEdRef; std::unique_ptr m_xRefBtn; std::unique_ptr m_xFuncPage; std::unique_ptr 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("tabs")) , m_xParaWinBox(rBuilder.weld_container("BOX")) , m_xFtHeadLine(rBuilder.weld_label("headline")) , m_xFtFuncName(rBuilder.weld_label("funcname")) , m_xFtFuncDesc(rBuilder.weld_label("funcdesc")) , m_xFtEditName(rBuilder.weld_label("editname")) , m_xFtResult(rBuilder.weld_label("label2")) , m_xWndResult(rBuilder.weld_entry("result")) , m_xFtFormula(rBuilder.weld_label("formula")) , m_xMEdit(rBuilder.weld_text_view("ed_formula")) , m_xBtnMatrix(rBuilder.weld_check_button("array")) , m_xBtnCancel(rBuilder.weld_button("cancel")) , m_xBtnBackward(rBuilder.weld_button("back")) , m_xBtnForward(rBuilder.weld_button("next")) , m_xBtnEnd(rBuilder.weld_button("ok")) , m_xFtFormResult(rBuilder.weld_label("label1")) , m_xWndFormResult(rBuilder.weld_entry("formula_result")) , m_xEdRef(new RefEdit(rBuilder.weld_entry("ED_REF"))) , m_xRefBtn(new RefButton(rBuilder.weld_button("RB_REF"))) { auto nWidth = m_xMEdit->get_approximate_digit_width() * 62; //Space for two lines of text m_xFtHeadLine->set_label("X\nX\n"); auto nHeight = m_xFtHeadLine->get_preferred_size().Height(); m_xFtHeadLine->set_size_request(nWidth, nHeight); m_xFtHeadLine->set_label(""); m_xFtFuncName->set_label("X\nX\n"); nHeight = m_xFtFuncName->get_preferred_size().Height(); m_xFtFuncName->set_size_request(nWidth, nHeight); m_xFtFuncDesc->set_size_request(nWidth, nHeight); m_xFtFuncName->set_label(""); m_xMEdit->set_size_request(nWidth, m_xMEdit->get_height_rows(5)); m_xEdRef->SetReferences(_pDlg, m_xFtEditName.get()); m_xRefBtn->SetReferences(_pDlg, m_xEdRef.get()); m_xParaWin.reset(new ParaWin(m_xParaWinBox.get(), _pDlg)); m_xParaWin->Show(); m_xParaWinBox->hide(); m_xFtEditName->hide(); m_xEdRef->GetWidget()->hide(); m_xRefBtn->GetWidget()->hide(); m_xMEdit->set_accessible_name(m_xFtFormula->get_label()); m_aEditHelpId = m_xMEdit->get_help_id(); m_bEditFlag =false; m_bStructUpdate =true; m_xParaWin->SetArgModifiedHdl( LINK( this, FormulaDlg_Impl, ModifyHdl ) ); m_xParaWin->SetFxHdl( LINK( this, FormulaDlg_Impl, FxHdl ) ); m_xFuncPage.reset(new FuncPage(m_xTabCtrl->get_page("function"), _pFunctionMgr)); m_xStructPage.reset(new StructPage(m_xTabCtrl->get_page("struct"))); m_xTabCtrl->set_current_page("function"); m_aOldHelp = m_rDialog.get_help_id(); // HelpId from resource always for "Page 1" m_xFtResult->set_visible( _bSupportResult ); m_xWndResult->set_visible( _bSupportResult ); m_xFtFormResult->set_visible( _bSupportFunctionResult ); m_xWndFormResult->set_visible( _bSupportFunctionResult ); if ( _bSupportMatrix ) m_xBtnMatrix->connect_clicked( LINK( this, FormulaDlg_Impl, MatrixHdl ) ); else m_xBtnMatrix->hide(); m_xBtnCancel->connect_clicked( LINK( this, FormulaDlg_Impl, BtnHdl ) ); m_xBtnEnd->connect_clicked( LINK( this, FormulaDlg_Impl, BtnHdl ) ); m_xBtnForward->connect_clicked( LINK( this, FormulaDlg_Impl, BtnHdl ) ); m_xBtnBackward->connect_clicked( LINK( this, FormulaDlg_Impl, BtnHdl ) ); m_xFuncPage->SetDoubleClickHdl( LINK( this, FormulaDlg_Impl, DblClkHdl ) ); m_xFuncPage->SetSelectHdl( LINK( this, FormulaDlg_Impl, FuncSelHdl) ); m_xStructPage->SetSelectionHdl( LINK( this, FormulaDlg_Impl, StructSelHdl ) ); m_xMEdit->connect_changed( LINK( this, FormulaDlg_Impl, FormulaHdl ) ); m_xMEdit->connect_cursor_position( LINK( this, FormulaDlg_Impl, FormulaCursorHdl ) ); vcl::Font aFntLight = m_xFtFormula->get_font(); vcl::Font aFntBold = aFntLight; aFntBold.SetWeight( WEIGHT_BOLD ); m_xParaWin->SetArgumentFonts( aFntBold, aFntLight); } FormulaDlg_Impl::~FormulaDlg_Impl() { m_xTabCtrl->remove_page("function"); m_xTabCtrl->remove_page("struct"); DeleteArgs(); } void FormulaDlg_Impl::StoreFormEditData(FormEditData* pData) { if (pData) // it won't be destroyed via Close { int nStartPos, nEndPos; m_xMEdit->get_selection_bounds(nStartPos, nEndPos); if (nStartPos > nEndPos) std::swap(nStartPos, nEndPos); pData->SetFStart(nStartPos); pData->SetSelection(Selection(nStartPos, nEndPos)); if (m_xTabCtrl->get_current_page_ident() == "function") pData->SetMode( FormulaDlgMode::Formula ); else pData->SetMode( FormulaDlgMode::Edit ); pData->SetUndoStr(m_xMEdit->get_text()); pData->SetMatrixFlag(m_xBtnMatrix->get_active()); } } void FormulaDlg_Impl::InitFormulaOpCodeMapper() { if ( m_xOpCodeMapper.is() ) return; m_xOpCodeMapper = m_pHelper->getFormulaOpCodeMapper(); m_aFunctionOpCodes = m_xOpCodeMapper->getAvailableMappings( sheet::FormulaLanguage::ODFF, sheet::FormulaMapGroup::FUNCTIONS); m_pFunctionOpCodesEnd = m_aFunctionOpCodes.getConstArray() + m_aFunctionOpCodes.getLength(); uno::Sequence< OUString > aArgs(3); aArgs[TOKEN_OPEN] = "("; aArgs[TOKEN_CLOSE] = ")"; aArgs[TOKEN_SEP] = ";"; 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; while ( pIter != pEnd ) { const sal_Int32 eOp = pIter->OpCode; uno::Sequence aArgs(1); aArgs[0] = *pIter; const OUString aString = xParser->printFormula( aArgs, aRefPos); const sheet::FormulaToken* pNextToken = pIter + 1; if ( !m_bUserMatrixFlag && FormulaCompiler::IsMatrixFunction(static_cast(eOp)) ) { m_xBtnMatrix->set_active(true); } if (eOp == m_aSpecialOpCodes[sheet::FormulaMapGroupSpecialOffset::PUSH].Token.OpCode || eOp == m_aSpecialOpCodes[sheet::FormulaMapGroupSpecialOffset::SPACES].Token.OpCode) { 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[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 && m_aSpecialOpCodes[sheet::FormulaMapGroupSpecialOffset::SPACES].Token.OpCode != 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& ) { css::uno::Any ex( cppu::getCaughtException() ); SAL_WARN("formula.ui", "FormulaDlg_Impl::GetFunctionPos exception! " << exceptionToString(ex)); } 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 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().get()) { const sal_Int32 nPos = m_aFuncSel.Min(); assert( 0 <= nPos && nPos < m_pHelper->getCurrentFormula().getLength()); OUStringBuffer aBuf; const FormulaToken* pToken = nullptr; for (pToken = m_pTokenArrayIterator->First(); pToken; pToken = m_pTokenArrayIterator->Next()) { pCompiler->CreateStringFromToken( aBuf, pToken); if (nPos < aBuf.getLength()) break; } if (pToken && nPos < aBuf.getLength()) bForceArray = pToken->IsInForceArray(); } } OUString aStrResult; if (m_pFuncDesc && CalcValue( m_pFuncDesc->getFormula( m_aArguments), aStrResult, bForceArray)) m_xWndResult->set_text( aStrResult ); if (m_bMakingTree) return; aStrResult.clear(); if ( CalcValue( m_pHelper->getCurrentFormula(), aStrResult ) ) m_xWndFormResult->set_text( aStrResult ); else { aStrResult.clear(); m_xWndFormResult->set_text( aStrResult ); } CalcStruct( m_xMEdit->get_text(), bForceRecalcStruct); } void FormulaDlg_Impl::CalcStruct( const OUString& rStrExp, bool bForceRecalcStruct ) { sal_Int32 nLength = rStrExp.getLength(); if ( !rStrExp.isEmpty() && (bForceRecalcStruct || m_aOldFormula != rStrExp) && m_bStructUpdate) { 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, long Count) { if ( _pToken != nullptr && Count > 0 ) { 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; uno::Sequence aArgs(1); ::std::map::const_iterator itr = m_aTokenMap.find(pOrigToken); if (itr == m_aTokenMap.end()) return; aArgs[0] = 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 xEntry; weld::TreeIter* pEntry; bool bCalcSubformula = false; OUString aTest = _pTree->GetEntryText(pParent); if (aTest == aResult && (eOp == ocAdd || eOp == ocMul || eOp == ocAmpersand)) { pEntry = pParent; } else { xEntry = m_xStructPage->GetTlbStruct().make_iterator(); if (eOp == ocBad) { _pTree->InsertEntry(aResult, pParent, STRUCT_ERROR, 0, _pToken, *xEntry); } else if (!((SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP) || (SC_OPCODE_START_UN_OP <= eOp && eOp < SC_OPCODE_STOP_UN_OP))) { // Not a binary or unary operator. bCalcSubformula = true; _pTree->InsertEntry(aResult, pParent, STRUCT_FOLDER, 0, _pToken, *xEntry); } else { /* TODO: question remains, why not sub calculate operators? */ _pTree->InsertEntry(aResult, pParent, STRUCT_FOLDER, 0, _pToken, *xEntry); } pEntry = xEntry.get(); } MakeTree(_pTree, pEntry, _pToken, m_pTokenArrayIterator->PrevRPN(), nParas); if (bCalcSubformula) { OUString aFormula; if (!m_bMakingTree) { // gets the last subformula result m_bMakingTree = true; aFormula = GetPrevFuncExpression( true); } else { // gets subsequent subformula results (from the back) aFormula = GetPrevFuncExpression( false); } OUString aStr; if (CalcValue( aFormula, aStr, _pToken->IsInForceArray())) m_xWndResult->set_text( aStr ); aStr = m_xWndResult->get_text(); m_xStructPage->GetTlbStruct().set_text(*pEntry, aResult + " = " + aStr); } --Count; m_pTokenArrayIterator->NextRPN(); /* TODO: what's this to be? ThisRPN()? */ MakeTree( _pTree, pParent, _pToken, m_pTokenArrayIterator->PrevRPN(), Count); } else { std::unique_ptr 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 pCompiler = m_pHelper->getCompiler(); if (pCompiler) eParamClass = pCompiler->GetForceArrayParameter( pFuncToken, Count - 1); } switch (eParamClass) { case ParamClass::Unknown: case ParamClass::Bounds: case ParamClass::Value: if (CalcValue( "=" + aResult, aUnforcedResult, false) && aUnforcedResult != aResult) aUnforcedResult += " "; else aUnforcedResult.clear(); break; case ParamClass::Reference: case ParamClass::ReferenceOrRefArray: case ParamClass::Array: case ParamClass::ForceArray: case ParamClass::ReferenceOrForceArray: case ParamClass::SuppressedReferenceOrForceArray: case ParamClass::ForceArrayReturn: ; // nothing, only as array/matrix // no default to get compiler warning } } OUString aCellResult; if (CalcValue( "=" + aResult, aCellResult, bForceMatrix) && aCellResult != aResult) { // Cell is a formula, print subformula. // With scalar values prints "A1:A3 = 2 {1;2;3}" _pTree->InsertEntry( aResult + " = " + aUnforcedResult + aCellResult, pParent, STRUCT_END, 0, _pToken, *xEntry); } else _pTree->InsertEntry(aResult, pParent, STRUCT_END, 0, _pToken, *xEntry); } else { _pTree->InsertEntry(aResult, pParent, STRUCT_END, 0, _pToken, *xEntry); } --Count; MakeTree( _pTree, pParent, _pToken, m_pTokenArrayIterator->PrevRPN(), Count); } } catch (const uno::Exception&) { DBG_UNHANDLED_EXCEPTION("formula.ui"); } } } void FormulaDlg_Impl::fillTree(StructPage* _pTree) { InitFormulaOpCodeMapper(); FormulaToken* pToken = m_pTokenArrayIterator->LastRPN(); if ( pToken != nullptr) { MakeTree( _pTree, nullptr, nullptr, pToken, 1); m_bMakingTree = false; } } void FormulaDlg_Impl::UpdateTokenArray( const OUString& rStrExp) { m_aTokenMap.clear(); m_aTokenList.realloc(0); try { const table::CellAddress aRefPos(m_pHelper->getReferencePosition()); m_aTokenList = m_pHelper->getFormulaParser()->parseFormula( rStrExp, aRefPos); } catch (const uno::Exception&) { DBG_UNHANDLED_EXCEPTION("formula.ui"); } InitFormulaOpCodeMapper(); m_pTokenArray = m_pHelper->convertToTokenArray(m_aTokenList); m_pTokenArrayIterator.reset(new FormulaTokenArrayPlainIterator(*m_pTokenArray)); const sal_Int32 nLen = static_cast(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 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 ... if ( m_xFuncPage->GetCategory() != static_cast(m_pFuncDesc->getCategory()->getNumber() + 1) ) m_xFuncPage->SetCategory(m_pFuncDesc->getCategory()->getNumber() + 1); sal_Int32 nPos = m_xFuncPage->GetFuncPos(m_pFuncDesc); m_xFuncPage->SetFunction(nPos); } else if ( pData ) { m_xFuncPage->SetCategory( 1 ); m_xFuncPage->SetFunction( -1 ); } FuncSelHdl(*m_xFuncPage); m_pHelper->setDispatcherLock( true ); // Activate Modal-Mode // HelpId for 1. page is the one from the resource m_rDialog.set_help_id( m_aOldHelp ); } void FormulaDlg_Impl::FillControls( bool &rbNext, bool &rbPrev) { // Switch between the "Pages" FormEditData* pData = m_pHelper->getFormEditData(); if (!pData ) return; // 2. Page or Edit: show selected function sal_Int32 nFStart = pData->GetFStart(); OUString aFormula = m_pHelper->getCurrentFormula() + " )"; sal_Int32 nNextFStart = nFStart; sal_Int32 nNextFEnd = 0; DeleteArgs(); const IFunctionDescription* pOldFuncDesc = m_pFuncDesc; if ( m_aFormulaHelper.GetNextFunc( aFormula, false, nNextFStart, &nNextFEnd, &m_pFuncDesc, &m_aArguments ) ) { const bool bTestFlag = (pOldFuncDesc != m_pFuncDesc); if (bTestFlag) { m_xFtHeadLine->hide(); m_xFtFuncName->hide(); m_xFtFuncDesc->hide(); m_xParaWin->SetFunctionDesc(m_pFuncDesc); m_xFtEditName->set_label( m_pFuncDesc->getFunctionName() ); m_xFtEditName->show(); m_xParaWinBox->show(); const OString aHelpId = m_pFuncDesc->getHelpId(); if ( !aHelpId.isEmpty() ) m_xMEdit->set_help_id(aHelpId); } sal_Int32 nOldStart, nOldEnd; m_pHelper->getSelection( nOldStart, nOldEnd ); if ( nOldStart != nNextFStart || nOldEnd != nNextFEnd ) { m_pHelper->setSelection( nNextFStart, nNextFEnd ); } m_aFuncSel.Min() = nNextFStart; m_aFuncSel.Max() = nNextFEnd; if (!m_bEditFlag) m_xMEdit->set_text(m_pHelper->getCurrentFormula()); sal_Int32 PrivStart, PrivEnd; m_pHelper->getSelection( PrivStart, PrivEnd); if (!m_bEditFlag) m_xMEdit->select_region(PrivStart, PrivEnd); m_nArgs = m_pFuncDesc->getSuppressedArgumentCount(); sal_uInt16 nOffset = pData->GetOffset(); // Concatenate the Edit's for Focus-Control if (bTestFlag) m_xParaWin->SetArgumentOffset(nOffset); sal_uInt16 nActiv = 0; sal_Int32 nArgPos = m_aFormulaHelper.GetArgStart( aFormula, nFStart, 0 ); int nStartPos, nEndPos; m_xMEdit->get_selection_bounds(nStartPos, nEndPos); if (nStartPos > nEndPos) std::swap(nStartPos, nEndPos); sal_Int32 nEditPos = nStartPos; bool bFlag = false; for (sal_Int32 i = 0; i < m_nArgs; i++) { sal_Int32 nLength = m_aArguments[i].getLength()+1; m_xParaWin->SetArgument( i, m_aArguments[i]); if (nArgPos <= nEditPos && nEditPos < nArgPos+nLength) { nActiv = i; bFlag = true; } nArgPos = nArgPos + nLength; } m_xParaWin->UpdateParas(); if (bFlag) { m_xParaWin->SetActiveLine(nActiv); } UpdateValues(); } else { m_xFtEditName->set_label(""); m_xMEdit->set_help_id(m_aEditHelpId); } // test if before/after are anymore functions sal_Int32 nTempStart = m_aFormulaHelper.GetArgStart( aFormula, nFStart, 0 ); rbNext = m_aFormulaHelper.GetNextFunc( aFormula, false, nTempStart ); int nStartPos, nEndPos; m_xMEdit->get_selection_bounds(nStartPos, nEndPos); if (nStartPos > nEndPos) std::swap(nStartPos, nEndPos); nTempStart = nStartPos; pData->SetFStart(nTempStart); rbPrev = m_aFormulaHelper.GetNextFunc( aFormula, true, nTempStart ); } void FormulaDlg_Impl::ClearAllParas() { DeleteArgs(); m_pFuncDesc = nullptr; m_xParaWin->ClearAll(); m_xWndResult->set_text(OUString()); m_xFtFuncName->set_label(OUString()); FuncSelHdl(*m_xFuncPage); if (m_xFuncPage->IsVisible()) { m_xFtEditName->hide(); m_xParaWinBox->hide(); m_xBtnForward->set_sensitive(true); //@new m_xFtHeadLine->show(); m_xFtFuncName->show(); m_xFtFuncDesc->show(); } } OUString FormulaDlg_Impl::RepairFormula(const OUString& aFormula) { OUString aResult('='); try { UpdateTokenArray(aFormula); if ( m_aTokenList.hasElements() ) { const table::CellAddress aRefPos(m_pHelper->getReferencePosition()); const OUString sFormula( m_pHelper->getFormulaParser()->printFormula( m_aTokenList, aRefPos)); if ( sFormula.isEmpty() || sFormula[0] != '=' ) aResult += sFormula; else aResult = sFormula; } } catch ( const uno::Exception& ) { css::uno::Any ex( cppu::getCaughtException() ); SAL_WARN("formula.ui", "FormulaDlg_Impl::RepairFormula exception! " << exceptionToString(ex)); } return aResult; } void FormulaDlg_Impl::DoEnter(bool bOk) { // Accept input to the document or cancel if ( bOk) { // remove dummy arguments OUString aInputFormula = m_pHelper->getCurrentFormula(); OUString aString = RepairFormula(m_xMEdit->get_text()); m_pHelper->setSelection( 0, aInputFormula.getLength()); m_pHelper->setCurrentFormula(aString); } m_pHelper->switchBack(); m_pHelper->dispatch( bOk, m_xBtnMatrix->get_active()); // Clear data m_pHelper->deleteFormData(); // Close dialog m_pHelper->doClose(bOk); } IMPL_LINK(FormulaDlg_Impl, BtnHdl, weld::Button&, rBtn, void) { if (&rBtn == m_xBtnCancel.get()) { DoEnter(false); // closes the Dialog } else if (&rBtn == m_xBtnEnd.get()) { DoEnter(true); // closes the Dialog } else if (&rBtn == m_xBtnForward.get()) { const IFunctionDescription* pDesc; sal_Int32 nSelFunc = m_xFuncPage->GetFunction(); if (nSelFunc != -1) pDesc = m_xFuncPage->GetFuncDesc( nSelFunc ); else { // Do not overwrite the selected formula expression, just edit the // unlisted function. m_pFuncDesc = pDesc = nullptr; } if (pDesc == m_pFuncDesc || !m_xFuncPage->IsVisible()) EditNextFunc( true ); else { DblClkHdl(*m_xFuncPage); //new m_xBtnForward->set_sensitive(false); //new } } else if (&rBtn == m_xBtnBackward.get()) { m_bEditFlag = false; m_xBtnForward->set_sensitive(true); EditNextFunc( false ); } } // Functions for 1. Page // Handler for Listboxes IMPL_LINK_NOARG( FormulaDlg_Impl, DblClkHdl, FuncPage&, void) { sal_Int32 nFunc = m_xFuncPage->GetFunction(); // ex-UpdateLRUList const IFunctionDescription* pDesc = m_xFuncPage->GetFuncDesc(nFunc); m_pHelper->insertEntryToLRUList(pDesc); OUString aFuncName = m_xFuncPage->GetSelFunctionName() + "()"; m_pHelper->setCurrentFormula(aFuncName); m_xMEdit->replace_selection(aFuncName); int nStartPos, nEndPos; m_xMEdit->get_selection_bounds(nStartPos, nEndPos); if (nStartPos > nEndPos) std::swap(nStartPos, nEndPos); nEndPos = nEndPos - 1; m_xMEdit->select_region(nStartPos, nEndPos); FormulaHdl(*m_xMEdit); nStartPos = nEndPos; m_xMEdit->select_region(nStartPos, nEndPos); if (m_nArgs == 0) { BtnHdl(*m_xBtnBackward); } m_xParaWin->SetEdFocus(); m_xBtnForward->set_sensitive(false); //@New } // Functions for right Page void FormulaDlg_Impl::SetData( sal_Int32 nFStart, sal_Int32 nNextFStart, sal_Int32 nNextFEnd, sal_Int32& PrivStart, sal_Int32& PrivEnd) { sal_Int32 nFEnd; // Notice and set new selection m_pHelper->getSelection( nFStart, nFEnd ); m_pHelper->setSelection( nNextFStart, nNextFEnd ); if (!m_bEditFlag) m_xMEdit->set_text(m_pHelper->getCurrentFormula()); m_pHelper->getSelection( PrivStart, PrivEnd); if (!m_bEditFlag) { m_xMEdit->select_region(PrivStart, PrivEnd); UpdateOldSel(); } FormEditData* pData = m_pHelper->getFormEditData(); pData->SetFStart( nNextFStart ); pData->SetOffset( 0 ); FillDialog(); } void FormulaDlg_Impl::EditThisFunc(sal_Int32 nFStart) { FormEditData* pData = m_pHelper->getFormEditData(); if (!pData) return; OUString aFormula = m_pHelper->getCurrentFormula(); if (nFStart == NOT_FOUND) { nFStart = pData->GetFStart(); } else { pData->SetFStart(nFStart); } sal_Int32 nNextFStart = nFStart; sal_Int32 nNextFEnd = 0; bool bFound; bFound = m_aFormulaHelper.GetNextFunc( aFormula, false, nNextFStart, &nNextFEnd); if ( bFound ) { sal_Int32 PrivStart, PrivEnd; SetData( nFStart, nNextFStart, nNextFEnd, PrivStart, PrivEnd); m_pHelper->showReference( aFormula.copy( PrivStart, PrivEnd-PrivStart)); } else { ClearAllParas(); } } bool FormulaDlg_Impl::EditNextFunc( bool bForward, sal_Int32 nFStart ) { FormEditData* pData = m_pHelper->getFormEditData(); if (!pData) return false; OUString aFormula = m_pHelper->getCurrentFormula(); if (nFStart == NOT_FOUND) { nFStart = pData->GetFStart(); } else { pData->SetFStart(nFStart); } sal_Int32 nNextFStart = 0; sal_Int32 nNextFEnd = 0; bool bFound; if ( bForward ) { nNextFStart = m_aFormulaHelper.GetArgStart( aFormula, nFStart, 0 ); bFound = m_aFormulaHelper.GetNextFunc( aFormula, false, nNextFStart, &nNextFEnd); } else { nNextFStart = nFStart; bFound = m_aFormulaHelper.GetNextFunc( aFormula, true, nNextFStart, &nNextFEnd); } if ( bFound ) { sal_Int32 PrivStart, PrivEnd; SetData( nFStart, nNextFStart, nNextFEnd, PrivStart, PrivEnd); } return bFound; } OUString FormulaDlg_Impl::GetPrevFuncExpression( bool bStartFromEnd ) { OUString aExpression; OUString aFormula( m_pHelper->getCurrentFormula()); if (aFormula.isEmpty()) return aExpression; if (bStartFromEnd || m_nFuncExpStart >= aFormula.getLength()) m_nFuncExpStart = aFormula.getLength() - 1; sal_Int32 nFStart = m_nFuncExpStart; sal_Int32 nFEnd = 0; if (m_aFormulaHelper.GetNextFunc( aFormula, true, nFStart, &nFEnd)) { aExpression = aFormula.copy( nFStart, nFEnd - nFStart); // nFEnd is exclusive m_nFuncExpStart = nFStart; } return aExpression; } void FormulaDlg_Impl::SaveArg( sal_uInt16 nEd ) { if (nEd < m_nArgs) { 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()) { m_xBtnForward->set_sensitive(true); //@ In order to be able to input another function. m_xTabCtrl->set_current_page("function"); OUString aUndoStr = m_pHelper->getCurrentFormula(); // it will be added before a ";" FormEditData* pData = m_pHelper->getFormEditData(); if (!pData) return; sal_uInt16 nArgNo = m_xParaWin->GetActiveLine(); sal_uInt16 nEdFocus = nArgNo; SaveArg(nArgNo); UpdateSelection(); sal_Int32 nFormulaStrPos = pData->GetFStart(); OUString aFormula = m_pHelper->getCurrentFormula(); sal_Int32 n1 = m_aFormulaHelper.GetArgStart( aFormula, nFormulaStrPos, nEdFocus + pData->GetOffset() ); pData->SaveValues(); pData->SetMode( FormulaDlgMode::Formula ); pData->SetFStart( n1 ); pData->SetUndoStr( aUndoStr ); ClearAllParas(); FillDialog(false); m_xFuncPage->SetFocus(); //There Parawin is not visible anymore } } IMPL_LINK( FormulaDlg_Impl, ModifyHdl, ParaWin&, rPtr, void ) { if (&rPtr == m_xParaWin.get()) { SaveArg(m_xParaWin->GetActiveLine()); UpdateValues(); UpdateSelection(); CalcStruct(m_xMEdit->get_text()); } } IMPL_LINK_NOARG( FormulaDlg_Impl, FormulaHdl, weld::TextView&, void) { FormEditData* pData = m_pHelper->getFormEditData(); if (!pData) return; m_bEditFlag = true; OUString aInputFormula = m_pHelper->getCurrentFormula(); OUString aString = m_xMEdit->get_text(); int nStartPos, nEndPos; m_xMEdit->get_selection_bounds(nStartPos, nEndPos); if (nStartPos > nEndPos) std::swap(nStartPos, nEndPos); if (aString.isEmpty()) // in case everything was cleared { aString += "="; m_xMEdit->set_text(aString); nStartPos = 1; nEndPos = 1; m_xMEdit->select_region(nStartPos, nEndPos); } else if (aString[0]!='=') // in case it's replaced { aString = "=" + aString; m_xMEdit->set_text(aString); nStartPos += 1; nEndPos += 1; m_xMEdit->select_region(nStartPos, nEndPos); } m_pHelper->setSelection( 0, aInputFormula.getLength()); m_pHelper->setCurrentFormula(aString); m_pHelper->setSelection(nStartPos, nEndPos); sal_Int32 nPos = nStartPos - 1; OUString aStrResult; if ( CalcValue( m_pHelper->getCurrentFormula(), aStrResult ) ) m_xWndFormResult->set_text( aStrResult ); else { aStrResult.clear(); m_xWndFormResult->set_text( aStrResult ); } CalcStruct(aString); nPos = GetFunctionPos(nPos); if (nPos < nStartPos - 1) { sal_Int32 nPos1 = aString.indexOf( '(', nPos); EditNextFunc( false, nPos1); } else { ClearAllParas(); } m_pHelper->setSelection(nStartPos, nEndPos); m_bEditFlag = false; } void FormulaDlg_Impl::FormulaCursor() { FormEditData* pData = m_pHelper->getFormEditData(); if (!pData) return; m_bEditFlag = true; OUString aString = m_xMEdit->get_text(); int nStartPos, nEndPos; m_xMEdit->get_selection_bounds(nStartPos, nEndPos); if (nStartPos > nEndPos) std::swap(nStartPos, nEndPos); m_pHelper->setSelection(nStartPos, nEndPos); if (nStartPos == 0) { nStartPos = 1; m_xMEdit->select_region(nStartPos, nEndPos); } if (nStartPos != aString.getLength()) { sal_Int32 nPos = nStartPos; sal_Int32 nFStart = GetFunctionPos(nPos - 1); if (nFStart < nPos) { sal_Int32 nPos1 = m_aFormulaHelper.GetFunctionEnd( aString, nFStart); if (nPos1 > nPos) { EditThisFunc(nFStart); } else { sal_Int32 n = nPos; short nCount = 1; while(n > 0) { if (aString[n]==')') nCount++; else if (aString[n]=='(') nCount--; if (nCount == 0) break; n--; } if (nCount == 0) { nFStart = m_aFormulaHelper.GetFunctionStart( aString, n, true); EditThisFunc(nFStart); } else { ClearAllParas(); } } } else { ClearAllParas(); } } m_pHelper->setSelection(nStartPos, nEndPos); m_bEditFlag = false; } void FormulaDlg_Impl::UpdateOldSel() { m_xMEdit->get_selection_bounds(m_nSelectionStart, m_nSelectionEnd); if (m_nSelectionStart > m_nSelectionEnd) std::swap(m_nSelectionStart, m_nSelectionEnd); } IMPL_LINK_NOARG( FormulaDlg_Impl, FormulaCursorHdl, weld::TextView&, void) { int nStartPos, nEndPos; m_xMEdit->get_selection_bounds(nStartPos, nEndPos); if (nStartPos > nEndPos) std::swap(nStartPos, nEndPos); if (nStartPos != m_nSelectionStart || nEndPos != m_nSelectionEnd) { m_nSelectionStart = nStartPos; m_nSelectionEnd = nEndPos; FormulaCursor(); } } void FormulaDlg_Impl::UpdateSelection() { m_pHelper->setSelection( m_aFuncSel.Min(), m_aFuncSel.Max()); m_pHelper->setCurrentFormula( m_pFuncDesc->getFormula( m_aArguments ) ); m_xMEdit->set_text(m_pHelper->getCurrentFormula()); sal_Int32 PrivStart, PrivEnd; m_pHelper->getSelection( PrivStart, PrivEnd); m_aFuncSel.Min() = PrivStart; m_aFuncSel.Max() = PrivEnd; m_nArgs = m_pFuncDesc->getSuppressedArgumentCount(); 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 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 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) { 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()) { m_xEdRef->GetWidget()->hide(); m_xRefBtn->GetWidget()->hide(); if ( m_pTheRefEdit ) { m_pTheRefEdit->SetRefString( m_xEdRef->GetText() ); m_pTheRefEdit->GrabFocus(); if ( m_pTheRefButton ) m_pTheRefButton->SetStartImage(); sal_uInt16 nPrivActiv = m_xParaWin->GetActiveLine(); m_xParaWin->SetArgument( nPrivActiv, m_xEdRef->GetText() ); ModifyHdl( *m_xParaWin ); m_pTheRefEdit = nullptr; } m_rDialog.set_title(m_aTitle1); } } RefEdit* FormulaDlg_Impl::GetCurrRefEdit() { return m_xEdRef->GetWidget()->get_visible() ? m_xEdRef.get() : m_xParaWin->GetActiveEdit(); } void FormulaDlg_Impl::Update() { FormEditData* pData = m_pHelper->getFormEditData(); const OUString sExpression = m_xMEdit->get_text(); m_aOldFormula.clear(); UpdateTokenArray(sExpression); FormulaCursor(); CalcStruct(sExpression); if (pData->GetMode() == FormulaDlgMode::Formula) m_xTabCtrl->set_current_page("function"); else m_xTabCtrl->set_current_page("struct"); m_xBtnMatrix->set_active(pData->GetMatrixFlag()); } void FormulaDlg_Impl::Update(const OUString& _sExp) { CalcStruct(_sExp); FillDialog(); FuncSelHdl(*m_xFuncPage); } void FormulaDlg_Impl::SetMeText(const OUString& _sText) { FormEditData* pData = m_pHelper->getFormEditData(); m_xMEdit->set_text(_sText); auto aSelection = pData->GetSelection(); m_xMEdit->select_region(aSelection.Min(), aSelection.Max()); UpdateOldSel(); } FormulaDlgMode FormulaDlg_Impl::SetMeText( const OUString& _sText, sal_Int32 PrivStart, sal_Int32 PrivEnd, bool bMatrix, bool _bSelect, bool _bUpdate) { FormulaDlgMode eMode = FormulaDlgMode::Formula; if (!m_bEditFlag) m_xMEdit->set_text(_sText); if ( _bSelect || !m_bEditFlag ) m_xMEdit->select_region(PrivStart, PrivEnd); if ( _bUpdate ) { UpdateOldSel(); int nStartPos, nEndPos; m_xMEdit->get_selection_bounds(nStartPos, nEndPos); if (nStartPos > nEndPos) std::swap(nStartPos, nEndPos); m_pHelper->showReference(m_xMEdit->get_text().copy(nStartPos, nEndPos - nStartPos)); eMode = FormulaDlgMode::Edit; m_xBtnMatrix->set_active( bMatrix ); } // if ( _bUpdate ) return eMode; } bool FormulaDlg_Impl::CheckMatrix(OUString& aFormula) { m_xMEdit->grab_focus(); sal_Int32 nLen = aFormula.getLength(); bool bMatrix = nLen > 3 // Matrix-Formula && aFormula[0] == '{' && aFormula[1] == '=' && aFormula[nLen-1] == '}'; if ( bMatrix ) { aFormula = aFormula.copy( 1, aFormula.getLength()-2 ); m_xBtnMatrix->set_active( bMatrix ); m_xBtnMatrix->set_sensitive(false); } // if ( bMatrix ) m_xTabCtrl->set_current_page("struct"); return bMatrix; } IMPL_LINK_NOARG( FormulaDlg_Impl, StructSelHdl, StructPage&, void) { m_bStructUpdate = false; if (m_xStructPage->IsVisible()) m_xBtnForward->set_sensitive(false); //@New m_bStructUpdate = true; } IMPL_LINK_NOARG( FormulaDlg_Impl, MatrixHdl, weld::Button&, void) { m_bUserMatrixFlag = true; UpdateValues(true); } IMPL_LINK_NOARG( FormulaDlg_Impl, FuncSelHdl, FuncPage&, void) { if ( (m_xFuncPage->GetFunctionEntryCount() > 0) && (m_xFuncPage->GetFunction() != -1) ) { const IFunctionDescription* pDesc = m_xFuncPage->GetFuncDesc( m_xFuncPage->GetFunction() ); if (pDesc != m_pFuncDesc) m_xBtnForward->set_sensitive(true); //new if (pDesc) { pDesc->initArgumentInfo(); // full argument info is needed OUString aSig = pDesc->getSignature(); m_xFtHeadLine->set_label( pDesc->getFunctionName() ); m_xFtFuncName->set_label( aSig ); m_xFtFuncDesc->set_label( pDesc->getDescription() ); } } else { m_xFtHeadLine->set_label( OUString() ); m_xFtFuncName->set_label( OUString() ); m_xFtFuncDesc->set_label( OUString() ); } } void FormulaDlg_Impl::UpdateParaWin( const Selection& _rSelection, const OUString& _sRefStr) { Selection theSel = _rSelection; m_xEdRef->GetWidget()->replace_selection(_sRefStr); theSel.Max() = theSel.Min() + _sRefStr.getLength(); m_xEdRef->SetSelection( theSel ); // Manual Update of the results' fields: sal_uInt16 nPrivActiv = m_xParaWin->GetActiveLine(); m_xParaWin->SetArgument( nPrivActiv, m_xEdRef->GetText()); m_xParaWin->UpdateParas(); RefEdit* pEd = GetCurrRefEdit(); if (pEd) pEd->SetSelection( theSel ); } bool FormulaDlg_Impl::UpdateParaWin(Selection& _rSelection) { OUString aStrEd; RefEdit* pEd = GetCurrRefEdit(); if (pEd && !m_pTheRefEdit) { _rSelection = pEd->GetSelection(); _rSelection.Justify(); aStrEd = pEd->GetText(); m_xEdRef->SetRefString(aStrEd); m_xEdRef->SetSelection( _rSelection ); } else { _rSelection = m_xEdRef->GetSelection(); _rSelection.Justify(); aStrEd = m_xEdRef->GetText(); } return m_pTheRefEdit == nullptr; } void FormulaDlg_Impl::SetEdSelection() { RefEdit* pEd = GetCurrRefEdit()/*aScParaWin.GetActiveEdit()*/; if (pEd) { Selection theSel = m_xEdRef->GetSelection(); // Edit may have the focus -> call ModifyHdl in addition // to what's happening in GetFocus pEd->GetModifyHdl().Call(*pEd); pEd->GrabFocus(); pEd->SetSelection(theSel); } // if ( pEd ) } FormulaModalDialog::FormulaModalDialog(weld::Window* pParent, IFunctionManager const * _pFunctionMgr, IControlReferenceHandler* _pDlg) : GenericDialogController(pParent, "formula/ui/formuladialog.ui", "FormulaDialog") , m_pImpl(new FormulaDlg_Impl(*m_xDialog, *m_xBuilder, false/*_bSupportFunctionResult*/, false/*_bSupportResult*/, false/*_bSupportMatrix*/, this, _pFunctionMgr, _pDlg)) { m_xDialog->set_title(m_pImpl->m_aTitle1); } FormulaModalDialog::~FormulaModalDialog() { } void FormulaModalDialog::Update(const OUString& _sExp) { m_pImpl->Update(_sExp); } void FormulaModalDialog::SetMeText(const OUString& _sText) { m_pImpl->SetMeText(_sText); } void FormulaModalDialog::CheckMatrix(OUString& aFormula) { m_pImpl->CheckMatrix(aFormula); } void FormulaModalDialog::Update() { m_pImpl->Update(); } ::std::pair FormulaModalDialog::RefInputStartBefore( RefEdit* pEdit, RefButton* pButton ) { return m_pImpl->RefInputStartBefore( pEdit, pButton ); } void FormulaModalDialog::RefInputStartAfter() { m_pImpl->RefInputStartAfter(); } void FormulaModalDialog::RefInputDoneAfter() { m_pImpl->RefInputDoneAfter( true/*bForced*/ ); } void FormulaModalDialog::StoreFormEditData(FormEditData* pData) { m_pImpl->StoreFormEditData(pData); } // Initialisation / General functions for Dialog FormulaDlg::FormulaDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent, IFunctionManager const * _pFunctionMgr, IControlReferenceHandler* _pDlg) : SfxModelessDialogController( pB, pCW, pParent, "formula/ui/formuladialog.ui", "FormulaDialog") , m_pImpl(new FormulaDlg_Impl(*m_xDialog, *m_xBuilder, true/*_bSupportFunctionResult*/ , true/*_bSupportResult*/ , true/*_bSupportMatrix*/ , this, _pFunctionMgr, _pDlg)) { m_xDialog->set_title(m_pImpl->m_aTitle1); } FormulaDlg::~FormulaDlg() { } void FormulaDlg::Update(const OUString& _sExp) { m_pImpl->Update(_sExp); } void FormulaDlg::SetMeText(const OUString& _sText) { m_pImpl->SetMeText(_sText); } FormulaDlgMode FormulaDlg::SetMeText( const OUString& _sText, sal_Int32 PrivStart, sal_Int32 PrivEnd, bool bMatrix, bool _bSelect, bool _bUpdate) { return m_pImpl->SetMeText( _sText, PrivStart, PrivEnd, bMatrix, _bSelect, _bUpdate); } bool FormulaDlg::CheckMatrix(OUString& aFormula) { return m_pImpl->CheckMatrix(aFormula); } OUString FormulaDlg::GetMeText() const { return m_pImpl->m_xMEdit->get_text(); } void FormulaDlg::Update() { m_pImpl->Update(); } void FormulaDlg::DoEnter() { m_pImpl->DoEnter(false); } ::std::pair 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: */