nss: upgrade to release 3.73
[LibreOffice.git] / formula / source / ui / dlg / formula.cxx
blob456d29e2de389fda02312bead90bccaba91b14b9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <memory>
21 #include <sfx2/viewfrm.hxx>
22 #include <vcl/svapp.hxx>
23 #include <vcl/weld.hxx>
25 #include <sal/log.hxx>
27 #include <unotools/charclass.hxx>
28 #include <tools/diagnose_ex.h>
30 #include "funcpage.hxx"
31 #include <formula/formula.hxx>
32 #include <formula/IFunctionDescription.hxx>
33 #include <formula/FormulaCompiler.hxx>
34 #include <formula/token.hxx>
35 #include <formula/tokenarray.hxx>
36 #include <formula/formdata.hxx>
37 #include <formula/formulahelper.hxx>
38 #include "structpg.hxx"
39 #include "parawin.hxx"
40 #include <strings.hrc>
41 #include <core_resource.hxx>
42 #include <com/sun/star/sheet/FormulaToken.hpp>
43 #include <com/sun/star/sheet/FormulaLanguage.hpp>
44 #include <com/sun/star/sheet/FormulaMapGroup.hpp>
45 #include <com/sun/star/sheet/FormulaMapGroupSpecialOffset.hpp>
46 #include <com/sun/star/sheet/XFormulaOpCodeMapper.hpp>
47 #include <com/sun/star/sheet/XFormulaParser.hpp>
48 #include <map>
50 // For tab page
51 #define TOKEN_OPEN 0
52 #define TOKEN_CLOSE 1
53 #define TOKEN_SEP 2
54 namespace formula
57 using namespace ::com::sun::star;
59 class FormulaDlg_Impl
61 public:
62 ::std::pair<RefButton*, RefEdit*>
63 RefInputStartBefore( RefEdit* pEdit, RefButton* pButton );
64 void RefInputStartAfter();
65 void RefInputDoneAfter( bool bForced );
66 bool CalcValue( const OUString& rStrExp, OUString& rStrResult, bool bForceMatrixFormula = false );
67 void CalcStruct( const OUString& rStrExp, bool bForceRecalcStruct = false );
68 void UpdateValues( bool bForceRecalcStruct = false );
69 void DeleteArgs();
70 sal_Int32 GetFunctionPos(sal_Int32 nPos);
71 void ClearAllParas();
73 void MakeTree(StructPage* _pTree, weld::TreeIter* pParent, const FormulaToken* pFuncToken,
74 const FormulaToken* _pToken, tools::Long Count);
75 void fillTree(StructPage* _pTree);
76 void UpdateTokenArray( const OUString& rStrExp);
77 OUString RepairFormula(const OUString& aFormula);
78 void FillDialog(bool bFlag = true);
79 bool EditNextFunc( bool bForward, sal_Int32 nFStart = NOT_FOUND );
80 void EditThisFunc(sal_Int32 nFStart);
82 OUString GetPrevFuncExpression( bool bStartFromEnd );
84 void StoreFormEditData(FormEditData* pEditData);
86 void Update();
87 void Update(const OUString& _sExp);
89 void SaveArg( sal_uInt16 nEd );
90 void UpdateSelection();
91 void DoEnter( bool bOk );
92 void FillListboxes();
93 void FillControls( bool &rbNext, bool &rbPrev);
95 FormulaDlgMode SetMeText( const OUString& _sText, sal_Int32 PrivStart, sal_Int32 PrivEnd, bool bMatrix, bool _bSelect, bool _bUpdate);
96 void SetMeText(const OUString& _sText);
97 bool CheckMatrix(OUString& aFormula /*IN/OUT*/);
99 void SetEdSelection();
101 bool UpdateParaWin(Selection& _rSelection);
102 void UpdateParaWin( const Selection& _rSelection, const OUString& _sRefStr);
104 void SetData( sal_Int32 nFStart, sal_Int32 nNextFStart, sal_Int32 nNextFEnd, sal_Int32& PrivStart, sal_Int32& PrivEnd);
106 RefEdit* GetCurrRefEdit();
108 const FormulaHelper& GetFormulaHelper() const { return m_aFormulaHelper;}
109 void InitFormulaOpCodeMapper();
111 void UpdateOldSel();
112 void FormulaCursor();
114 DECL_LINK( ModifyHdl, ParaWin&, void );
115 DECL_LINK( FxHdl, ParaWin&, void );
117 DECL_LINK( MatrixHdl, weld::Button&, void );
118 DECL_LINK( FormulaHdl, weld::TextView&, void);
119 DECL_LINK( FormulaCursorHdl, weld::TextView&, void );
120 DECL_LINK( BtnHdl, weld::Button&, void );
121 DECL_LINK( DblClkHdl, FuncPage&, void );
122 DECL_LINK( FuncSelHdl, FuncPage&, void );
123 DECL_LINK( StructSelHdl, StructPage&, void );
124 public:
125 mutable uno::Reference< sheet::XFormulaOpCodeMapper> m_xOpCodeMapper;
126 uno::Sequence< sheet::FormulaToken > m_aTokenList;
127 ::std::unique_ptr<FormulaTokenArray> m_pTokenArray;
128 ::std::unique_ptr<FormulaTokenArrayPlainIterator> m_pTokenArrayIterator;
129 mutable uno::Sequence< sheet::FormulaOpCodeMapEntry > m_aSpecialOpCodes;
130 mutable uno::Sequence< sheet::FormulaToken > m_aSeparatorsOpCodes;
131 mutable uno::Sequence< sheet::FormulaOpCodeMapEntry > m_aFunctionOpCodes;
132 mutable const sheet::FormulaOpCodeMapEntry* m_pFunctionOpCodesEnd;
133 ::std::map<const FormulaToken*, sheet::FormulaToken> m_aTokenMap;
134 IFormulaEditorHelper* m_pHelper;
135 weld::Dialog& m_rDialog;
137 OUString m_aOldFormula;
138 bool m_bStructUpdate;
139 bool m_bUserMatrixFlag;
141 const OUString m_aTitle1;
142 const OUString m_aTitle2;
143 FormulaHelper m_aFormulaHelper;
145 OString m_aEditHelpId;
147 OString m_aOldHelp;
148 bool m_bMakingTree; // in method of constructing tree
150 bool m_bEditFlag;
151 const IFunctionDescription* m_pFuncDesc;
152 sal_Int32 m_nArgs;
153 ::std::vector< OUString > m_aArguments;
154 Selection m_aFuncSel;
156 sal_Int32 m_nFuncExpStart; ///< current formula position for treeview results
158 int m_nSelectionStart;
159 int m_nSelectionEnd;
161 RefEdit* m_pTheRefEdit;
162 RefButton* m_pTheRefButton;
164 std::unique_ptr<weld::Notebook> m_xTabCtrl;
165 std::unique_ptr<weld::Container> m_xParaWinBox;
166 std::unique_ptr<ParaWin> m_xParaWin;
167 std::unique_ptr<weld::Label> m_xFtHeadLine;
168 std::unique_ptr<weld::Label> m_xFtFuncName;
169 std::unique_ptr<weld::Label> m_xFtFuncDesc;
171 std::unique_ptr<weld::Label> m_xFtEditName;
173 std::unique_ptr<weld::Label> m_xFtResult;
174 std::unique_ptr<weld::Entry> m_xWndResult;
176 std::unique_ptr<weld::Label> m_xFtFormula;
177 std::unique_ptr<weld::TextView> m_xMEdit;
179 std::unique_ptr<weld::CheckButton> m_xBtnMatrix;
180 std::unique_ptr<weld::Button> m_xBtnCancel;
182 std::unique_ptr<weld::Button> m_xBtnBackward;
183 std::unique_ptr<weld::Button> m_xBtnForward;
184 std::unique_ptr<weld::Button> m_xBtnEnd;
186 std::unique_ptr<weld::Label> m_xFtFormResult;
187 std::unique_ptr<weld::Entry> m_xWndFormResult;
189 std::unique_ptr<RefEdit> m_xEdRef;
190 std::unique_ptr<RefButton> m_xRefBtn;
192 std::unique_ptr<FuncPage> m_xFuncPage;
193 std::unique_ptr<StructPage> m_xStructPage;
195 FormulaDlg_Impl(weld::Dialog& rDialog,
196 weld::Builder& rBuilder,
197 bool _bSupportFunctionResult,
198 bool _bSupportResult,
199 bool _bSupportMatrix,
200 IFormulaEditorHelper* _pHelper,
201 const IFunctionManager* _pFunctionMgr,
202 IControlReferenceHandler* _pDlg);
203 ~FormulaDlg_Impl();
206 FormulaDlg_Impl::FormulaDlg_Impl(weld::Dialog& rDialog,
207 weld::Builder& rBuilder,
208 bool _bSupportFunctionResult,
209 bool _bSupportResult,
210 bool _bSupportMatrix,
211 IFormulaEditorHelper* _pHelper,
212 const IFunctionManager* _pFunctionMgr,
213 IControlReferenceHandler* _pDlg)
214 : m_pFunctionOpCodesEnd(nullptr)
215 , m_pHelper(_pHelper)
216 , m_rDialog(rDialog)
217 , m_bUserMatrixFlag(false)
218 , m_aTitle1( ForResId( STR_TITLE1 ) )
219 , m_aTitle2( ForResId( STR_TITLE2 ) )
220 , m_aFormulaHelper(_pFunctionMgr)
221 , m_bMakingTree(false)
222 , m_pFuncDesc(nullptr)
223 , m_nArgs(0)
224 , m_nFuncExpStart(0)
225 , m_nSelectionStart(-1)
226 , m_nSelectionEnd(-1)
227 , m_pTheRefEdit(nullptr)
228 , m_pTheRefButton(nullptr)
229 , m_xTabCtrl(rBuilder.weld_notebook("tabcontrol"))
230 , m_xParaWinBox(rBuilder.weld_container("BOX"))
231 , m_xFtHeadLine(rBuilder.weld_label("headline"))
232 , m_xFtFuncName(rBuilder.weld_label("funcname"))
233 , m_xFtFuncDesc(rBuilder.weld_label("funcdesc"))
234 , m_xFtEditName(rBuilder.weld_label("editname"))
235 , m_xFtResult(rBuilder.weld_label("label2"))
236 , m_xWndResult(rBuilder.weld_entry("result"))
237 , m_xFtFormula(rBuilder.weld_label("formula"))
238 , m_xMEdit(rBuilder.weld_text_view("ed_formula"))
239 , m_xBtnMatrix(rBuilder.weld_check_button("array"))
240 , m_xBtnCancel(rBuilder.weld_button("cancel"))
241 , m_xBtnBackward(rBuilder.weld_button("back"))
242 , m_xBtnForward(rBuilder.weld_button("next"))
243 , m_xBtnEnd(rBuilder.weld_button("ok"))
244 , m_xFtFormResult(rBuilder.weld_label("label1"))
245 , m_xWndFormResult(rBuilder.weld_entry("formula_result"))
246 , m_xEdRef(new RefEdit(rBuilder.weld_entry("ED_REF")))
247 , m_xRefBtn(new RefButton(rBuilder.weld_button("RB_REF")))
249 auto nWidth = m_xMEdit->get_approximate_digit_width() * 62;
251 //Space for two lines of text
252 m_xFtHeadLine->set_label("X\nX\n");
253 auto nHeight = m_xFtHeadLine->get_preferred_size().Height();
254 m_xFtHeadLine->set_size_request(nWidth, nHeight);
255 m_xFtHeadLine->set_label("");
257 m_xFtFuncName->set_label("X\nX\n");
258 nHeight = m_xFtFuncName->get_preferred_size().Height();
259 m_xFtFuncName->set_size_request(nWidth, nHeight);
260 m_xFtFuncDesc->set_size_request(nWidth, nHeight);
261 m_xFtFuncName->set_label("");
263 m_xMEdit->set_size_request(nWidth,
264 m_xMEdit->get_height_rows(5));
266 m_xEdRef->SetReferences(_pDlg, m_xFtEditName.get());
267 m_xRefBtn->SetReferences(_pDlg, m_xEdRef.get());
269 m_xParaWin.reset(new ParaWin(m_xParaWinBox.get(), _pDlg));
270 m_xParaWin->Show();
271 m_xParaWinBox->hide();
272 m_xFtEditName->hide();
273 m_xEdRef->GetWidget()->hide();
274 m_xRefBtn->GetWidget()->hide();
276 m_xMEdit->set_accessible_name(m_xFtFormula->get_label());
278 m_aEditHelpId = m_xMEdit->get_help_id();
280 m_bEditFlag =false;
281 m_bStructUpdate =true;
282 m_xParaWin->SetArgModifiedHdl( LINK( this, FormulaDlg_Impl, ModifyHdl ) );
283 m_xParaWin->SetFxHdl( LINK( this, FormulaDlg_Impl, FxHdl ) );
285 m_xFuncPage.reset(new FuncPage(m_xTabCtrl->get_page("function"), _pFunctionMgr));
286 m_xStructPage.reset(new StructPage(m_xTabCtrl->get_page("struct")));
287 m_xTabCtrl->set_current_page("function");
289 m_aOldHelp = m_rDialog.get_help_id(); // HelpId from resource always for "Page 1"
291 m_xFtResult->set_visible( _bSupportResult );
292 m_xWndResult->set_visible( _bSupportResult );
294 m_xFtFormResult->set_visible( _bSupportFunctionResult );
295 m_xWndFormResult->set_visible( _bSupportFunctionResult );
297 if ( _bSupportMatrix )
298 m_xBtnMatrix->connect_clicked( LINK( this, FormulaDlg_Impl, MatrixHdl ) );
299 else
300 m_xBtnMatrix->hide();
302 m_xBtnCancel->connect_clicked( LINK( this, FormulaDlg_Impl, BtnHdl ) );
303 m_xBtnEnd->connect_clicked( LINK( this, FormulaDlg_Impl, BtnHdl ) );
304 m_xBtnForward->connect_clicked( LINK( this, FormulaDlg_Impl, BtnHdl ) );
305 m_xBtnBackward->connect_clicked( LINK( this, FormulaDlg_Impl, BtnHdl ) );
307 m_xFuncPage->SetDoubleClickHdl( LINK( this, FormulaDlg_Impl, DblClkHdl ) );
308 m_xFuncPage->SetSelectHdl( LINK( this, FormulaDlg_Impl, FuncSelHdl) );
309 m_xStructPage->SetSelectionHdl( LINK( this, FormulaDlg_Impl, StructSelHdl ) );
310 m_xMEdit->connect_changed( LINK( this, FormulaDlg_Impl, FormulaHdl ) );
311 m_xMEdit->connect_cursor_position( LINK( this, FormulaDlg_Impl, FormulaCursorHdl ) );
313 vcl::Font aFntLight = m_xFtFormula->get_font();
314 vcl::Font aFntBold = aFntLight;
315 aFntBold.SetWeight( WEIGHT_BOLD );
317 m_xParaWin->SetArgumentFonts( aFntBold, aFntLight);
320 FormulaDlg_Impl::~FormulaDlg_Impl()
322 m_xTabCtrl->remove_page("function");
323 m_xTabCtrl->remove_page("struct");
325 DeleteArgs();
328 void FormulaDlg_Impl::StoreFormEditData(FormEditData* pData)
330 if (!pData) // it won't be destroyed via Close
331 return;
333 int nStartPos, nEndPos;
334 m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
335 if (nStartPos > nEndPos)
336 std::swap(nStartPos, nEndPos);
338 pData->SetFStart(nStartPos);
339 pData->SetSelection(Selection(nStartPos, nEndPos));
341 if (m_xTabCtrl->get_current_page_ident() == "function")
342 pData->SetMode( FormulaDlgMode::Formula );
343 else
344 pData->SetMode( FormulaDlgMode::Edit );
345 pData->SetUndoStr(m_xMEdit->get_text());
346 pData->SetMatrixFlag(m_xBtnMatrix->get_active());
349 void FormulaDlg_Impl::InitFormulaOpCodeMapper()
351 if ( m_xOpCodeMapper.is() )
352 return;
354 m_xOpCodeMapper = m_pHelper->getFormulaOpCodeMapper();
355 m_aFunctionOpCodes = m_xOpCodeMapper->getAvailableMappings( sheet::FormulaLanguage::ODFF, sheet::FormulaMapGroup::FUNCTIONS);
356 m_pFunctionOpCodesEnd = m_aFunctionOpCodes.getConstArray() + m_aFunctionOpCodes.getLength();
358 uno::Sequence< OUString > aArgs(3);
359 aArgs[TOKEN_OPEN] = "(";
360 aArgs[TOKEN_CLOSE] = ")";
361 aArgs[TOKEN_SEP] = ";";
362 m_aSeparatorsOpCodes = m_xOpCodeMapper->getMappings( aArgs, sheet::FormulaLanguage::ODFF);
364 m_aSpecialOpCodes = m_xOpCodeMapper->getAvailableMappings( sheet::FormulaLanguage::ODFF, sheet::FormulaMapGroup::SPECIAL);
367 void FormulaDlg_Impl::DeleteArgs()
369 ::std::vector< OUString>().swap(m_aArguments);
370 m_nArgs = 0;
373 sal_Int32 FormulaDlg_Impl::GetFunctionPos(sal_Int32 nPos)
375 if ( !m_aTokenList.hasElements() )
376 return SAL_MAX_INT32;
378 const sal_Unicode sep = m_pHelper->getFunctionManager()->getSingleToken(IFunctionManager::eSep);
380 sal_Int32 nFuncPos = SAL_MAX_INT32;
381 OUString aFormString = m_aFormulaHelper.GetCharClass()->uppercase(m_xMEdit->get_text());
383 const uno::Reference< sheet::XFormulaParser > xParser(m_pHelper->getFormulaParser());
384 const table::CellAddress aRefPos(m_pHelper->getReferencePosition());
386 const sheet::FormulaToken* pIter = m_aTokenList.getConstArray();
387 const sheet::FormulaToken* pEnd = pIter + m_aTokenList.getLength();
390 bool bFlag = false;
391 sal_Int32 nTokPos = 1;
392 sal_Int32 nOldTokPos = 1;
393 sal_Int32 nPrevFuncPos = 1;
394 short nBracketCount = 0;
395 while ( pIter != pEnd )
397 const sal_Int32 eOp = pIter->OpCode;
398 uno::Sequence<sheet::FormulaToken> aArgs(1);
399 aArgs[0] = *pIter;
400 const OUString aString = xParser->printFormula( aArgs, aRefPos);
401 const sheet::FormulaToken* pNextToken = pIter + 1;
403 if ( !m_bUserMatrixFlag && FormulaCompiler::IsMatrixFunction(static_cast<OpCode>(eOp)) )
405 m_xBtnMatrix->set_active(true);
408 if (eOp == m_aSpecialOpCodes[sheet::FormulaMapGroupSpecialOffset::PUSH].Token.OpCode ||
409 eOp == m_aSpecialOpCodes[sheet::FormulaMapGroupSpecialOffset::SPACES].Token.OpCode)
411 const sal_Int32 n1 = nTokPos < 0 ? -1 : aFormString.indexOf( sep, nTokPos);
412 const sal_Int32 n2 = nTokPos < 0 ? -1 : aFormString.indexOf( ')', nTokPos);
413 sal_Int32 nXXX = nTokPos;
414 if ( n1 < n2 && n1 != -1 )
416 nTokPos = n1;
418 else
420 nTokPos = n2;
422 if ( pNextToken != pEnd )
424 aArgs[0] = *pNextToken;
425 const OUString a2String = xParser->printFormula( aArgs, aRefPos);
426 const sal_Int32 n3 = nXXX < 0 ? -1 : aFormString.indexOf( a2String, nXXX);
427 if (n3 < nTokPos && n3 != -1)
428 nTokPos = n3;
431 else
433 nTokPos = nTokPos + aString.getLength();
436 if ( eOp == m_aSeparatorsOpCodes[TOKEN_OPEN].OpCode )
438 nBracketCount++;
439 bFlag = true;
441 else if ( eOp == m_aSeparatorsOpCodes[TOKEN_CLOSE].OpCode )
443 nBracketCount--;
444 bFlag = false;
445 nFuncPos = nPrevFuncPos;
447 bool bIsFunction = std::any_of( m_aFunctionOpCodes.getConstArray(),
448 m_pFunctionOpCodesEnd,
449 [&eOp](const sheet::FormulaOpCodeMapEntry& aEntry) { return aEntry.Token.OpCode == eOp; });
451 if ( bIsFunction && m_aSpecialOpCodes[sheet::FormulaMapGroupSpecialOffset::SPACES].Token.OpCode != eOp )
453 nPrevFuncPos = nFuncPos;
454 nFuncPos = nOldTokPos;
457 if ( nOldTokPos <= nPos && nPos < nTokPos )
459 if ( !bIsFunction )
461 if ( nBracketCount < 1 )
463 nFuncPos = m_xMEdit->get_text().getLength();
465 else if ( !bFlag )
467 nFuncPos = nPrevFuncPos;
470 break;
473 pIter = pNextToken;
474 nOldTokPos = nTokPos;
475 } // while ( pIter != pEnd )
477 catch ( const uno::Exception& )
479 TOOLS_WARN_EXCEPTION("formula.ui", "FormulaDlg_Impl::GetFunctionPos");
482 return nFuncPos;
485 bool FormulaDlg_Impl::CalcValue( const OUString& rStrExp, OUString& rStrResult, bool bForceMatrixFormula )
487 bool bResult = true;
489 if ( !rStrExp.isEmpty() )
491 // Only calculate the value when there isn't any more keyboard input:
493 // Make this debuggable by assigning to a variable that can be changed
494 // from within the debugger.
495 bool bInput = Application::AnyInput( VclInputFlags::KEYBOARD );
496 if ( !bInput )
498 bResult = m_pHelper->calculateValue( rStrExp, rStrResult, bForceMatrixFormula || m_xBtnMatrix->get_active());
500 else
501 bResult = false;
504 return bResult;
507 void FormulaDlg_Impl::UpdateValues( bool bForceRecalcStruct )
509 // Take a force-array context into account. RPN creation propagated those
510 // to tokens that are ref-counted so also available in the token array.
511 bool bForceArray = false;
512 // Only necessary if it's not a matrix formula anyway and matrix evaluation
513 // is supported, i.e. the button is visible.
514 if (m_xBtnMatrix->get_visible() && !m_xBtnMatrix->get_active())
516 std::unique_ptr<FormulaCompiler> pCompiler(m_pHelper->createCompiler(*m_pTokenArray));
517 // In the case of the reportdesign dialog there is no currently active
518 // OpCode symbol mapping that could be used to create strings from
519 // tokens, it's all dreaded API mapping. However, in that case there's
520 // no array/matrix support anyway, but ensure checking.
521 if (pCompiler->GetCurrentOpCodeMap())
523 const sal_Int32 nPos = m_aFuncSel.Min();
524 assert( 0 <= nPos && nPos < m_pHelper->getCurrentFormula().getLength());
525 OUStringBuffer aBuf;
526 const FormulaToken* pToken = nullptr;
527 for (pToken = m_pTokenArrayIterator->First(); pToken; pToken = m_pTokenArrayIterator->Next())
529 pCompiler->CreateStringFromToken( aBuf, pToken);
530 if (nPos < aBuf.getLength())
531 break;
533 if (pToken && nPos < aBuf.getLength())
534 bForceArray = pToken->IsInForceArray();
538 OUString aStrResult;
539 if (m_pFuncDesc && CalcValue( m_pFuncDesc->getFormula( m_aArguments), aStrResult, bForceArray))
540 m_xWndResult->set_text( aStrResult );
542 if (m_bMakingTree)
543 return;
545 aStrResult.clear();
546 if ( CalcValue( m_pHelper->getCurrentFormula(), aStrResult ) )
547 m_xWndFormResult->set_text( aStrResult );
548 else
550 aStrResult.clear();
551 m_xWndFormResult->set_text( aStrResult );
553 CalcStruct( m_xMEdit->get_text(), bForceRecalcStruct);
556 void FormulaDlg_Impl::CalcStruct( const OUString& rStrExp, bool bForceRecalcStruct )
558 sal_Int32 nLength = rStrExp.getLength();
560 if ( !(!rStrExp.isEmpty() && (bForceRecalcStruct || m_aOldFormula != rStrExp) && m_bStructUpdate))
561 return;
563 m_xStructPage->ClearStruct();
565 OUString aString = rStrExp;
566 if (rStrExp[nLength-1] == '(')
568 aString = aString.copy( 0, nLength-1);
571 aString = aString.replaceAll( "\n", "");
572 OUString aStrResult;
574 if ( CalcValue( aString, aStrResult ) )
575 m_xWndFormResult->set_text(aStrResult);
577 UpdateTokenArray(aString);
578 fillTree(m_xStructPage.get());
580 m_aOldFormula = rStrExp;
581 if (rStrExp[nLength-1] == '(')
582 UpdateTokenArray(rStrExp);
585 void FormulaDlg_Impl::MakeTree(StructPage* _pTree, weld::TreeIter* pParent, const FormulaToken* pFuncToken,
586 const FormulaToken* _pToken, tools::Long Count)
588 if ( _pToken == nullptr || Count <= 0 )
589 return;
591 tools::Long nParas = _pToken->GetParamCount();
592 OpCode eOp = _pToken->GetOpCode();
594 // #i101512# for output, the original token is needed
595 const FormulaToken* pOrigToken = (_pToken->GetType() == svFAP) ? _pToken->GetFAPOrigToken() : _pToken;
596 uno::Sequence<sheet::FormulaToken> aArgs(1);
597 ::std::map<const FormulaToken*, sheet::FormulaToken>::const_iterator itr = m_aTokenMap.find(pOrigToken);
598 if (itr == m_aTokenMap.end())
599 return;
601 aArgs[0] = itr->second;
604 const table::CellAddress aRefPos(m_pHelper->getReferencePosition());
605 const OUString aResult = m_pHelper->getFormulaParser()->printFormula( aArgs, aRefPos);
607 if ( nParas > 0 || (nParas == 0 && _pToken->IsFunction()) )
609 std::unique_ptr<weld::TreeIter> xEntry;
610 weld::TreeIter* pEntry;
612 bool bCalcSubformula = false;
613 OUString aTest = _pTree->GetEntryText(pParent);
615 if (aTest == aResult && (eOp == ocAdd || eOp == ocMul || eOp == ocAmpersand))
617 pEntry = pParent;
619 else
621 xEntry = m_xStructPage->GetTlbStruct().make_iterator();
623 if (eOp == ocBad)
625 _pTree->InsertEntry(aResult, pParent, STRUCT_ERROR, 0, _pToken, *xEntry);
627 else if (!((SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP) ||
628 (SC_OPCODE_START_UN_OP <= eOp && eOp < SC_OPCODE_STOP_UN_OP)))
630 // Not a binary or unary operator.
631 bCalcSubformula = true;
632 _pTree->InsertEntry(aResult, pParent, STRUCT_FOLDER, 0, _pToken, *xEntry);
634 else
636 /* TODO: question remains, why not sub calculate operators? */
637 _pTree->InsertEntry(aResult, pParent, STRUCT_FOLDER, 0, _pToken, *xEntry);
640 pEntry = xEntry.get();
643 MakeTree(_pTree, pEntry, _pToken, m_pTokenArrayIterator->PrevRPN(), nParas);
645 if (bCalcSubformula)
647 OUString aFormula;
649 if (!m_bMakingTree)
651 // gets the last subformula result
652 m_bMakingTree = true;
653 aFormula = GetPrevFuncExpression( true);
655 else
657 // gets subsequent subformula results (from the back)
658 aFormula = GetPrevFuncExpression( false);
661 OUString aStr;
662 if (CalcValue( aFormula, aStr, _pToken->IsInForceArray()))
663 m_xWndResult->set_text( aStr );
664 aStr = m_xWndResult->get_text();
665 m_xStructPage->GetTlbStruct().set_text(*pEntry, aResult + " = " + aStr);
668 --Count;
669 m_pTokenArrayIterator->NextRPN(); /* TODO: what's this to be? ThisRPN()? */
670 MakeTree( _pTree, pParent, _pToken, m_pTokenArrayIterator->PrevRPN(), Count);
672 else
674 std::unique_ptr<weld::TreeIter> xEntry(m_xStructPage->GetTlbStruct().make_iterator());
675 if (eOp == ocBad)
677 _pTree->InsertEntry( aResult, pParent, STRUCT_ERROR, 0, _pToken, *xEntry);
679 else if (eOp == ocPush)
681 // Interpret range reference in matrix context to resolve
682 // as array elements. Depending on parameter classification
683 // a scalar value (non-array context) is calculated first.
684 OUString aUnforcedResult;
685 bool bForceMatrix = (!m_xBtnMatrix->get_active() &&
686 (_pToken->GetType() == svDoubleRef || _pToken->GetType() == svExternalDoubleRef));
687 if (bForceMatrix && pFuncToken)
689 formula::ParamClass eParamClass = ParamClass::Reference;
690 if (pFuncToken->IsInForceArray())
691 eParamClass = ParamClass::ForceArray;
692 else
694 std::shared_ptr<FormulaCompiler> pCompiler = m_pHelper->getCompiler();
695 if (pCompiler)
696 eParamClass = pCompiler->GetForceArrayParameter( pFuncToken, Count - 1);
698 switch (eParamClass)
700 case ParamClass::Unknown:
701 case ParamClass::Bounds:
702 case ParamClass::Value:
703 if (CalcValue( "=" + aResult, aUnforcedResult, false) && aUnforcedResult != aResult)
704 aUnforcedResult += " ";
705 else
706 aUnforcedResult.clear();
707 break;
708 case ParamClass::Reference:
709 case ParamClass::ReferenceOrRefArray:
710 case ParamClass::Array:
711 case ParamClass::ForceArray:
712 case ParamClass::ReferenceOrForceArray:
713 case ParamClass::SuppressedReferenceOrForceArray:
714 case ParamClass::ForceArrayReturn:
715 ; // nothing, only as array/matrix
716 // no default to get compiler warning
719 OUString aCellResult;
720 if (CalcValue( "=" + aResult, aCellResult, bForceMatrix) && aCellResult != aResult)
722 // Cell is a formula, print subformula.
723 // With scalar values prints "A1:A3 = 2 {1;2;3}"
724 _pTree->InsertEntry( aResult + " = " + aUnforcedResult + aCellResult,
725 pParent, STRUCT_END, 0, _pToken, *xEntry);
727 else
728 _pTree->InsertEntry(aResult, pParent, STRUCT_END, 0, _pToken, *xEntry);
730 else
732 _pTree->InsertEntry(aResult, pParent, STRUCT_END, 0, _pToken, *xEntry);
734 --Count;
735 MakeTree( _pTree, pParent, _pToken, m_pTokenArrayIterator->PrevRPN(), Count);
738 catch (const uno::Exception&)
740 DBG_UNHANDLED_EXCEPTION("formula.ui");
744 void FormulaDlg_Impl::fillTree(StructPage* _pTree)
746 InitFormulaOpCodeMapper();
747 FormulaToken* pToken = m_pTokenArrayIterator->LastRPN();
749 if ( pToken != nullptr)
751 MakeTree( _pTree, nullptr, nullptr, pToken, 1);
752 m_bMakingTree = false;
756 void FormulaDlg_Impl::UpdateTokenArray( const OUString& rStrExp)
758 m_aTokenMap.clear();
759 m_aTokenList.realloc(0);
762 const table::CellAddress aRefPos(m_pHelper->getReferencePosition());
763 m_aTokenList = m_pHelper->getFormulaParser()->parseFormula( rStrExp, aRefPos);
765 catch (const uno::Exception&)
767 DBG_UNHANDLED_EXCEPTION("formula.ui");
769 InitFormulaOpCodeMapper();
770 m_pTokenArray = m_pHelper->convertToTokenArray(m_aTokenList);
771 m_pTokenArrayIterator.reset(new FormulaTokenArrayPlainIterator(*m_pTokenArray));
772 const sal_Int32 nLen = static_cast<sal_Int32>(m_pTokenArray->GetLen());
773 FormulaToken** pTokens = m_pTokenArray->GetArray();
774 if ( pTokens && nLen == m_aTokenList.getLength() )
776 for (sal_Int32 nPos = 0; nPos < nLen; nPos++)
778 m_aTokenMap.emplace( pTokens[nPos], m_aTokenList[nPos] );
780 } // if ( pTokens && nLen == m_aTokenList.getLength() )
782 std::unique_ptr<FormulaCompiler> pCompiler(m_pHelper->createCompiler(*m_pTokenArray));
783 // #i101512# Disable special handling of jump commands.
784 pCompiler->EnableJumpCommandReorder(false);
785 pCompiler->EnableStopOnError(false);
786 pCompiler->SetComputeIIFlag(true);
787 pCompiler->SetMatrixFlag(m_bUserMatrixFlag);
788 pCompiler->CompileTokenArray();
791 void FormulaDlg_Impl::FillDialog(bool bFlag)
793 bool bNext = true, bPrev = true;
794 if (bFlag)
795 FillControls( bNext, bPrev);
796 FillListboxes();
797 if (bFlag)
799 m_xBtnBackward->set_sensitive(bPrev);
800 m_xBtnForward->set_sensitive(bNext);
803 OUString aStrResult;
805 if ( CalcValue( m_pHelper->getCurrentFormula(), aStrResult ) )
806 m_xWndFormResult->set_text( aStrResult );
807 else
809 aStrResult.clear();
810 m_xWndFormResult->set_text( aStrResult );
814 void FormulaDlg_Impl::FillListboxes()
816 // Switch between the "Pages"
817 FormEditData* pData = m_pHelper->getFormEditData();
818 // 1. Page: select function
819 if ( m_pFuncDesc && m_pFuncDesc->getCategory() )
821 // We'll never have more than int32 max categories so this is safe ...
822 // Category listbox holds additional entries for Last Used and All, so
823 // the offset should be two but hard coded numbers are ugly...
824 const sal_Int32 nCategoryOffset = m_xFuncPage->GetCategoryEntryCount() - m_aFormulaHelper.GetCategoryCount();
825 if ( m_xFuncPage->GetCategory() != static_cast<sal_Int32>(m_pFuncDesc->getCategory()->getNumber() + nCategoryOffset) )
826 m_xFuncPage->SetCategory(m_pFuncDesc->getCategory()->getNumber() + nCategoryOffset);
828 sal_Int32 nPos = m_xFuncPage->GetFuncPos(m_pFuncDesc);
830 m_xFuncPage->SetFunction(nPos);
832 else if ( pData )
834 m_xFuncPage->SetCategory( 1 );
835 m_xFuncPage->SetFunction( -1 );
837 FuncSelHdl(*m_xFuncPage);
839 m_pHelper->setDispatcherLock( true ); // Activate Modal-Mode
841 // HelpId for 1. page is the one from the resource
842 m_rDialog.set_help_id( m_aOldHelp );
845 void FormulaDlg_Impl::FillControls( bool &rbNext, bool &rbPrev)
847 // Switch between the "Pages"
848 FormEditData* pData = m_pHelper->getFormEditData();
849 if (!pData )
850 return;
852 // 2. Page or Edit: show selected function
854 sal_Int32 nFStart = pData->GetFStart();
855 OUString aFormula = m_pHelper->getCurrentFormula() + " )";
856 sal_Int32 nNextFStart = nFStart;
857 sal_Int32 nNextFEnd = 0;
859 DeleteArgs();
860 const IFunctionDescription* pOldFuncDesc = m_pFuncDesc;
862 if ( m_aFormulaHelper.GetNextFunc( aFormula, false,
863 nNextFStart, &nNextFEnd, &m_pFuncDesc, &m_aArguments ) )
865 const bool bTestFlag = (pOldFuncDesc != m_pFuncDesc);
866 if (bTestFlag)
868 m_xFtHeadLine->hide();
869 m_xFtFuncName->hide();
870 m_xFtFuncDesc->hide();
871 m_xParaWin->SetFunctionDesc(m_pFuncDesc);
872 m_xFtEditName->set_label( m_pFuncDesc->getFunctionName() );
873 m_xFtEditName->show();
874 m_xParaWinBox->show();
875 const OString aHelpId = m_pFuncDesc->getHelpId();
876 if ( !aHelpId.isEmpty() )
877 m_xMEdit->set_help_id(aHelpId);
880 sal_Int32 nOldStart, nOldEnd;
881 m_pHelper->getSelection( nOldStart, nOldEnd );
882 if ( nOldStart != nNextFStart || nOldEnd != nNextFEnd )
884 m_pHelper->setSelection( nNextFStart, nNextFEnd );
886 m_aFuncSel.Min() = nNextFStart;
887 m_aFuncSel.Max() = nNextFEnd;
889 if (!m_bEditFlag)
890 m_xMEdit->set_text(m_pHelper->getCurrentFormula());
891 sal_Int32 PrivStart, PrivEnd;
892 m_pHelper->getSelection( PrivStart, PrivEnd);
893 if (!m_bEditFlag)
894 m_xMEdit->select_region(PrivStart, PrivEnd);
896 m_nArgs = m_pFuncDesc->getSuppressedArgumentCount();
897 sal_uInt16 nOffset = pData->GetOffset();
899 // Concatenate the Edit's for Focus-Control
901 if (bTestFlag)
902 m_xParaWin->SetArgumentOffset(nOffset);
903 sal_uInt16 nActiv = 0;
904 sal_Int32 nArgPos = m_aFormulaHelper.GetArgStart( aFormula, nFStart, 0 );
906 int nStartPos, nEndPos;
907 m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
908 if (nStartPos > nEndPos)
909 std::swap(nStartPos, nEndPos);
911 sal_Int32 nEditPos = nStartPos;
912 bool bFlag = false;
914 for (sal_Int32 i = 0; i < m_nArgs; i++)
916 sal_Int32 nLength = m_aArguments[i].getLength()+1;
917 m_xParaWin->SetArgument( i, m_aArguments[i]);
918 if (nArgPos <= nEditPos && nEditPos < nArgPos+nLength)
920 nActiv = i;
921 bFlag = true;
923 nArgPos = nArgPos + nLength;
925 m_xParaWin->UpdateParas();
927 if (bFlag)
929 m_xParaWin->SetActiveLine(nActiv);
932 UpdateValues();
934 else
936 m_xFtEditName->set_label("");
937 m_xMEdit->set_help_id(m_aEditHelpId);
939 // test if before/after are anymore functions
941 sal_Int32 nTempStart = m_aFormulaHelper.GetArgStart( aFormula, nFStart, 0 );
942 rbNext = m_aFormulaHelper.GetNextFunc( aFormula, false, nTempStart );
944 int nStartPos, nEndPos;
945 m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
946 if (nStartPos > nEndPos)
947 std::swap(nStartPos, nEndPos);
949 nTempStart = nStartPos;
950 pData->SetFStart(nTempStart);
951 rbPrev = m_aFormulaHelper.GetNextFunc( aFormula, true, nTempStart );
955 void FormulaDlg_Impl::ClearAllParas()
957 DeleteArgs();
958 m_pFuncDesc = nullptr;
959 m_xParaWin->ClearAll();
960 m_xWndResult->set_text(OUString());
961 m_xFtFuncName->set_label(OUString());
962 FuncSelHdl(*m_xFuncPage);
964 if (m_xFuncPage->IsVisible())
966 m_xFtEditName->hide();
967 m_xParaWinBox->hide();
969 m_xBtnForward->set_sensitive(true); //@new
970 m_xFtHeadLine->show();
971 m_xFtFuncName->show();
972 m_xFtFuncDesc->show();
976 OUString FormulaDlg_Impl::RepairFormula(const OUString& aFormula)
978 OUString aResult('=');
981 UpdateTokenArray(aFormula);
983 if ( m_aTokenList.hasElements() )
985 const table::CellAddress aRefPos(m_pHelper->getReferencePosition());
986 const OUString sFormula( m_pHelper->getFormulaParser()->printFormula( m_aTokenList, aRefPos));
987 if ( sFormula.isEmpty() || sFormula[0] != '=' )
988 aResult += sFormula;
989 else
990 aResult = sFormula;
994 catch ( const uno::Exception& )
996 TOOLS_WARN_EXCEPTION("formula.ui", "FormulaDlg_Impl::RepairFormula");
998 return aResult;
1001 void FormulaDlg_Impl::DoEnter(bool bOk)
1003 // Accept input to the document or cancel
1004 if ( bOk)
1006 // remove dummy arguments
1007 OUString aInputFormula = m_pHelper->getCurrentFormula();
1008 OUString aString = RepairFormula(m_xMEdit->get_text());
1009 m_pHelper->setSelection( 0, aInputFormula.getLength());
1010 m_pHelper->setCurrentFormula(aString);
1013 m_pHelper->switchBack();
1015 m_pHelper->dispatch( bOk, m_xBtnMatrix->get_active());
1016 // Clear data
1017 m_pHelper->deleteFormData();
1019 // Close dialog
1020 m_pHelper->doClose(bOk);
1024 IMPL_LINK(FormulaDlg_Impl, BtnHdl, weld::Button&, rBtn, void)
1026 if (&rBtn == m_xBtnCancel.get())
1028 DoEnter(false); // closes the Dialog
1030 else if (&rBtn == m_xBtnEnd.get())
1032 DoEnter(true); // closes the Dialog
1034 else if (&rBtn == m_xBtnForward.get())
1036 const IFunctionDescription* pDesc;
1037 sal_Int32 nSelFunc = m_xFuncPage->GetFunction();
1038 if (nSelFunc != -1)
1039 pDesc = m_xFuncPage->GetFuncDesc( nSelFunc );
1040 else
1042 // Do not overwrite the selected formula expression, just edit the
1043 // unlisted function.
1044 m_pFuncDesc = pDesc = nullptr;
1047 if (pDesc == m_pFuncDesc || !m_xFuncPage->IsVisible())
1048 EditNextFunc( true );
1049 else
1051 DblClkHdl(*m_xFuncPage); //new
1052 m_xBtnForward->set_sensitive(false); //new
1055 else if (&rBtn == m_xBtnBackward.get())
1057 m_bEditFlag = false;
1058 m_xBtnForward->set_sensitive(true);
1059 EditNextFunc( false );
1063 // Functions for 1. Page
1065 // Handler for Listboxes
1067 IMPL_LINK_NOARG( FormulaDlg_Impl, DblClkHdl, FuncPage&, void)
1069 sal_Int32 nFunc = m_xFuncPage->GetFunction();
1071 // ex-UpdateLRUList
1072 const IFunctionDescription* pDesc = m_xFuncPage->GetFuncDesc(nFunc);
1073 m_pHelper->insertEntryToLRUList(pDesc);
1075 OUString aFuncName = m_xFuncPage->GetSelFunctionName() + "()";
1076 m_pHelper->setCurrentFormula(aFuncName);
1077 m_xMEdit->replace_selection(aFuncName);
1079 int nStartPos, nEndPos;
1080 m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
1081 if (nStartPos > nEndPos)
1082 std::swap(nStartPos, nEndPos);
1084 nEndPos = nEndPos - 1;
1085 m_xMEdit->select_region(nStartPos, nEndPos);
1087 FormulaHdl(*m_xMEdit);
1089 nStartPos = nEndPos;
1090 m_xMEdit->select_region(nStartPos, nEndPos);
1092 if (m_nArgs == 0)
1094 BtnHdl(*m_xBtnBackward);
1097 m_xParaWin->SetEdFocus();
1098 m_xBtnForward->set_sensitive(false); //@New
1101 // Functions for right Page
1103 void FormulaDlg_Impl::SetData( sal_Int32 nFStart, sal_Int32 nNextFStart, sal_Int32 nNextFEnd, sal_Int32& PrivStart, sal_Int32& PrivEnd)
1105 sal_Int32 nFEnd;
1107 // Notice and set new selection
1108 m_pHelper->getSelection( nFStart, nFEnd );
1109 m_pHelper->setSelection( nNextFStart, nNextFEnd );
1110 if (!m_bEditFlag)
1111 m_xMEdit->set_text(m_pHelper->getCurrentFormula());
1114 m_pHelper->getSelection( PrivStart, PrivEnd);
1115 if (!m_bEditFlag)
1117 m_xMEdit->select_region(PrivStart, PrivEnd);
1118 UpdateOldSel();
1121 FormEditData* pData = m_pHelper->getFormEditData();
1122 pData->SetFStart( nNextFStart );
1123 pData->SetOffset( 0 );
1125 FillDialog();
1128 void FormulaDlg_Impl::EditThisFunc(sal_Int32 nFStart)
1130 FormEditData* pData = m_pHelper->getFormEditData();
1131 if (!pData)
1132 return;
1134 OUString aFormula = m_pHelper->getCurrentFormula();
1136 if (nFStart == NOT_FOUND)
1138 nFStart = pData->GetFStart();
1140 else
1142 pData->SetFStart(nFStart);
1145 sal_Int32 nNextFStart = nFStart;
1146 sal_Int32 nNextFEnd = 0;
1148 bool bFound;
1150 bFound = m_aFormulaHelper.GetNextFunc( aFormula, false, nNextFStart, &nNextFEnd);
1151 if ( bFound )
1153 sal_Int32 PrivStart, PrivEnd;
1154 SetData( nFStart, nNextFStart, nNextFEnd, PrivStart, PrivEnd);
1155 m_pHelper->showReference( aFormula.copy( PrivStart, PrivEnd-PrivStart));
1157 else
1159 ClearAllParas();
1163 bool FormulaDlg_Impl::EditNextFunc( bool bForward, sal_Int32 nFStart )
1165 FormEditData* pData = m_pHelper->getFormEditData();
1166 if (!pData)
1167 return false;
1169 OUString aFormula = m_pHelper->getCurrentFormula();
1171 if (nFStart == NOT_FOUND)
1173 nFStart = pData->GetFStart();
1175 else
1177 pData->SetFStart(nFStart);
1180 sal_Int32 nNextFStart = 0;
1181 sal_Int32 nNextFEnd = 0;
1183 bool bFound;
1184 if ( bForward )
1186 nNextFStart = m_aFormulaHelper.GetArgStart( aFormula, nFStart, 0 );
1187 bFound = m_aFormulaHelper.GetNextFunc( aFormula, false, nNextFStart, &nNextFEnd);
1189 else
1191 nNextFStart = nFStart;
1192 bFound = m_aFormulaHelper.GetNextFunc( aFormula, true, nNextFStart, &nNextFEnd);
1195 if ( bFound )
1197 sal_Int32 PrivStart, PrivEnd;
1198 SetData( nFStart, nNextFStart, nNextFEnd, PrivStart, PrivEnd);
1201 return bFound;
1204 OUString FormulaDlg_Impl::GetPrevFuncExpression( bool bStartFromEnd )
1206 OUString aExpression;
1208 OUString aFormula( m_pHelper->getCurrentFormula());
1209 if (aFormula.isEmpty())
1210 return aExpression;
1212 if (bStartFromEnd || m_nFuncExpStart >= aFormula.getLength())
1213 m_nFuncExpStart = aFormula.getLength() - 1;
1215 sal_Int32 nFStart = m_nFuncExpStart;
1216 sal_Int32 nFEnd = 0;
1217 if (m_aFormulaHelper.GetNextFunc( aFormula, true, nFStart, &nFEnd))
1219 aExpression = aFormula.copy( nFStart, nFEnd - nFStart); // nFEnd is exclusive
1220 m_nFuncExpStart = nFStart;
1223 return aExpression;
1226 void FormulaDlg_Impl::SaveArg( sal_uInt16 nEd )
1228 if (nEd >= m_nArgs)
1229 return;
1231 for (sal_uInt16 i = 0; i <= nEd; i++)
1233 if ( m_aArguments[i].isEmpty() )
1234 m_aArguments[i] = " ";
1236 if (!m_xParaWin->GetArgument(nEd).isEmpty())
1237 m_aArguments[nEd] = m_xParaWin->GetArgument(nEd);
1239 sal_uInt16 nClearPos = nEd+1;
1240 for (sal_Int32 i = nEd+1; i < m_nArgs; i++)
1242 if ( !m_xParaWin->GetArgument(i).isEmpty() )
1244 nClearPos = i+1;
1248 for (sal_Int32 i = nClearPos; i < m_nArgs; i++)
1250 m_aArguments[i].clear();
1254 IMPL_LINK( FormulaDlg_Impl, FxHdl, ParaWin&, rPtr, void )
1256 if (&rPtr != m_xParaWin.get())
1257 return;
1259 m_xBtnForward->set_sensitive(true); //@ In order to be able to input another function.
1260 m_xTabCtrl->set_current_page("function");
1262 OUString aUndoStr = m_pHelper->getCurrentFormula(); // it will be added before a ";"
1263 FormEditData* pData = m_pHelper->getFormEditData();
1264 if (!pData)
1265 return;
1267 sal_uInt16 nArgNo = m_xParaWin->GetActiveLine();
1268 sal_uInt16 nEdFocus = nArgNo;
1270 SaveArg(nArgNo);
1271 UpdateSelection();
1273 sal_Int32 nFormulaStrPos = pData->GetFStart();
1275 OUString aFormula = m_pHelper->getCurrentFormula();
1276 sal_Int32 n1 = m_aFormulaHelper.GetArgStart( aFormula, nFormulaStrPos, nEdFocus + pData->GetOffset() );
1278 pData->SaveValues();
1279 pData->SetMode( FormulaDlgMode::Formula );
1280 pData->SetFStart( n1 );
1281 pData->SetUndoStr( aUndoStr );
1282 ClearAllParas();
1284 FillDialog(false);
1285 m_xFuncPage->SetFocus(); //There Parawin is not visible anymore
1288 IMPL_LINK( FormulaDlg_Impl, ModifyHdl, ParaWin&, rPtr, void )
1290 if (&rPtr == m_xParaWin.get())
1292 SaveArg(m_xParaWin->GetActiveLine());
1293 UpdateValues();
1295 UpdateSelection();
1296 CalcStruct(m_xMEdit->get_text());
1300 IMPL_LINK_NOARG( FormulaDlg_Impl, FormulaHdl, weld::TextView&, void)
1303 FormEditData* pData = m_pHelper->getFormEditData();
1304 if (!pData)
1305 return;
1307 m_bEditFlag = true;
1308 OUString aInputFormula = m_pHelper->getCurrentFormula();
1309 OUString aString = m_xMEdit->get_text();
1311 int nStartPos, nEndPos;
1312 m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
1313 if (nStartPos > nEndPos)
1314 std::swap(nStartPos, nEndPos);
1316 if (aString.isEmpty()) // in case everything was cleared
1318 aString += "=";
1319 m_xMEdit->set_text(aString);
1320 nStartPos = 1;
1321 nEndPos = 1;
1322 m_xMEdit->select_region(nStartPos, nEndPos);
1324 else if (aString[0]!='=') // in case it's replaced
1326 aString = "=" + aString;
1327 m_xMEdit->set_text(aString);
1328 nStartPos += 1;
1329 nEndPos += 1;
1330 m_xMEdit->select_region(nStartPos, nEndPos);
1333 m_pHelper->setSelection( 0, aInputFormula.getLength());
1334 m_pHelper->setCurrentFormula(aString);
1335 m_pHelper->setSelection(nStartPos, nEndPos);
1337 sal_Int32 nPos = nStartPos - 1;
1339 OUString aStrResult;
1341 if ( CalcValue( m_pHelper->getCurrentFormula(), aStrResult ) )
1342 m_xWndFormResult->set_text( aStrResult );
1343 else
1345 aStrResult.clear();
1346 m_xWndFormResult->set_text( aStrResult );
1348 CalcStruct(aString);
1350 nPos = GetFunctionPos(nPos);
1352 if (nPos < nStartPos - 1)
1354 sal_Int32 nPos1 = aString.indexOf( '(', nPos);
1355 EditNextFunc( false, nPos1);
1357 else
1359 ClearAllParas();
1362 m_pHelper->setSelection(nStartPos, nEndPos);
1363 m_bEditFlag = false;
1366 void FormulaDlg_Impl::FormulaCursor()
1368 FormEditData* pData = m_pHelper->getFormEditData();
1369 if (!pData)
1370 return;
1372 m_bEditFlag = true;
1374 OUString aString = m_xMEdit->get_text();
1376 int nStartPos, nEndPos;
1377 m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
1378 if (nStartPos > nEndPos)
1379 std::swap(nStartPos, nEndPos);
1381 m_pHelper->setSelection(nStartPos, nEndPos);
1383 if (nStartPos == 0)
1385 nStartPos = 1;
1386 m_xMEdit->select_region(nStartPos, nEndPos);
1388 if (nStartPos != aString.getLength())
1390 sal_Int32 nPos = nStartPos;
1392 sal_Int32 nFStart = GetFunctionPos(nPos - 1);
1394 if (nFStart < nPos)
1396 sal_Int32 nPos1 = m_aFormulaHelper.GetFunctionEnd( aString, nFStart);
1398 if (nPos1 > nPos)
1400 EditThisFunc(nFStart);
1402 else
1404 sal_Int32 n = nPos;
1405 short nCount = 1;
1406 while(n > 0)
1408 if (aString[n]==')')
1409 nCount++;
1410 else if (aString[n]=='(')
1411 nCount--;
1412 if (nCount == 0)
1413 break;
1414 n--;
1416 if (nCount == 0)
1418 nFStart = m_aFormulaHelper.GetFunctionStart( aString, n, true);
1419 EditThisFunc(nFStart);
1421 else
1423 ClearAllParas();
1427 else
1429 ClearAllParas();
1432 m_pHelper->setSelection(nStartPos, nEndPos);
1434 m_bEditFlag = false;
1437 void FormulaDlg_Impl::UpdateOldSel()
1439 m_xMEdit->get_selection_bounds(m_nSelectionStart, m_nSelectionEnd);
1440 if (m_nSelectionStart > m_nSelectionEnd)
1441 std::swap(m_nSelectionStart, m_nSelectionEnd);
1444 IMPL_LINK_NOARG( FormulaDlg_Impl, FormulaCursorHdl, weld::TextView&, void)
1446 int nStartPos, nEndPos;
1447 m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
1448 if (nStartPos > nEndPos)
1449 std::swap(nStartPos, nEndPos);
1451 if (nStartPos != m_nSelectionStart || nEndPos != m_nSelectionEnd)
1453 m_nSelectionStart = nStartPos;
1454 m_nSelectionEnd = nEndPos;
1455 FormulaCursor();
1459 void FormulaDlg_Impl::UpdateSelection()
1461 m_pHelper->setSelection( m_aFuncSel.Min(), m_aFuncSel.Max());
1462 m_pHelper->setCurrentFormula( m_pFuncDesc->getFormula( m_aArguments ) );
1463 m_xMEdit->set_text(m_pHelper->getCurrentFormula());
1464 sal_Int32 PrivStart, PrivEnd;
1465 m_pHelper->getSelection( PrivStart, PrivEnd);
1466 m_aFuncSel.Min() = PrivStart;
1467 m_aFuncSel.Max() = PrivEnd;
1469 m_nArgs = m_pFuncDesc->getSuppressedArgumentCount();
1471 OUString aFormula = m_xMEdit->get_text();
1472 sal_Int32 nArgPos = m_aFormulaHelper.GetArgStart( aFormula, PrivStart, 0);
1474 sal_uInt16 nPos = m_xParaWin->GetActiveLine();
1475 if (nPos >= m_aArguments.size())
1477 SAL_WARN("formula.ui","FormulaDlg_Impl::UpdateSelection - shot in foot: nPos " <<
1478 nPos << " >= m_aArguments.size() " << m_aArguments.size() <<
1479 " for aFormula '" << aFormula << "'");
1480 nPos = m_aArguments.size();
1481 if (nPos)
1482 --nPos;
1485 for (sal_uInt16 i = 0; i < nPos; i++)
1487 nArgPos += (m_aArguments[i].getLength() + 1);
1489 sal_Int32 nLength = (nPos < m_aArguments.size()) ? m_aArguments[nPos].getLength() : 0;
1491 m_pHelper->setSelection(nArgPos, nArgPos + nLength);
1492 m_xMEdit->select_region(nArgPos, nArgPos + nLength);
1493 UpdateOldSel();
1496 ::std::pair<RefButton*, RefEdit*> FormulaDlg_Impl::RefInputStartBefore(RefEdit* pEdit, RefButton* pButton)
1498 m_pTheRefEdit = pEdit;
1499 m_pTheRefButton = pButton;
1501 Selection aOrigSelection;
1502 if (m_pTheRefEdit)
1504 // grab selection before showing next widget in case the selection is blown away
1505 // by it appearing
1506 aOrigSelection = m_pTheRefEdit->GetSelection();
1509 // because its initially hidden, give it its optimal size so clicking the
1510 // refbutton has an initial size to work when retro-fitting this to .ui
1511 m_xEdRef->GetWidget()->set_size_request(m_xEdRef->GetWidget()->get_preferred_size().Width(), -1);
1512 m_xEdRef->GetWidget()->show();
1514 if ( m_pTheRefEdit )
1516 m_xEdRef->SetRefString(m_pTheRefEdit->GetText());
1517 m_xEdRef->SetSelection(aOrigSelection);
1518 m_xEdRef->GetWidget()->set_help_id(m_pTheRefEdit->GetWidget()->get_help_id());
1521 m_xRefBtn->GetWidget()->set_visible(pButton != nullptr);
1523 ::std::pair<RefButton*, RefEdit*> aPair;
1524 aPair.first = pButton ? m_xRefBtn.get() : nullptr;
1525 aPair.second = m_xEdRef.get();
1526 return aPair;
1529 void FormulaDlg_Impl::RefInputStartAfter()
1531 m_xRefBtn->SetEndImage();
1533 if (!m_pTheRefEdit)
1534 return;
1536 OUString aStr = m_aTitle2 + " " + m_xFtEditName->get_label() + "( ";
1538 if ( m_xParaWin->GetActiveLine() > 0 )
1539 aStr += "...; ";
1540 aStr += m_xParaWin->GetActiveArgName();
1541 if ( m_xParaWin->GetActiveLine() + 1 < m_nArgs )
1542 aStr += "; ...";
1543 aStr += " )";
1545 m_rDialog.set_title(m_rDialog.strip_mnemonic(aStr));
1548 void FormulaDlg_Impl::RefInputDoneAfter( bool bForced )
1550 m_xRefBtn->SetStartImage();
1551 if (!bForced && m_xRefBtn->GetWidget()->get_visible())
1552 return;
1554 m_xEdRef->GetWidget()->hide();
1555 m_xRefBtn->GetWidget()->hide();
1556 if ( m_pTheRefEdit )
1558 m_pTheRefEdit->SetRefString( m_xEdRef->GetText() );
1559 m_pTheRefEdit->GrabFocus();
1561 if ( m_pTheRefButton )
1562 m_pTheRefButton->SetStartImage();
1564 sal_uInt16 nPrivActiv = m_xParaWin->GetActiveLine();
1565 m_xParaWin->SetArgument( nPrivActiv, m_xEdRef->GetText() );
1566 ModifyHdl( *m_xParaWin );
1567 m_pTheRefEdit = nullptr;
1569 m_rDialog.set_title(m_aTitle1);
1572 RefEdit* FormulaDlg_Impl::GetCurrRefEdit()
1574 return m_xEdRef->GetWidget()->get_visible() ? m_xEdRef.get() : m_xParaWin->GetActiveEdit();
1577 void FormulaDlg_Impl::Update()
1579 FormEditData* pData = m_pHelper->getFormEditData();
1580 const OUString sExpression = m_xMEdit->get_text();
1581 m_aOldFormula.clear();
1582 UpdateTokenArray(sExpression);
1583 FormulaCursor();
1584 CalcStruct(sExpression);
1585 if (pData->GetMode() == FormulaDlgMode::Formula)
1586 m_xTabCtrl->set_current_page("function");
1587 else
1588 m_xTabCtrl->set_current_page("struct");
1589 m_xBtnMatrix->set_active(pData->GetMatrixFlag());
1592 void FormulaDlg_Impl::Update(const OUString& _sExp)
1594 CalcStruct(_sExp);
1595 FillDialog();
1596 FuncSelHdl(*m_xFuncPage);
1599 void FormulaDlg_Impl::SetMeText(const OUString& _sText)
1601 FormEditData* pData = m_pHelper->getFormEditData();
1602 m_xMEdit->set_text(_sText);
1603 auto aSelection = pData->GetSelection();
1604 m_xMEdit->select_region(aSelection.Min(), aSelection.Max());
1605 UpdateOldSel();
1608 FormulaDlgMode FormulaDlg_Impl::SetMeText( const OUString& _sText, sal_Int32 PrivStart, sal_Int32 PrivEnd, bool bMatrix, bool _bSelect, bool _bUpdate)
1610 FormulaDlgMode eMode = FormulaDlgMode::Formula;
1611 if (!m_bEditFlag)
1612 m_xMEdit->set_text(_sText);
1614 if ( _bSelect || !m_bEditFlag )
1615 m_xMEdit->select_region(PrivStart, PrivEnd);
1616 if ( _bUpdate )
1618 UpdateOldSel();
1619 int nStartPos, nEndPos;
1620 m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
1621 if (nStartPos > nEndPos)
1622 std::swap(nStartPos, nEndPos);
1623 m_pHelper->showReference(m_xMEdit->get_text().copy(nStartPos, nEndPos - nStartPos));
1624 eMode = FormulaDlgMode::Edit;
1626 m_xBtnMatrix->set_active( bMatrix );
1627 } // if ( _bUpdate )
1628 return eMode;
1631 bool FormulaDlg_Impl::CheckMatrix(OUString& aFormula)
1633 m_xMEdit->grab_focus();
1634 sal_Int32 nLen = aFormula.getLength();
1635 bool bMatrix = nLen > 3 // Matrix-Formula
1636 && aFormula[0] == '{'
1637 && aFormula[1] == '='
1638 && aFormula[nLen-1] == '}';
1639 if ( bMatrix )
1641 aFormula = aFormula.copy( 1, aFormula.getLength()-2 );
1642 m_xBtnMatrix->set_active( bMatrix );
1643 m_xBtnMatrix->set_sensitive(false);
1644 } // if ( bMatrix )
1646 m_xTabCtrl->set_current_page("struct");
1647 return bMatrix;
1650 IMPL_LINK_NOARG( FormulaDlg_Impl, StructSelHdl, StructPage&, void)
1652 m_bStructUpdate = false;
1653 if (m_xStructPage->IsVisible())
1654 m_xBtnForward->set_sensitive(false); //@New
1655 m_bStructUpdate = true;
1658 IMPL_LINK_NOARG( FormulaDlg_Impl, MatrixHdl, weld::Button&, void)
1660 m_bUserMatrixFlag = true;
1661 UpdateValues(true);
1664 IMPL_LINK_NOARG( FormulaDlg_Impl, FuncSelHdl, FuncPage&, void)
1666 if ( (m_xFuncPage->GetFunctionEntryCount() > 0)
1667 && (m_xFuncPage->GetFunction() != -1) )
1669 const IFunctionDescription* pDesc = m_xFuncPage->GetFuncDesc( m_xFuncPage->GetFunction() );
1671 if (pDesc != m_pFuncDesc)
1672 m_xBtnForward->set_sensitive(true); //new
1674 if (pDesc)
1676 pDesc->initArgumentInfo(); // full argument info is needed
1678 OUString aSig = pDesc->getSignature();
1679 m_xFtHeadLine->set_label( pDesc->getFunctionName() );
1680 m_xFtFuncName->set_label( aSig );
1681 m_xFtFuncDesc->set_label( pDesc->getDescription() );
1684 else
1686 m_xFtHeadLine->set_label( OUString() );
1687 m_xFtFuncName->set_label( OUString() );
1688 m_xFtFuncDesc->set_label( OUString() );
1692 void FormulaDlg_Impl::UpdateParaWin( const Selection& _rSelection, const OUString& _sRefStr)
1694 Selection theSel = _rSelection;
1695 m_xEdRef->GetWidget()->replace_selection(_sRefStr);
1696 theSel.Max() = theSel.Min() + _sRefStr.getLength();
1697 m_xEdRef->SetSelection( theSel );
1700 // Manual Update of the results' fields:
1702 sal_uInt16 nPrivActiv = m_xParaWin->GetActiveLine();
1703 m_xParaWin->SetArgument( nPrivActiv, m_xEdRef->GetText());
1704 m_xParaWin->UpdateParas();
1706 RefEdit* pEd = GetCurrRefEdit();
1707 if (pEd)
1708 pEd->SetSelection( theSel );
1711 bool FormulaDlg_Impl::UpdateParaWin(Selection& _rSelection)
1713 OUString aStrEd;
1714 RefEdit* pEd = GetCurrRefEdit();
1715 if (pEd && !m_pTheRefEdit)
1717 _rSelection = pEd->GetSelection();
1718 _rSelection.Justify();
1719 aStrEd = pEd->GetText();
1720 m_xEdRef->SetRefString(aStrEd);
1721 m_xEdRef->SetSelection( _rSelection );
1723 else
1725 _rSelection = m_xEdRef->GetSelection();
1726 _rSelection.Justify();
1727 aStrEd = m_xEdRef->GetText();
1729 return m_pTheRefEdit == nullptr;
1732 void FormulaDlg_Impl::SetEdSelection()
1734 RefEdit* pEd = GetCurrRefEdit()/*aScParaWin.GetActiveEdit()*/;
1735 if (pEd)
1737 Selection theSel = m_xEdRef->GetSelection();
1738 // Edit may have the focus -> call ModifyHdl in addition
1739 // to what's happening in GetFocus
1740 pEd->GetModifyHdl().Call(*pEd);
1741 pEd->GrabFocus();
1742 pEd->SetSelection(theSel);
1743 } // if ( pEd )
1746 FormulaModalDialog::FormulaModalDialog(weld::Window* pParent,
1747 IFunctionManager const * _pFunctionMgr,
1748 IControlReferenceHandler* _pDlg)
1749 : GenericDialogController(pParent, "formula/ui/formuladialog.ui", "FormulaDialog")
1750 , m_pImpl(new FormulaDlg_Impl(*m_xDialog, *m_xBuilder, false/*_bSupportFunctionResult*/,
1751 false/*_bSupportResult*/, false/*_bSupportMatrix*/,
1752 this, _pFunctionMgr, _pDlg))
1754 m_xDialog->set_title(m_pImpl->m_aTitle1);
1757 FormulaModalDialog::~FormulaModalDialog() { }
1759 void FormulaModalDialog::Update(const OUString& _sExp)
1761 m_pImpl->Update(_sExp);
1764 void FormulaModalDialog::SetMeText(const OUString& _sText)
1766 m_pImpl->SetMeText(_sText);
1769 void FormulaModalDialog::CheckMatrix(OUString& aFormula)
1771 m_pImpl->CheckMatrix(aFormula);
1774 void FormulaModalDialog::Update()
1776 m_pImpl->Update();
1779 ::std::pair<RefButton*, RefEdit*> FormulaModalDialog::RefInputStartBefore( RefEdit* pEdit, RefButton* pButton )
1781 return m_pImpl->RefInputStartBefore( pEdit, pButton );
1784 void FormulaModalDialog::RefInputStartAfter()
1786 m_pImpl->RefInputStartAfter();
1789 void FormulaModalDialog::RefInputDoneAfter()
1791 m_pImpl->RefInputDoneAfter( true/*bForced*/ );
1794 void FormulaModalDialog::StoreFormEditData(FormEditData* pData)
1796 m_pImpl->StoreFormEditData(pData);
1799 // Initialisation / General functions for Dialog
1800 FormulaDlg::FormulaDlg(SfxBindings* pB, SfxChildWindow* pCW,
1801 weld::Window* pParent,
1802 IFunctionManager const * _pFunctionMgr, IControlReferenceHandler* _pDlg)
1803 : SfxModelessDialogController( pB, pCW, pParent, "formula/ui/formuladialog.ui", "FormulaDialog")
1804 , m_pImpl(new FormulaDlg_Impl(*m_xDialog, *m_xBuilder, true/*_bSupportFunctionResult*/
1805 , true/*_bSupportResult*/
1806 , true/*_bSupportMatrix*/
1807 , this, _pFunctionMgr, _pDlg))
1809 m_xDialog->set_title(m_pImpl->m_aTitle1);
1812 FormulaDlg::~FormulaDlg()
1816 void FormulaDlg::Update(const OUString& _sExp)
1818 m_pImpl->Update(_sExp);
1821 void FormulaDlg::SetMeText(const OUString& _sText)
1823 m_pImpl->SetMeText(_sText);
1826 FormulaDlgMode FormulaDlg::SetMeText( const OUString& _sText, sal_Int32 PrivStart, sal_Int32 PrivEnd, bool bMatrix, bool _bSelect, bool _bUpdate)
1828 return m_pImpl->SetMeText( _sText, PrivStart, PrivEnd, bMatrix, _bSelect, _bUpdate);
1831 bool FormulaDlg::CheckMatrix(OUString& aFormula)
1833 return m_pImpl->CheckMatrix(aFormula);
1836 OUString FormulaDlg::GetMeText() const
1838 return m_pImpl->m_xMEdit->get_text();
1841 void FormulaDlg::Update()
1843 m_pImpl->Update();
1846 void FormulaDlg::DoEnter()
1848 m_pImpl->DoEnter(false);
1851 ::std::pair<RefButton*, RefEdit*> FormulaDlg::RefInputStartBefore( RefEdit* pEdit, RefButton* pButton )
1853 return m_pImpl->RefInputStartBefore( pEdit, pButton );
1856 void FormulaDlg::RefInputStartAfter()
1858 m_pImpl->RefInputStartAfter();
1861 void FormulaDlg::RefInputDoneAfter( bool bForced )
1863 m_pImpl->RefInputDoneAfter( bForced );
1866 void FormulaDlg::disableOk()
1868 m_pImpl->m_xBtnEnd->set_sensitive(false);
1871 void FormulaDlg::StoreFormEditData(FormEditData* pData)
1873 m_pImpl->StoreFormEditData(pData);
1876 const IFunctionDescription* FormulaDlg::getCurrentFunctionDescription() const
1878 SAL_WARN_IF( (m_pImpl->m_pFuncDesc && m_pImpl->m_pFuncDesc->getSuppressedArgumentCount() != m_pImpl->m_nArgs),
1879 "formula.ui", "FormulaDlg::getCurrentFunctionDescription: getSuppressedArgumentCount " <<
1880 m_pImpl->m_pFuncDesc->getSuppressedArgumentCount() << " != m_nArgs " << m_pImpl->m_nArgs << " for " <<
1881 m_pImpl->m_pFuncDesc->getFunctionName());
1882 return m_pImpl->m_pFuncDesc;
1885 void FormulaDlg::UpdateParaWin( const Selection& _rSelection, const OUString& _sRefStr)
1887 m_pImpl->UpdateParaWin( _rSelection, _sRefStr);
1890 bool FormulaDlg::UpdateParaWin(Selection& _rSelection)
1892 return m_pImpl->UpdateParaWin(_rSelection);
1895 RefEdit* FormulaDlg::GetActiveEdit()
1897 return m_pImpl->m_xParaWin->GetActiveEdit();
1900 const FormulaHelper& FormulaDlg::GetFormulaHelper() const
1902 return m_pImpl->GetFormulaHelper();
1905 void FormulaDlg::SetEdSelection()
1907 m_pImpl->SetEdSelection();
1910 void FormEditData::SaveValues()
1912 Reset();
1915 void FormEditData::Reset()
1917 nMode = FormulaDlgMode::Formula;
1918 nFStart = 0;
1919 nOffset = 0;
1920 bMatrix = false;
1921 aSelection.Min() = 0;
1922 aSelection.Max() = 0;
1923 aUndoStr.clear();
1926 FormEditData& FormEditData::operator=( const FormEditData& r )
1928 nMode = r.nMode;
1929 nFStart = r.nFStart;
1930 nOffset = r.nOffset;
1931 aUndoStr = r.aUndoStr;
1932 bMatrix = r.bMatrix ;
1933 aSelection = r.aSelection;
1934 return *this;
1937 FormEditData::FormEditData()
1939 Reset();
1942 FormEditData::~FormEditData()
1946 FormEditData::FormEditData( const FormEditData& r )
1948 *this = r;
1952 } // formula
1955 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */