xref: /core/formula/source/ui/dlg/formula.cxx (revision 12215925)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <memory>
21 #include <sfx2/viewfrm.hxx>
22 #include <vcl/svapp.hxx>
23 #include <vcl/weld.hxx>
24 
25 #include <sal/log.hxx>
26 
27 #include <unotools/charclass.hxx>
28 #include <comphelper/diagnose_ex.hxx>
29 
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>
49 
50 // For tab page
51 #define TOKEN_OPEN  0
52 #define TOKEN_CLOSE 1
53 namespace formula
54 {
55 
56 using namespace ::com::sun::star;
57 
58 class FormulaDlg_Impl
59 {
60 public:
61     ::std::pair<RefButton*, RefEdit*>
62         RefInputStartBefore( RefEdit* pEdit, RefButton* pButton );
63     void            RefInputStartAfter();
64     void            RefInputDoneAfter( bool bForced );
65     bool            CalcValue( const OUString& rStrExp, OUString& rStrResult, bool bForceMatrixFormula = false );
66     void            CalcStruct( const OUString& rStrExp, bool bForceRecalcStruct = false );
67     void            UpdateValues( bool bForceRecalcStruct = false );
68     void            DeleteArgs();
69     sal_Int32       GetFunctionPos(sal_Int32 nPos);
70     void            ClearAllParas();
71 
72     void            MakeTree(StructPage* _pTree, weld::TreeIter* pParent, const FormulaToken* pFuncToken,
73                              const FormulaToken* _pToken, tools::Long Count);
74     void            fillTree(StructPage* _pTree);
75     void            UpdateTokenArray( const OUString& rStrExp);
76     OUString        RepairFormula(const OUString& aFormula);
77     void            FillDialog(bool bFlag = true);
78     bool            EditNextFunc( bool bForward, sal_Int32 nFStart = NOT_FOUND );
79     void            EditThisFunc(sal_Int32 nFStart);
80 
81     OUString        GetPrevFuncExpression( bool bStartFromEnd );
82 
83     void            StoreFormEditData(FormEditData* pEditData);
84 
85     void            Update();
86     void            Update(const OUString& _sExp);
87 
88     void            SaveArg( sal_uInt16 nEd );
89     void            UpdateSelection();
90     void            DoEnter( bool bOk );
91     void            FillListboxes();
92     void            FillControls( bool &rbNext, bool &rbPrev);
93 
94     FormulaDlgMode  SetMeText( const OUString& _sText, sal_Int32 PrivStart, sal_Int32 PrivEnd, bool bMatrix, bool _bSelect, bool _bUpdate);
95     void            SetMeText(const OUString& _sText);
96     bool            CheckMatrix(OUString& aFormula /*IN/OUT*/);
97 
98     void            SetEdSelection();
99 
100     bool            UpdateParaWin(Selection& _rSelection);
101     void            UpdateParaWin( const Selection& _rSelection, const OUString& _sRefStr);
102 
103     void            SetData( sal_Int32 nFStart, sal_Int32 nNextFStart, sal_Int32 nNextFEnd, sal_Int32& PrivStart, sal_Int32& PrivEnd);
104 
105     RefEdit*    GetCurrRefEdit();
106 
GetFormulaHelper() const107     const FormulaHelper& GetFormulaHelper() const { return m_aFormulaHelper;}
108     void InitFormulaOpCodeMapper();
109 
110     void UpdateOldSel();
111     void FormulaCursor();
112 
113     DECL_LINK( ModifyHdl, ParaWin&, void );
114     DECL_LINK( FxHdl, ParaWin&, void );
115 
116     DECL_LINK( MatrixHdl, weld::Toggleable&, void );
117     DECL_LINK( FormulaHdl, weld::TextView&, void);
118     DECL_LINK( FormulaCursorHdl, weld::TextView&, void );
119     DECL_LINK( BtnHdl, weld::Button&, void );
120     DECL_LINK( DblClkHdl, FuncPage&, void );
121     DECL_LINK( FuncSelHdl, FuncPage&, void );
122     DECL_LINK( StructSelHdl, StructPage&, void );
123 public:
124     mutable uno::Reference< sheet::XFormulaOpCodeMapper>    m_xOpCodeMapper;
125     uno::Sequence< sheet::FormulaToken >                    m_aTokenList;
126     ::std::unique_ptr<FormulaTokenArray>                    m_pTokenArray;
127     ::std::optional<FormulaTokenArrayPlainIterator>         m_oTokenArrayIterator;
128     mutable uno::Sequence< sheet::FormulaOpCodeMapEntry >   m_aSpecialOpCodes;
129     mutable uno::Sequence< sheet::FormulaToken >            m_aSeparatorsOpCodes;
130     mutable uno::Sequence< sheet::FormulaOpCodeMapEntry >   m_aFunctionOpCodes;
131     mutable const sheet::FormulaOpCodeMapEntry*             m_pFunctionOpCodesEnd;
132     ::std::map<const FormulaToken*, sheet::FormulaToken>    m_aTokenMap;
133     IFormulaEditorHelper*                                   m_pHelper;
134     weld::Dialog&           m_rDialog;
135 
136     OUString                m_aOldFormula;
137     bool                    m_bStructUpdate;
138     bool                    m_bUserMatrixFlag;
139 
140     const OUString          m_aTitle1;
141     const OUString          m_aTitle2;
142     FormulaHelper           m_aFormulaHelper;
143 
144     OUString                m_aEditHelpId;
145 
146     OUString                 m_aOldHelp;
147     bool                    m_bMakingTree;  // in method of constructing tree
148 
149     bool                    m_bEditFlag;
150     const IFunctionDescription* m_pFuncDesc;
151     sal_Int32               m_nArgs;
152     ::std::vector< OUString > m_aArguments;
153     Selection               m_aFuncSel;
154 
155     sal_Int32               m_nFuncExpStart;     ///< current formula position for treeview results
156 
157     int m_nSelectionStart;
158     int m_nSelectionEnd;
159 
160     RefEdit* m_pTheRefEdit;
161     RefButton* m_pTheRefButton;
162 
163     std::unique_ptr<weld::Notebook> m_xTabCtrl;
164     std::unique_ptr<weld::Container> m_xParaWinBox;
165     std::unique_ptr<ParaWin> m_xParaWin;
166     std::unique_ptr<weld::Label> m_xFtHeadLine;
167     std::unique_ptr<weld::Label> m_xFtFuncName;
168     std::unique_ptr<weld::Label> m_xFtFuncDesc;
169 
170     std::unique_ptr<weld::Label> m_xFtEditName;
171 
172     std::unique_ptr<weld::Label> m_xFtResult;
173     std::unique_ptr<weld::Entry> m_xWndResult;
174 
175     std::unique_ptr<weld::Label> m_xFtFormula;
176     std::unique_ptr<weld::TextView> m_xMEdit;
177 
178     std::unique_ptr<weld::CheckButton> m_xBtnMatrix;
179     std::unique_ptr<weld::Button> m_xBtnCancel;
180 
181     std::unique_ptr<weld::Button> m_xBtnBackward;
182     std::unique_ptr<weld::Button> m_xBtnForward;
183     std::unique_ptr<weld::Button> m_xBtnEnd;
184 
185     std::unique_ptr<weld::Label> m_xFtFormResult;
186     std::unique_ptr<weld::Entry> m_xWndFormResult;
187 
188     std::unique_ptr<RefEdit> m_xEdRef;
189     std::unique_ptr<RefButton> m_xRefBtn;
190 
191     std::unique_ptr<FuncPage> m_xFuncPage;
192     std::unique_ptr<StructPage> m_xStructPage;
193 
194     FormulaDlg_Impl(weld::Dialog& rDialog,
195                     weld::Builder& rBuilder,
196                     bool _bSupportFunctionResult,
197                     bool _bSupportResult,
198                     bool _bSupportMatrix,
199                     IFormulaEditorHelper* _pHelper,
200                     const IFunctionManager* _pFunctionMgr,
201                     IControlReferenceHandler* _pDlg);
202     ~FormulaDlg_Impl();
203 };
204 
FormulaDlg_Impl(weld::Dialog & rDialog,weld::Builder & rBuilder,bool _bSupportFunctionResult,bool _bSupportResult,bool _bSupportMatrix,IFormulaEditorHelper * _pHelper,const IFunctionManager * _pFunctionMgr,IControlReferenceHandler * _pDlg)205 FormulaDlg_Impl::FormulaDlg_Impl(weld::Dialog& rDialog,
206                                  weld::Builder& rBuilder,
207                                  bool _bSupportFunctionResult,
208                                  bool _bSupportResult,
209                                  bool _bSupportMatrix,
210                                  IFormulaEditorHelper* _pHelper,
211                                  const IFunctionManager* _pFunctionMgr,
212                                  IControlReferenceHandler* _pDlg)
213     : m_pFunctionOpCodesEnd(nullptr)
214     , m_pHelper(_pHelper)
215     , m_rDialog(rDialog)
216     , m_bUserMatrixFlag(false)
217     , m_aTitle1( ForResId( STR_TITLE1 ) )
218     , m_aTitle2( ForResId( STR_TITLE2 ) )
219     , m_aFormulaHelper(_pFunctionMgr)
220     , m_bMakingTree(false)
221     , m_pFuncDesc(nullptr)
222     , m_nArgs(0)
223     , m_nFuncExpStart(0)
224     , m_nSelectionStart(-1)
225     , m_nSelectionEnd(-1)
226     , m_pTheRefEdit(nullptr)
227     , m_pTheRefButton(nullptr)
228     , m_xTabCtrl(rBuilder.weld_notebook(u"tabcontrol"_ustr))
229     , m_xParaWinBox(rBuilder.weld_container(u"BOX"_ustr))
230     , m_xFtHeadLine(rBuilder.weld_label(u"headline"_ustr))
231     , m_xFtFuncName(rBuilder.weld_label(u"funcname"_ustr))
232     , m_xFtFuncDesc(rBuilder.weld_label(u"funcdesc"_ustr))
233     , m_xFtEditName(rBuilder.weld_label(u"editname"_ustr))
234     , m_xFtResult(rBuilder.weld_label(u"label2"_ustr))
235     , m_xWndResult(rBuilder.weld_entry(u"result"_ustr))
236     , m_xFtFormula(rBuilder.weld_label(u"formula"_ustr))
237     , m_xMEdit(rBuilder.weld_text_view(u"ed_formula"_ustr))
238     , m_xBtnMatrix(rBuilder.weld_check_button(u"array"_ustr))
239     , m_xBtnCancel(rBuilder.weld_button(u"cancel"_ustr))
240     , m_xBtnBackward(rBuilder.weld_button(u"back"_ustr))
241     , m_xBtnForward(rBuilder.weld_button(u"next"_ustr))
242     , m_xBtnEnd(rBuilder.weld_button(u"ok"_ustr))
243     , m_xFtFormResult(rBuilder.weld_label(u"label1"_ustr))
244     , m_xWndFormResult(rBuilder.weld_entry(u"formula_result"_ustr))
245     , m_xEdRef(new RefEdit(rBuilder.weld_entry(u"ED_REF"_ustr)))
246     , m_xRefBtn(new RefButton(rBuilder.weld_button(u"RB_REF"_ustr)))
247 {
248     auto nWidth = m_xMEdit->get_approximate_digit_width() * 62;
249 
250     //Space for two lines of text
251     m_xFtHeadLine->set_label(u"X\nX\n"_ustr);
252     auto nHeight = m_xFtHeadLine->get_preferred_size().Height();
253     m_xFtHeadLine->set_size_request(nWidth, nHeight);
254     m_xFtHeadLine->set_label(u""_ustr);
255 
256     m_xFtFuncName->set_label(u"X\nX\n"_ustr);
257     nHeight = m_xFtFuncName->get_preferred_size().Height();
258     m_xFtFuncName->set_size_request(nWidth, nHeight);
259     m_xFtFuncDesc->set_size_request(nWidth, nHeight);
260     m_xFtFuncName->set_label(u""_ustr);
261 
262     m_xMEdit->set_size_request(nWidth,
263                                m_xMEdit->get_height_rows(5));
264 
265     m_xEdRef->SetReferences(_pDlg, m_xFtEditName.get());
266     m_xRefBtn->SetReferences(_pDlg, m_xEdRef.get());
267 
268     m_xParaWin.reset(new ParaWin(m_xParaWinBox.get(), _pDlg));
269     m_xParaWin->Show();
270     m_xParaWinBox->hide();
271     m_xFtEditName->hide();
272     m_xEdRef->GetWidget()->hide();
273     m_xRefBtn->GetWidget()->hide();
274 
275     m_xMEdit->set_accessible_name(m_xFtFormula->get_label());
276 
277     m_aEditHelpId = m_xMEdit->get_help_id();
278 
279     m_bEditFlag =false;
280     m_bStructUpdate =true;
281     m_xParaWin->SetArgModifiedHdl( LINK( this, FormulaDlg_Impl, ModifyHdl ) );
282     m_xParaWin->SetFxHdl( LINK( this, FormulaDlg_Impl, FxHdl ) );
283 
284     m_xFuncPage.reset(new FuncPage(m_xTabCtrl->get_page(u"functiontab"_ustr), _pFunctionMgr));
285     m_xStructPage.reset(new StructPage(m_xTabCtrl->get_page(u"structtab"_ustr)));
286     m_xTabCtrl->set_current_page(u"functiontab"_ustr);
287 
288     m_aOldHelp = m_rDialog.get_help_id();                // HelpId from resource always for "Page 1"
289 
290     m_xFtResult->set_visible( _bSupportResult );
291     m_xWndResult->set_visible( _bSupportResult );
292 
293     m_xFtFormResult->set_visible( _bSupportFunctionResult );
294     m_xWndFormResult->set_visible( _bSupportFunctionResult );
295 
296     if ( _bSupportMatrix )
297         m_xBtnMatrix->connect_toggled( LINK( this, FormulaDlg_Impl, MatrixHdl ) );
298     else
299         m_xBtnMatrix->hide();
300 
301     m_xBtnCancel->connect_clicked( LINK( this, FormulaDlg_Impl, BtnHdl ) );
302     m_xBtnEnd->connect_clicked( LINK( this, FormulaDlg_Impl, BtnHdl ) );
303     m_xBtnForward->connect_clicked( LINK( this, FormulaDlg_Impl, BtnHdl ) );
304     m_xBtnBackward->connect_clicked( LINK( this, FormulaDlg_Impl, BtnHdl ) );
305 
306     m_xFuncPage->SetDoubleClickHdl( LINK( this, FormulaDlg_Impl, DblClkHdl ) );
307     m_xFuncPage->SetSelectHdl( LINK( this, FormulaDlg_Impl, FuncSelHdl) );
308     m_xStructPage->SetSelectionHdl( LINK( this, FormulaDlg_Impl, StructSelHdl ) );
309     m_xMEdit->connect_changed( LINK( this, FormulaDlg_Impl, FormulaHdl ) );
310     m_xMEdit->connect_cursor_position( LINK( this, FormulaDlg_Impl, FormulaCursorHdl ) );
311 
312     vcl::Font aFntLight = m_xFtFormula->get_font();
313     vcl::Font aFntBold = aFntLight;
314     aFntBold.SetWeight( WEIGHT_BOLD );
315 
316     m_xParaWin->SetArgumentFonts( aFntBold, aFntLight);
317 }
318 
~FormulaDlg_Impl()319 FormulaDlg_Impl::~FormulaDlg_Impl()
320 {
321     m_xTabCtrl->remove_page(u"functiontab"_ustr);
322     m_xTabCtrl->remove_page(u"structtab"_ustr);
323 
324     DeleteArgs();
325 }
326 
StoreFormEditData(FormEditData * pData)327 void FormulaDlg_Impl::StoreFormEditData(FormEditData* pData)
328 {
329     if (!pData) // it won't be destroyed via Close
330         return;
331 
332     int nStartPos, nEndPos;
333     m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
334     if (nStartPos > nEndPos)
335         std::swap(nStartPos, nEndPos);
336 
337     pData->SetFStart(nStartPos);
338     pData->SetSelection(Selection(nStartPos, nEndPos));
339 
340     if (m_xTabCtrl->get_current_page_ident() == "functiontab")
341         pData->SetMode( FormulaDlgMode::Formula );
342     else
343         pData->SetMode( FormulaDlgMode::Edit );
344     pData->SetUndoStr(m_xMEdit->get_text());
345     pData->SetMatrixFlag(m_xBtnMatrix->get_active());
346 }
347 
InitFormulaOpCodeMapper()348 void FormulaDlg_Impl::InitFormulaOpCodeMapper()
349 {
350     if ( m_xOpCodeMapper.is() )
351         return;
352 
353     m_xOpCodeMapper = m_pHelper->getFormulaOpCodeMapper();
354     m_aFunctionOpCodes = m_xOpCodeMapper->getAvailableMappings( sheet::FormulaLanguage::ODFF, sheet::FormulaMapGroup::FUNCTIONS);
355     m_pFunctionOpCodesEnd = m_aFunctionOpCodes.getConstArray() + m_aFunctionOpCodes.getLength();
356 
357     // 0:TOKEN_OPEN, 1:TOKEN_CLOSE, 2:TOKEN_SEP
358     uno::Sequence< OUString > aArgs { u"("_ustr, u")"_ustr, u";"_ustr };
359     m_aSeparatorsOpCodes = m_xOpCodeMapper->getMappings( aArgs, sheet::FormulaLanguage::ODFF);
360 
361     m_aSpecialOpCodes = m_xOpCodeMapper->getAvailableMappings( sheet::FormulaLanguage::ODFF, sheet::FormulaMapGroup::SPECIAL);
362 }
363 
DeleteArgs()364 void FormulaDlg_Impl::DeleteArgs()
365 {
366     ::std::vector< OUString>().swap(m_aArguments);
367     m_nArgs = 0;
368 }
369 
GetFunctionPos(sal_Int32 nPos)370 sal_Int32 FormulaDlg_Impl::GetFunctionPos(sal_Int32 nPos)
371 {
372     if ( !m_aTokenList.hasElements() )
373         return SAL_MAX_INT32;
374 
375     const sal_Unicode sep = m_pHelper->getFunctionManager()->getSingleToken(IFunctionManager::eSep);
376 
377     sal_Int32 nFuncPos = SAL_MAX_INT32;
378     OUString  aFormString = m_aFormulaHelper.GetCharClass().uppercase(m_xMEdit->get_text());
379 
380     const uno::Reference< sheet::XFormulaParser > xParser(m_pHelper->getFormulaParser());
381     const table::CellAddress aRefPos(m_pHelper->getReferencePosition());
382 
383     const sheet::FormulaToken* pIter = m_aTokenList.getConstArray();
384     const sheet::FormulaToken* pEnd = pIter + m_aTokenList.getLength();
385     try
386     {
387         bool  bFlag = false;
388         sal_Int32 nTokPos = 1;
389         sal_Int32 nOldTokPos = 1;
390         sal_Int32 nPrevFuncPos = 1;
391         short nBracketCount = 0;
392         const sal_Int32 nOpPush = m_aSpecialOpCodes[sheet::FormulaMapGroupSpecialOffset::PUSH].Token.OpCode;
393         const sal_Int32 nOpSpaces = m_aSpecialOpCodes[sheet::FormulaMapGroupSpecialOffset::SPACES].Token.OpCode;
394         const sal_Int32 nOpWhitespace = m_aSpecialOpCodes[sheet::FormulaMapGroupSpecialOffset::WHITESPACE].Token.OpCode;
395         while ( pIter != pEnd )
396         {
397             const sal_Int32 eOp = pIter->OpCode;
398             uno::Sequence<sheet::FormulaToken> aArgs { *pIter };
399             const OUString aString = xParser->printFormula( aArgs, aRefPos);
400             const sheet::FormulaToken* pNextToken = pIter + 1;
401 
402             if ( !m_bUserMatrixFlag && FormulaCompiler::IsMatrixFunction(static_cast<OpCode>(eOp)) )
403             {
404                 m_xBtnMatrix->set_active(true);
405             }
406 
407             if (eOp == nOpPush || eOp == nOpSpaces || eOp == nOpWhitespace)
408             {
409                 const sal_Int32 n1 = nTokPos < 0 ? -1 : aFormString.indexOf( sep, nTokPos);
410                 const sal_Int32 n2 = nTokPos < 0 ? -1 : aFormString.indexOf( ')', nTokPos);
411                 sal_Int32 nXXX = nTokPos;
412                 if ( n1 < n2 && n1 != -1 )
413                 {
414                     nTokPos = n1;
415                 }
416                 else
417                 {
418                     nTokPos = n2;
419                 }
420                 if ( pNextToken != pEnd )
421                 {
422                     aArgs.getArray()[0] = *pNextToken;
423                     const OUString a2String = xParser->printFormula( aArgs, aRefPos);
424                     const sal_Int32 n3 = nXXX < 0 ? -1 : aFormString.indexOf( a2String, nXXX);
425                     if (n3 < nTokPos && n3 != -1)
426                         nTokPos = n3;
427                 }
428             }
429             else
430             {
431                 nTokPos = nTokPos + aString.getLength();
432             }
433 
434             if ( eOp == m_aSeparatorsOpCodes[TOKEN_OPEN].OpCode )
435             {
436                 nBracketCount++;
437                 bFlag = true;
438             }
439             else if ( eOp == m_aSeparatorsOpCodes[TOKEN_CLOSE].OpCode )
440             {
441                 nBracketCount--;
442                 bFlag = false;
443                 nFuncPos = nPrevFuncPos;
444             }
445             bool bIsFunction = std::any_of( m_aFunctionOpCodes.getConstArray(),
446                     m_pFunctionOpCodesEnd,
447                     [&eOp](const sheet::FormulaOpCodeMapEntry& aEntry) { return aEntry.Token.OpCode == eOp; });
448 
449             if ( bIsFunction && nOpSpaces != eOp && nOpWhitespace != eOp )
450             {
451                 nPrevFuncPos = nFuncPos;
452                 nFuncPos = nOldTokPos;
453             }
454 
455             if ( nOldTokPos <= nPos && nPos < nTokPos )
456             {
457                 if ( !bIsFunction )
458                 {
459                     if ( nBracketCount < 1 )
460                     {
461                         nFuncPos = m_xMEdit->get_text().getLength();
462                     }
463                     else if ( !bFlag )
464                     {
465                         nFuncPos = nPrevFuncPos;
466                     }
467                 }
468                 break;
469             }
470 
471             pIter = pNextToken;
472             nOldTokPos = nTokPos;
473         } // while ( pIter != pEnd )
474     }
475     catch ( const uno::Exception& )
476     {
477         TOOLS_WARN_EXCEPTION("formula.ui", "FormulaDlg_Impl::GetFunctionPos");
478     }
479 
480     return nFuncPos;
481 }
482 
CalcValue(const OUString & rStrExp,OUString & rStrResult,bool bForceMatrixFormula)483 bool FormulaDlg_Impl::CalcValue( const OUString& rStrExp, OUString& rStrResult, bool bForceMatrixFormula )
484 {
485     bool bResult = true;
486 
487     if ( !rStrExp.isEmpty() )
488     {
489         // Only calculate the value when there isn't any more keyboard input:
490 
491         // Make this debuggable by assigning to a variable that can be changed
492         // from within the debugger.
493         bool bInput = Application::AnyInput( VclInputFlags::KEYBOARD );
494         if ( !bInput )
495         {
496             bResult = m_pHelper->calculateValue( rStrExp, rStrResult, bForceMatrixFormula || m_xBtnMatrix->get_active());
497         }
498         else
499             bResult = false;
500     }
501 
502     return bResult;
503 }
504 
UpdateValues(bool bForceRecalcStruct)505 void FormulaDlg_Impl::UpdateValues( bool bForceRecalcStruct )
506 {
507     // Take a force-array context into account. RPN creation propagated those
508     // to tokens that are ref-counted so also available in the token array.
509     bool bForceArray = false;
510     // Only necessary if it's not a matrix formula anyway and matrix evaluation
511     // is supported, i.e. the button is visible.
512     if (m_xBtnMatrix->get_visible() && !m_xBtnMatrix->get_active())
513     {
514         std::unique_ptr<FormulaCompiler> pCompiler(m_pHelper->createCompiler(*m_pTokenArray));
515         // In the case of the reportdesign dialog there is no currently active
516         // OpCode symbol mapping that could be used to create strings from
517         // tokens, it's all dreaded API mapping. However, in that case there's
518         // no array/matrix support anyway, but ensure checking.
519         if (pCompiler->GetCurrentOpCodeMap())
520         {
521             const sal_Int32 nPos = m_aFuncSel.Min();
522             assert( 0 <= nPos && nPos < m_pHelper->getCurrentFormula().getLength());
523             OUStringBuffer aBuf;
524             const FormulaToken* pToken = nullptr;
525             for (pToken = m_oTokenArrayIterator->First(); pToken; pToken = m_oTokenArrayIterator->Next())
526             {
527                 pCompiler->CreateStringFromToken( aBuf, pToken);
528                 if (nPos < aBuf.getLength())
529                     break;
530             }
531             if (pToken && nPos < aBuf.getLength())
532                 bForceArray = pToken->IsInForceArray();
533         }
534     }
535 
536     OUString aStrResult;
537     if (m_pFuncDesc && CalcValue( m_pFuncDesc->getFormula( m_aArguments), aStrResult, bForceArray))
538         m_xWndResult->set_text( aStrResult );
539 
540     if (m_bMakingTree)
541         return;
542 
543     aStrResult.clear();
544     if ( CalcValue( m_pHelper->getCurrentFormula(), aStrResult ) )
545         m_xWndFormResult->set_text( aStrResult );
546     else
547     {
548         aStrResult.clear();
549         m_xWndFormResult->set_text( aStrResult );
550     }
551     CalcStruct( m_xMEdit->get_text(), bForceRecalcStruct);
552 }
553 
CalcStruct(const OUString & rStrExp,bool bForceRecalcStruct)554 void FormulaDlg_Impl::CalcStruct( const OUString& rStrExp, bool bForceRecalcStruct )
555 {
556     sal_Int32 nLength = rStrExp.getLength();
557 
558     if ( !(!rStrExp.isEmpty() && (bForceRecalcStruct || m_aOldFormula != rStrExp) && m_bStructUpdate))
559         return;
560 
561     m_xStructPage->ClearStruct();
562 
563     OUString aString = rStrExp;
564     if (rStrExp[nLength-1] == '(')
565     {
566         aString = aString.copy( 0, nLength-1);
567     }
568 
569     aString = aString.replaceAll( "\n", "");
570     OUString aStrResult;
571 
572     if ( CalcValue( aString, aStrResult ) )
573         m_xWndFormResult->set_text(aStrResult);
574 
575     UpdateTokenArray(aString);
576     fillTree(m_xStructPage.get());
577 
578     m_aOldFormula = rStrExp;
579     if (rStrExp[nLength-1] == '(')
580         UpdateTokenArray(rStrExp);
581 }
582 
MakeTree(StructPage * _pTree,weld::TreeIter * pParent,const FormulaToken * pFuncToken,const FormulaToken * _pToken,tools::Long Count)583 void FormulaDlg_Impl::MakeTree(StructPage* _pTree, weld::TreeIter* pParent, const FormulaToken* pFuncToken,
584                                const FormulaToken* _pToken, tools::Long Count)
585 {
586     if ( _pToken == nullptr || Count <= 0 )
587         return;
588 
589     tools::Long nParas = _pToken->GetParamCount();
590     OpCode eOp = _pToken->GetOpCode();
591 
592     // #i101512# for output, the original token is needed
593     const FormulaToken* pOrigToken = (_pToken->GetType() == svFAP) ? _pToken->GetFAPOrigToken() : _pToken;
594     ::std::map<const FormulaToken*, sheet::FormulaToken>::const_iterator itr = m_aTokenMap.find(pOrigToken);
595     if (itr == m_aTokenMap.end())
596         return;
597 
598     uno::Sequence<sheet::FormulaToken> aArgs { itr->second };
599     try
600     {
601         const table::CellAddress aRefPos(m_pHelper->getReferencePosition());
602         const OUString aResult = m_pHelper->getFormulaParser()->printFormula( aArgs, aRefPos);
603 
604         if ( nParas > 0 || (nParas == 0 && _pToken->IsFunction()) )
605         {
606             std::unique_ptr<weld::TreeIter> xEntry;
607             weld::TreeIter* pEntry;
608 
609             bool bCalcSubformula = false;
610             OUString aTest = _pTree->GetEntryText(pParent);
611 
612             if (aTest == aResult && (eOp == ocAdd || eOp == ocMul || eOp == ocAmpersand))
613             {
614                 pEntry = pParent;
615             }
616             else
617             {
618                 xEntry = m_xStructPage->GetTlbStruct().make_iterator();
619 
620                 if (eOp == ocBad)
621                 {
622                     _pTree->InsertEntry(aResult, pParent, STRUCT_ERROR, 0, _pToken, *xEntry);
623                 }
624                 else if (!((SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP) ||
625                             (SC_OPCODE_START_UN_OP <= eOp && eOp < SC_OPCODE_STOP_UN_OP)))
626                 {
627                     // Not a binary or unary operator.
628                     bCalcSubformula = true;
629                     _pTree->InsertEntry(aResult, pParent, STRUCT_FOLDER, 0, _pToken, *xEntry);
630                 }
631                 else
632                 {
633                     /* TODO: question remains, why not sub calculate operators? */
634                     _pTree->InsertEntry(aResult, pParent, STRUCT_FOLDER, 0, _pToken, *xEntry);
635                 }
636 
637                 pEntry = xEntry.get();
638             }
639 
640             MakeTree(_pTree, pEntry, _pToken, m_oTokenArrayIterator->PrevRPN(), nParas);
641 
642             if (bCalcSubformula)
643             {
644                 OUString aFormula;
645 
646                 if (!m_bMakingTree)
647                 {
648                     // gets the last subformula result
649                     m_bMakingTree = true;
650                     aFormula = GetPrevFuncExpression( true);
651                 }
652                 else
653                 {
654                     // gets subsequent subformula results (from the back)
655                     aFormula = GetPrevFuncExpression( false);
656                 }
657 
658                 OUString aStr;
659                 if (CalcValue( aFormula, aStr, _pToken->IsInForceArray()))
660                     m_xWndResult->set_text( aStr );
661                 aStr = m_xWndResult->get_text();
662                 m_xStructPage->GetTlbStruct().set_text(*pEntry, aResult + " = " + aStr);
663             }
664 
665             --Count;
666             m_oTokenArrayIterator->NextRPN();   /* TODO: what's this to be? ThisRPN()? */
667             MakeTree( _pTree, pParent, _pToken, m_oTokenArrayIterator->PrevRPN(), Count);
668         }
669         else
670         {
671             std::unique_ptr<weld::TreeIter> xEntry(m_xStructPage->GetTlbStruct().make_iterator());
672             if (eOp == ocBad)
673             {
674                 _pTree->InsertEntry( aResult, pParent, STRUCT_ERROR, 0, _pToken, *xEntry);
675             }
676             else if (eOp == ocPush)
677             {
678                 // Interpret range reference in matrix context to resolve
679                 // as array elements. Depending on parameter classification
680                 // a scalar value (non-array context) is calculated first.
681                 OUString aUnforcedResult;
682                 bool bForceMatrix = (!m_xBtnMatrix->get_active() &&
683                         (_pToken->GetType() == svDoubleRef || _pToken->GetType() == svExternalDoubleRef));
684                 if (bForceMatrix && pFuncToken)
685                 {
686                     formula::ParamClass eParamClass = ParamClass::Reference;
687                     if (pFuncToken->IsInForceArray())
688                         eParamClass = ParamClass::ForceArray;
689                     else
690                     {
691                         std::shared_ptr<FormulaCompiler> pCompiler = m_pHelper->getCompiler();
692                         if (pCompiler)
693                             eParamClass = pCompiler->GetForceArrayParameter( pFuncToken, Count - 1);
694                     }
695                     switch (eParamClass)
696                     {
697                         case ParamClass::Unknown:
698                         case ParamClass::Bounds:
699                         case ParamClass::Value:
700                             if (CalcValue( "=" + aResult, aUnforcedResult, false) && aUnforcedResult != aResult)
701                                 aUnforcedResult += "  ";
702                             else
703                                 aUnforcedResult.clear();
704                         break;
705                         case ParamClass::Reference:
706                         case ParamClass::ReferenceOrRefArray:
707                         case ParamClass::Array:
708                         case ParamClass::ForceArray:
709                         case ParamClass::ReferenceOrForceArray:
710                         case ParamClass::SuppressedReferenceOrForceArray:
711                         case ParamClass::ForceArrayReturn:
712                             ;   // nothing, only as array/matrix
713                         // no default to get compiler warning
714                     }
715                 }
716                 OUString aCellResult;
717                 if (CalcValue( "=" + aResult, aCellResult, bForceMatrix) && aCellResult != aResult)
718                 {
719                     // Cell is a formula, print subformula.
720                     // With scalar values prints "A1:A3 = 2 {1;2;3}"
721                     _pTree->InsertEntry( aResult + " = " + aUnforcedResult + aCellResult,
722                             pParent, STRUCT_END, 0, _pToken, *xEntry);
723                 }
724                 else
725                     _pTree->InsertEntry(aResult, pParent, STRUCT_END, 0, _pToken, *xEntry);
726             }
727             else
728             {
729                 _pTree->InsertEntry(aResult, pParent, STRUCT_END, 0, _pToken, *xEntry);
730             }
731             --Count;
732             MakeTree( _pTree, pParent, _pToken, m_oTokenArrayIterator->PrevRPN(), Count);
733         }
734     }
735     catch (const uno::Exception&)
736     {
737         DBG_UNHANDLED_EXCEPTION("formula.ui");
738     }
739 }
740 
fillTree(StructPage * _pTree)741 void FormulaDlg_Impl::fillTree(StructPage* _pTree)
742 {
743     InitFormulaOpCodeMapper();
744     FormulaToken* pToken = m_oTokenArrayIterator->LastRPN();
745 
746     if ( pToken != nullptr)
747     {
748         MakeTree( _pTree, nullptr, nullptr, pToken, 1);
749         m_bMakingTree = false;
750     }
751 }
752 
UpdateTokenArray(const OUString & rStrExp)753 void FormulaDlg_Impl::UpdateTokenArray( const OUString& rStrExp)
754 {
755     m_aTokenMap.clear();
756     m_aTokenList.realloc(0);
757     try
758     {
759         const table::CellAddress aRefPos(m_pHelper->getReferencePosition());
760         m_aTokenList = m_pHelper->getFormulaParser()->parseFormula( rStrExp, aRefPos);
761     }
762     catch (const uno::Exception&)
763     {
764         DBG_UNHANDLED_EXCEPTION("formula.ui");
765     }
766     InitFormulaOpCodeMapper();
767     m_pTokenArray = m_pHelper->convertToTokenArray(m_aTokenList);
768     m_oTokenArrayIterator.emplace(*m_pTokenArray);
769     const sal_Int32 nLen = static_cast<sal_Int32>(m_pTokenArray->GetLen());
770     FormulaToken** pTokens = m_pTokenArray->GetArray();
771     if ( pTokens && nLen == m_aTokenList.getLength() )
772     {
773         for (sal_Int32 nPos = 0; nPos < nLen; nPos++)
774         {
775             m_aTokenMap.emplace( pTokens[nPos], m_aTokenList[nPos] );
776         }
777     } // if ( pTokens && nLen == m_aTokenList.getLength() )
778 
779     std::unique_ptr<FormulaCompiler> pCompiler(m_pHelper->createCompiler(*m_pTokenArray));
780     // #i101512# Disable special handling of jump commands.
781     pCompiler->EnableJumpCommandReorder(false);
782     pCompiler->EnableStopOnError(false);
783     pCompiler->SetComputeIIFlag(true);
784     pCompiler->SetMatrixFlag(m_bUserMatrixFlag);
785     pCompiler->CompileTokenArray();
786 }
787 
FillDialog(bool bFlag)788 void FormulaDlg_Impl::FillDialog(bool bFlag)
789 {
790     bool bNext = true, bPrev = true;
791     if (bFlag)
792         FillControls( bNext, bPrev);
793     FillListboxes();
794     if (bFlag)
795     {
796         m_xBtnBackward->set_sensitive(bPrev);
797         m_xBtnForward->set_sensitive(bNext);
798     }
799 
800     OUString aStrResult;
801 
802     if ( CalcValue( m_pHelper->getCurrentFormula(), aStrResult ) )
803         m_xWndFormResult->set_text( aStrResult );
804     else
805     {
806         aStrResult.clear();
807         m_xWndFormResult->set_text( aStrResult );
808     }
809 }
810 
FillListboxes()811 void FormulaDlg_Impl::FillListboxes()
812 {
813     //  Switch between the "Pages"
814     FormEditData* pData = m_pHelper->getFormEditData();
815     //  1. Page: select function
816     if ( m_pFuncDesc && m_pFuncDesc->getCategory() )
817     {
818         // We'll never have more than int32 max categories so this is safe ...
819         // Category listbox holds additional entries for Last Used and All, so
820         // the offset should be two but hard coded numbers are ugly...
821         const sal_Int32 nCategoryOffset = m_xFuncPage->GetCategoryEntryCount() - m_aFormulaHelper.GetCategoryCount();
822         if ( m_xFuncPage->GetCategory() != static_cast<sal_Int32>(m_pFuncDesc->getCategory()->getNumber() + nCategoryOffset) )
823             m_xFuncPage->SetCategory(m_pFuncDesc->getCategory()->getNumber() + nCategoryOffset);
824 
825         sal_Int32 nPos = m_xFuncPage->GetFuncPos(m_pFuncDesc);
826 
827         m_xFuncPage->SetFunction(nPos);
828     }
829     else if ( pData )
830     {
831         // tdf#104487 - remember last used function category
832         m_xFuncPage->SetCategory(FuncPage::GetRememeberdFunctionCategory());
833         m_xFuncPage->SetFunction( -1 );
834     }
835     FuncSelHdl(*m_xFuncPage);
836 
837     m_pHelper->setDispatcherLock( true );   // Activate Modal-Mode
838 
839     //  HelpId for 1. page is the one from the resource
840     m_rDialog.set_help_id( m_aOldHelp );
841 }
842 
FillControls(bool & rbNext,bool & rbPrev)843 void FormulaDlg_Impl::FillControls( bool &rbNext, bool &rbPrev)
844 {
845     //  Switch between the "Pages"
846     FormEditData* pData = m_pHelper->getFormEditData();
847     if (!pData )
848         return;
849 
850     //  2. Page or Edit: show selected function
851 
852     sal_Int32  nFStart     = pData->GetFStart();
853     OUString   aFormula    = m_pHelper->getCurrentFormula() + " )";
854     sal_Int32  nNextFStart = nFStart;
855     sal_Int32  nNextFEnd   = 0;
856 
857     DeleteArgs();
858     const IFunctionDescription* pOldFuncDesc = m_pFuncDesc;
859 
860     if ( m_aFormulaHelper.GetNextFunc( aFormula, false,
861                                      nNextFStart, &nNextFEnd, &m_pFuncDesc, &m_aArguments ) )
862     {
863         const bool bTestFlag = (pOldFuncDesc != m_pFuncDesc);
864         if (bTestFlag)
865         {
866             m_xFtHeadLine->hide();
867             m_xFtFuncName->hide();
868             m_xFtFuncDesc->hide();
869             m_xParaWin->SetFunctionDesc(m_pFuncDesc);
870             m_xFtEditName->set_label( m_pFuncDesc->getFunctionName() );
871             m_xFtEditName->show();
872             m_xParaWinBox->show();
873             const OUString aHelpId = m_pFuncDesc->getHelpId();
874             if ( !aHelpId.isEmpty() )
875                 m_xMEdit->set_help_id(aHelpId);
876         }
877 
878         sal_Int32 nOldStart, nOldEnd;
879         m_pHelper->getSelection( nOldStart, nOldEnd );
880         if ( nOldStart != nNextFStart || nOldEnd != nNextFEnd )
881         {
882             m_pHelper->setSelection( nNextFStart, nNextFEnd );
883         }
884         m_aFuncSel.Min() = nNextFStart;
885         m_aFuncSel.Max() = nNextFEnd;
886 
887         if (!m_bEditFlag)
888             m_xMEdit->set_text(m_pHelper->getCurrentFormula());
889         sal_Int32 PrivStart, PrivEnd;
890         m_pHelper->getSelection( PrivStart, PrivEnd);
891         if (!m_bEditFlag)
892             m_xMEdit->select_region(PrivStart, PrivEnd);
893 
894         m_nArgs = m_pFuncDesc->getSuppressedArgumentCount();
895         sal_uInt16 nOffset = pData->GetOffset();
896 
897         //  Concatenate the Edit's for Focus-Control
898 
899         if (bTestFlag)
900             m_xParaWin->SetArgumentOffset(nOffset);
901         sal_uInt16 nActiv = 0;
902         sal_Int32   nArgPos  = m_aFormulaHelper.GetArgStart( aFormula, nFStart, 0 );
903 
904         int nStartPos, nEndPos;
905         m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
906         if (nStartPos > nEndPos)
907             std::swap(nStartPos, nEndPos);
908 
909         sal_Int32 nEditPos = nStartPos;
910         bool    bFlag    = false;
911 
912         for (sal_Int32 i = 0; i < m_nArgs; i++)
913         {
914             sal_Int32 nLength = m_aArguments[i].getLength()+1;
915             m_xParaWin->SetArgument( i, m_aArguments[i]);
916             if (nArgPos <= nEditPos && nEditPos < nArgPos+nLength)
917             {
918                 nActiv = i;
919                 bFlag = true;
920             }
921             nArgPos = nArgPos + nLength;
922         }
923         m_xParaWin->UpdateParas();
924 
925         if (bFlag)
926         {
927             m_xParaWin->SetActiveLine(nActiv);
928         }
929 
930         UpdateValues();
931     }
932     else
933     {
934         m_xFtEditName->set_label(u""_ustr);
935         m_xMEdit->set_help_id(m_aEditHelpId);
936     }
937         //  test if before/after are anymore functions
938 
939     sal_Int32 nTempStart = m_aFormulaHelper.GetArgStart( aFormula, nFStart, 0 );
940     rbNext = m_aFormulaHelper.GetNextFunc( aFormula, false, nTempStart );
941 
942     int nStartPos, nEndPos;
943     m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
944     if (nStartPos > nEndPos)
945         std::swap(nStartPos, nEndPos);
946 
947     nTempStart = nStartPos;
948     pData->SetFStart(nTempStart);
949     rbPrev = m_aFormulaHelper.GetNextFunc( aFormula, true, nTempStart );
950 }
951 
952 
ClearAllParas()953 void FormulaDlg_Impl::ClearAllParas()
954 {
955     DeleteArgs();
956     m_pFuncDesc = nullptr;
957     m_xParaWin->ClearAll();
958     m_xWndResult->set_text(OUString());
959     m_xFtFuncName->set_label(OUString());
960     FuncSelHdl(*m_xFuncPage);
961 
962     if (m_xFuncPage->IsVisible())
963     {
964         m_xFtEditName->hide();
965         m_xParaWinBox->hide();
966 
967         m_xBtnForward->set_sensitive(true); //@new
968         m_xFtHeadLine->show();
969         m_xFtFuncName->show();
970         m_xFtFuncDesc->show();
971     }
972 }
973 
RepairFormula(const OUString & aFormula)974 OUString FormulaDlg_Impl::RepairFormula(const OUString& aFormula)
975 {
976     OUString aResult('=');
977     try
978     {
979         UpdateTokenArray(aFormula);
980 
981         if ( m_aTokenList.hasElements() )
982         {
983             const table::CellAddress aRefPos(m_pHelper->getReferencePosition());
984             const OUString sFormula( m_pHelper->getFormulaParser()->printFormula( m_aTokenList, aRefPos));
985             if ( sFormula.isEmpty() || sFormula[0] != '=' )
986                 aResult += sFormula;
987             else
988                 aResult = sFormula;
989 
990         }
991     }
992     catch ( const uno::Exception& )
993     {
994         TOOLS_WARN_EXCEPTION("formula.ui", "FormulaDlg_Impl::RepairFormula");
995     }
996     return aResult;
997 }
998 
DoEnter(bool bOk)999 void FormulaDlg_Impl::DoEnter(bool bOk)
1000 {
1001     //  Accept input to the document or cancel
1002     if ( bOk)
1003     {
1004         //  remove dummy arguments
1005         OUString  aInputFormula = m_pHelper->getCurrentFormula();
1006         OUString  aString = RepairFormula(m_xMEdit->get_text());
1007         m_pHelper->setSelection( 0, aInputFormula.getLength());
1008         m_pHelper->setCurrentFormula(aString);
1009     }
1010 
1011     m_pHelper->switchBack();
1012 
1013     m_pHelper->dispatch( bOk, m_xBtnMatrix->get_active());
1014     //  Clear data
1015     m_pHelper->deleteFormData();
1016 
1017     //  Close dialog
1018     m_pHelper->doClose(bOk);
1019 }
1020 
1021 
IMPL_LINK(FormulaDlg_Impl,BtnHdl,weld::Button &,rBtn,void)1022 IMPL_LINK(FormulaDlg_Impl, BtnHdl, weld::Button&, rBtn, void)
1023 {
1024     if (&rBtn == m_xBtnCancel.get())
1025     {
1026         DoEnter(false);                 // closes the Dialog
1027     }
1028     else if (&rBtn == m_xBtnEnd.get())
1029     {
1030         DoEnter(true);                  // closes the Dialog
1031     }
1032     else if (&rBtn == m_xBtnForward.get())
1033     {
1034         const IFunctionDescription* pDesc;
1035         sal_Int32 nSelFunc = m_xFuncPage->GetFunction();
1036         if (nSelFunc != -1)
1037             pDesc = m_xFuncPage->GetFuncDesc( nSelFunc );
1038         else
1039         {
1040             // Do not overwrite the selected formula expression, just edit the
1041             // unlisted function.
1042             m_pFuncDesc = pDesc = nullptr;
1043         }
1044 
1045         if (pDesc == m_pFuncDesc || !m_xFuncPage->IsVisible())
1046             EditNextFunc( true );
1047         else
1048         {
1049             DblClkHdl(*m_xFuncPage);      //new
1050             m_xBtnForward->set_sensitive(false); //new
1051         }
1052     }
1053     else if (&rBtn == m_xBtnBackward.get())
1054     {
1055         m_bEditFlag = false;
1056         m_xBtnForward->set_sensitive(true);
1057         EditNextFunc( false );
1058     }
1059 }
1060 
1061 //                          Functions for 1. Page
1062 
1063 // Handler for Listboxes
1064 
IMPL_LINK_NOARG(FormulaDlg_Impl,DblClkHdl,FuncPage &,void)1065 IMPL_LINK_NOARG( FormulaDlg_Impl, DblClkHdl, FuncPage&, void)
1066 {
1067     sal_Int32 nFunc = m_xFuncPage->GetFunction();
1068 
1069     //  ex-UpdateLRUList
1070     const IFunctionDescription* pDesc = m_xFuncPage->GetFuncDesc(nFunc);
1071     m_pHelper->insertEntryToLRUList(pDesc);
1072 
1073     OUString aFuncName = m_xFuncPage->GetSelFunctionName() + "()";
1074     m_pHelper->setCurrentFormula(aFuncName);
1075     m_xMEdit->replace_selection(aFuncName);
1076 
1077     int nStartPos, nEndPos;
1078     m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
1079     if (nStartPos > nEndPos)
1080         std::swap(nStartPos, nEndPos);
1081 
1082     nEndPos = nEndPos - 1;
1083     m_xMEdit->select_region(nStartPos, nEndPos);
1084 
1085     FormulaHdl(*m_xMEdit);
1086 
1087     nStartPos = nEndPos;
1088     m_xMEdit->select_region(nStartPos, nEndPos);
1089 
1090     if (m_nArgs == 0)
1091     {
1092         BtnHdl(*m_xBtnBackward);
1093     }
1094 
1095     m_xParaWin->SetEdFocus();
1096     m_xBtnForward->set_sensitive(false); //@New
1097 }
1098 
1099 //                          Functions for right Page
1100 
SetData(sal_Int32 nFStart,sal_Int32 nNextFStart,sal_Int32 nNextFEnd,sal_Int32 & PrivStart,sal_Int32 & PrivEnd)1101 void FormulaDlg_Impl::SetData( sal_Int32 nFStart, sal_Int32 nNextFStart, sal_Int32 nNextFEnd, sal_Int32& PrivStart, sal_Int32& PrivEnd)
1102 {
1103     sal_Int32 nFEnd;
1104 
1105     // Notice and set new selection
1106     m_pHelper->getSelection( nFStart, nFEnd );
1107     m_pHelper->setSelection( nNextFStart, nNextFEnd );
1108     if (!m_bEditFlag)
1109         m_xMEdit->set_text(m_pHelper->getCurrentFormula());
1110 
1111 
1112     m_pHelper->getSelection( PrivStart, PrivEnd);
1113     if (!m_bEditFlag)
1114     {
1115         m_xMEdit->select_region(PrivStart, PrivEnd);
1116         UpdateOldSel();
1117     }
1118 
1119     FormEditData* pData = m_pHelper->getFormEditData();
1120     pData->SetFStart( nNextFStart );
1121     pData->SetOffset( 0 );
1122 
1123     FillDialog();
1124 }
1125 
EditThisFunc(sal_Int32 nFStart)1126 void FormulaDlg_Impl::EditThisFunc(sal_Int32 nFStart)
1127 {
1128     FormEditData* pData = m_pHelper->getFormEditData();
1129     if (!pData)
1130         return;
1131 
1132     OUString aFormula = m_pHelper->getCurrentFormula();
1133 
1134     if (nFStart == NOT_FOUND)
1135     {
1136         nFStart = pData->GetFStart();
1137     }
1138     else
1139     {
1140         pData->SetFStart(nFStart);
1141     }
1142 
1143     sal_Int32 nNextFStart  = nFStart;
1144     sal_Int32 nNextFEnd    = 0;
1145 
1146     bool bFound;
1147 
1148     bFound = m_aFormulaHelper.GetNextFunc( aFormula, false, nNextFStart, &nNextFEnd);
1149     if ( bFound )
1150     {
1151         sal_Int32 PrivStart, PrivEnd;
1152         SetData( nFStart, nNextFStart, nNextFEnd, PrivStart, PrivEnd);
1153         m_pHelper->showReference( aFormula.copy( PrivStart, PrivEnd-PrivStart));
1154     }
1155     else
1156     {
1157         ClearAllParas();
1158     }
1159 }
1160 
EditNextFunc(bool bForward,sal_Int32 nFStart)1161 bool FormulaDlg_Impl::EditNextFunc( bool bForward, sal_Int32 nFStart )
1162 {
1163     FormEditData* pData = m_pHelper->getFormEditData();
1164     if (!pData)
1165         return false;
1166 
1167     OUString aFormula = m_pHelper->getCurrentFormula();
1168 
1169     if (nFStart == NOT_FOUND)
1170     {
1171         nFStart = pData->GetFStart();
1172     }
1173     else
1174     {
1175         pData->SetFStart(nFStart);
1176     }
1177 
1178     sal_Int32 nNextFStart  = 0;
1179     sal_Int32 nNextFEnd    = 0;
1180 
1181     bool bFound;
1182     if ( bForward )
1183     {
1184         nNextFStart = m_aFormulaHelper.GetArgStart( aFormula, nFStart, 0 );
1185         bFound = m_aFormulaHelper.GetNextFunc( aFormula, false, nNextFStart, &nNextFEnd);
1186     }
1187     else
1188     {
1189         nNextFStart = nFStart;
1190         bFound = m_aFormulaHelper.GetNextFunc( aFormula, true, nNextFStart, &nNextFEnd);
1191     }
1192 
1193     if ( bFound )
1194     {
1195         sal_Int32 PrivStart, PrivEnd;
1196         SetData( nFStart, nNextFStart, nNextFEnd, PrivStart, PrivEnd);
1197     }
1198 
1199     return bFound;
1200 }
1201 
GetPrevFuncExpression(bool bStartFromEnd)1202 OUString FormulaDlg_Impl::GetPrevFuncExpression( bool bStartFromEnd )
1203 {
1204     OUString aExpression;
1205 
1206     OUString aFormula( m_pHelper->getCurrentFormula());
1207     if (aFormula.isEmpty())
1208         return aExpression;
1209 
1210     if (bStartFromEnd || m_nFuncExpStart >= aFormula.getLength())
1211         m_nFuncExpStart = aFormula.getLength() - 1;
1212 
1213     sal_Int32 nFStart = m_nFuncExpStart;
1214     sal_Int32 nFEnd   = 0;
1215     if (m_aFormulaHelper.GetNextFunc( aFormula, true, nFStart, &nFEnd))
1216     {
1217         aExpression = aFormula.copy( nFStart, nFEnd - nFStart); // nFEnd is exclusive
1218         m_nFuncExpStart = nFStart;
1219     }
1220 
1221     return aExpression;
1222 }
1223 
SaveArg(sal_uInt16 nEd)1224 void FormulaDlg_Impl::SaveArg( sal_uInt16 nEd )
1225 {
1226     if (nEd >= m_nArgs)
1227         return;
1228 
1229     for (sal_uInt16 i = 0; i <= nEd; i++)
1230     {
1231         if ( m_aArguments[i].isEmpty() )
1232             m_aArguments[i] = " ";
1233     }
1234     if (!m_xParaWin->GetArgument(nEd).isEmpty())
1235         m_aArguments[nEd] = m_xParaWin->GetArgument(nEd);
1236 
1237     sal_uInt16 nClearPos = nEd+1;
1238     for (sal_Int32 i = nEd+1; i < m_nArgs; i++)
1239     {
1240         if ( !m_xParaWin->GetArgument(i).isEmpty() )
1241         {
1242             nClearPos = i+1;
1243         }
1244     }
1245 
1246     for (sal_Int32 i = nClearPos; i < m_nArgs; i++)
1247     {
1248         m_aArguments[i].clear();
1249     }
1250 }
1251 
IMPL_LINK(FormulaDlg_Impl,FxHdl,ParaWin &,rPtr,void)1252 IMPL_LINK( FormulaDlg_Impl, FxHdl, ParaWin&, rPtr, void )
1253 {
1254     if (&rPtr != m_xParaWin.get())
1255         return;
1256 
1257     m_xBtnForward->set_sensitive(true); //@ In order to be able to input another function.
1258     m_xTabCtrl->set_current_page(u"functiontab"_ustr);
1259 
1260     OUString aUndoStr = m_pHelper->getCurrentFormula();       // it will be added before a ";"
1261     FormEditData* pData = m_pHelper->getFormEditData();
1262     if (!pData)
1263         return;
1264 
1265     sal_uInt16 nArgNo = m_xParaWin->GetActiveLine();
1266     sal_uInt16 nEdFocus = nArgNo;
1267 
1268     SaveArg(nArgNo);
1269     UpdateSelection();
1270 
1271     sal_Int32 nFormulaStrPos = pData->GetFStart();
1272 
1273     OUString aFormula = m_pHelper->getCurrentFormula();
1274     sal_Int32 n1 = m_aFormulaHelper.GetArgStart( aFormula, nFormulaStrPos, nEdFocus + pData->GetOffset() );
1275 
1276     pData->SaveValues();
1277     pData->SetMode( FormulaDlgMode::Formula );
1278     pData->SetFStart( n1 );
1279     pData->SetUndoStr( aUndoStr );
1280     ClearAllParas();
1281 
1282     FillDialog(false);
1283     m_xFuncPage->SetFocus(); //There Parawin is not visible anymore
1284 }
1285 
IMPL_LINK(FormulaDlg_Impl,ModifyHdl,ParaWin &,rPtr,void)1286 IMPL_LINK( FormulaDlg_Impl, ModifyHdl, ParaWin&, rPtr, void )
1287 {
1288     if (&rPtr == m_xParaWin.get())
1289     {
1290         SaveArg(m_xParaWin->GetActiveLine());
1291         UpdateValues();
1292 
1293         UpdateSelection();
1294         CalcStruct(m_xMEdit->get_text());
1295     }
1296 }
1297 
IMPL_LINK_NOARG(FormulaDlg_Impl,FormulaHdl,weld::TextView &,void)1298 IMPL_LINK_NOARG( FormulaDlg_Impl, FormulaHdl, weld::TextView&, void)
1299 {
1300 
1301     FormEditData* pData = m_pHelper->getFormEditData();
1302     if (!pData)
1303         return;
1304 
1305     m_bEditFlag = true;
1306     OUString    aInputFormula = m_pHelper->getCurrentFormula();
1307     OUString    aString = m_xMEdit->get_text();
1308 
1309     int nStartPos, nEndPos;
1310     m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
1311     if (nStartPos > nEndPos)
1312         std::swap(nStartPos, nEndPos);
1313 
1314     if (aString.isEmpty())      // in case everything was cleared
1315     {
1316         aString += "=";
1317         m_xMEdit->set_text(aString);
1318         nStartPos = 1;
1319         nEndPos = 1;
1320         m_xMEdit->select_region(nStartPos, nEndPos);
1321     }
1322     else if (aString[0]!='=')   // in case it's replaced
1323     {
1324         aString = "=" + aString;
1325         m_xMEdit->set_text(aString);
1326         nStartPos += 1;
1327         nEndPos += 1;
1328         m_xMEdit->select_region(nStartPos, nEndPos);
1329     }
1330 
1331     m_pHelper->setSelection( 0, aInputFormula.getLength());
1332     m_pHelper->setCurrentFormula(aString);
1333     m_pHelper->setSelection(nStartPos, nEndPos);
1334 
1335     sal_Int32 nPos = nStartPos - 1;
1336 
1337     OUString aStrResult;
1338 
1339     if ( CalcValue( m_pHelper->getCurrentFormula(), aStrResult ) )
1340         m_xWndFormResult->set_text( aStrResult );
1341     else
1342     {
1343         aStrResult.clear();
1344         m_xWndFormResult->set_text( aStrResult );
1345     }
1346     CalcStruct(aString);
1347 
1348     nPos = GetFunctionPos(nPos);
1349 
1350     if (nPos < nStartPos - 1)
1351     {
1352         sal_Int32 nPos1 = aString.indexOf( '(', nPos);
1353         EditNextFunc( false, nPos1);
1354     }
1355     else
1356     {
1357         ClearAllParas();
1358     }
1359 
1360     m_pHelper->setSelection(nStartPos, nEndPos);
1361     m_bEditFlag = false;
1362 }
1363 
FormulaCursor()1364 void FormulaDlg_Impl::FormulaCursor()
1365 {
1366     FormEditData* pData = m_pHelper->getFormEditData();
1367     if (!pData)
1368         return;
1369 
1370     m_bEditFlag = true;
1371 
1372     OUString    aString = m_xMEdit->get_text();
1373 
1374     int nStartPos, nEndPos;
1375     m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
1376     if (nStartPos > nEndPos)
1377         std::swap(nStartPos, nEndPos);
1378 
1379     m_pHelper->setSelection(nStartPos, nEndPos);
1380 
1381     if (nStartPos == 0)
1382     {
1383         nStartPos = 1;
1384         m_xMEdit->select_region(nStartPos, nEndPos);
1385     }
1386     if (nStartPos != aString.getLength())
1387     {
1388         sal_Int32 nPos = nStartPos;
1389 
1390         sal_Int32 nFStart = GetFunctionPos(nPos - 1);
1391 
1392         if (nFStart < nPos)
1393         {
1394             sal_Int32 nPos1 = m_aFormulaHelper.GetFunctionEnd( aString, nFStart);
1395 
1396             if (nPos1 > nPos)
1397             {
1398                 EditThisFunc(nFStart);
1399             }
1400             else
1401             {
1402                 sal_Int32 n = nPos;
1403                 short nCount = 1;
1404                 while(n > 0)
1405                 {
1406                    if (aString[n]==')')
1407                        nCount++;
1408                    else if (aString[n]=='(')
1409                        nCount--;
1410                    if (nCount == 0)
1411                        break;
1412                    n--;
1413                 }
1414                 if (nCount == 0)
1415                 {
1416                     nFStart = m_aFormulaHelper.GetFunctionStart( aString, n, true);
1417                     EditThisFunc(nFStart);
1418                 }
1419                 else
1420                 {
1421                     ClearAllParas();
1422                 }
1423             }
1424         }
1425         else
1426         {
1427             ClearAllParas();
1428         }
1429     }
1430     m_pHelper->setSelection(nStartPos, nEndPos);
1431 
1432     m_bEditFlag = false;
1433 }
1434 
UpdateOldSel()1435 void FormulaDlg_Impl::UpdateOldSel()
1436 {
1437     m_xMEdit->get_selection_bounds(m_nSelectionStart, m_nSelectionEnd);
1438     if (m_nSelectionStart > m_nSelectionEnd)
1439         std::swap(m_nSelectionStart, m_nSelectionEnd);
1440 }
1441 
IMPL_LINK_NOARG(FormulaDlg_Impl,FormulaCursorHdl,weld::TextView &,void)1442 IMPL_LINK_NOARG( FormulaDlg_Impl, FormulaCursorHdl, weld::TextView&, void)
1443 {
1444     int nStartPos, nEndPos;
1445     m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
1446     if (nStartPos > nEndPos)
1447         std::swap(nStartPos, nEndPos);
1448 
1449     if (nStartPos != m_nSelectionStart || nEndPos != m_nSelectionEnd)
1450     {
1451         m_nSelectionStart = nStartPos;
1452         m_nSelectionEnd = nEndPos;
1453         FormulaCursor();
1454     }
1455 }
1456 
UpdateSelection()1457 void FormulaDlg_Impl::UpdateSelection()
1458 {
1459     m_pHelper->setSelection( m_aFuncSel.Min(), m_aFuncSel.Max());
1460     if (m_pFuncDesc)
1461     {
1462         m_pHelper->setCurrentFormula( m_pFuncDesc->getFormula( m_aArguments ) );
1463         m_nArgs = m_pFuncDesc->getSuppressedArgumentCount();
1464     }
1465     else
1466     {
1467         m_pHelper->setCurrentFormula(u""_ustr);
1468         m_nArgs = 0;
1469     }
1470 
1471     m_xMEdit->set_text(m_pHelper->getCurrentFormula());
1472     sal_Int32 PrivStart, PrivEnd;
1473     m_pHelper->getSelection( PrivStart, PrivEnd);
1474     m_aFuncSel.Min() = PrivStart;
1475     m_aFuncSel.Max() = PrivEnd;
1476 
1477     OUString aFormula = m_xMEdit->get_text();
1478     sal_Int32 nArgPos = m_aFormulaHelper.GetArgStart( aFormula, PrivStart, 0);
1479 
1480     sal_uInt16 nPos = m_xParaWin->GetActiveLine();
1481     if (nPos >= m_aArguments.size())
1482     {
1483         SAL_WARN("formula.ui","FormulaDlg_Impl::UpdateSelection - shot in foot: nPos " <<
1484                 nPos << " >= m_aArguments.size() " << m_aArguments.size() <<
1485                 " for aFormula '" << aFormula << "'");
1486         nPos = m_aArguments.size();
1487         if (nPos)
1488             --nPos;
1489     }
1490 
1491     for (sal_uInt16 i = 0; i < nPos; i++)
1492     {
1493         nArgPos += (m_aArguments[i].getLength() + 1);
1494     }
1495     sal_Int32 nLength = (nPos < m_aArguments.size()) ? m_aArguments[nPos].getLength() : 0;
1496 
1497     m_pHelper->setSelection(nArgPos, nArgPos + nLength);
1498     m_xMEdit->select_region(nArgPos, nArgPos + nLength);
1499     UpdateOldSel();
1500 }
1501 
RefInputStartBefore(RefEdit * pEdit,RefButton * pButton)1502 ::std::pair<RefButton*, RefEdit*> FormulaDlg_Impl::RefInputStartBefore(RefEdit* pEdit, RefButton* pButton)
1503 {
1504     m_pTheRefEdit = pEdit;
1505     m_pTheRefButton = pButton;
1506 
1507     Selection aOrigSelection;
1508     if (m_pTheRefEdit)
1509     {
1510         // grab selection before showing next widget in case the selection is blown away
1511         // by it appearing
1512         aOrigSelection = m_pTheRefEdit->GetSelection();
1513     }
1514 
1515     // because its initially hidden, give it its optimal size so clicking the
1516     // refbutton has an initial size to work when retro-fitting this to .ui
1517     m_xEdRef->GetWidget()->set_size_request(m_xEdRef->GetWidget()->get_preferred_size().Width(), -1);
1518     m_xEdRef->GetWidget()->show();
1519 
1520     if ( m_pTheRefEdit )
1521     {
1522         m_xEdRef->SetRefString(m_pTheRefEdit->GetText());
1523         m_xEdRef->SetSelection(aOrigSelection);
1524         m_xEdRef->GetWidget()->set_help_id(m_pTheRefEdit->GetWidget()->get_help_id());
1525     }
1526 
1527     m_xRefBtn->GetWidget()->set_visible(pButton != nullptr);
1528 
1529     ::std::pair<RefButton*, RefEdit*> aPair;
1530     aPair.first = pButton ? m_xRefBtn.get() : nullptr;
1531     aPair.second = m_xEdRef.get();
1532     return aPair;
1533 }
1534 
RefInputStartAfter()1535 void FormulaDlg_Impl::RefInputStartAfter()
1536 {
1537     m_xRefBtn->SetEndImage();
1538 
1539     if (!m_pTheRefEdit)
1540         return;
1541 
1542     OUString aStr = m_aTitle2 + " " + m_xFtEditName->get_label() + "( ";
1543 
1544     if ( m_xParaWin->GetActiveLine() > 0 )
1545         aStr += "...; ";
1546     aStr += m_xParaWin->GetActiveArgName();
1547     if ( m_xParaWin->GetActiveLine() + 1 < m_nArgs )
1548         aStr += "; ...";
1549     aStr += " )";
1550 
1551     m_rDialog.set_title(m_rDialog.strip_mnemonic(aStr));
1552 }
1553 
RefInputDoneAfter(bool bForced)1554 void FormulaDlg_Impl::RefInputDoneAfter( bool bForced )
1555 {
1556     m_xRefBtn->SetStartImage();
1557     if (!bForced && m_xRefBtn->GetWidget()->get_visible())
1558         return;
1559 
1560     m_xEdRef->GetWidget()->hide();
1561     m_xRefBtn->GetWidget()->hide();
1562     if ( m_pTheRefEdit )
1563     {
1564         m_pTheRefEdit->SetRefString( m_xEdRef->GetText() );
1565         m_pTheRefEdit->GrabFocus();
1566 
1567         if ( m_pTheRefButton )
1568             m_pTheRefButton->SetStartImage();
1569 
1570         sal_uInt16 nPrivActiv = m_xParaWin->GetActiveLine();
1571         m_xParaWin->SetArgument( nPrivActiv, m_xEdRef->GetText() );
1572         ModifyHdl( *m_xParaWin );
1573         m_pTheRefEdit = nullptr;
1574     }
1575     m_rDialog.set_title(m_aTitle1);
1576 }
1577 
GetCurrRefEdit()1578 RefEdit* FormulaDlg_Impl::GetCurrRefEdit()
1579 {
1580     return m_xEdRef->GetWidget()->get_visible() ? m_xEdRef.get() : m_xParaWin->GetActiveEdit();
1581 }
1582 
Update()1583 void FormulaDlg_Impl::Update()
1584 {
1585     FormEditData* pData = m_pHelper->getFormEditData();
1586     const OUString sExpression = m_xMEdit->get_text();
1587     m_aOldFormula.clear();
1588     UpdateTokenArray(sExpression);
1589     FormulaCursor();
1590     CalcStruct(sExpression);
1591     if (pData->GetMode() == FormulaDlgMode::Formula)
1592         m_xTabCtrl->set_current_page(u"functiontab"_ustr);
1593     else
1594         m_xTabCtrl->set_current_page(u"structtab"_ustr);
1595     m_xBtnMatrix->set_active(pData->GetMatrixFlag());
1596 }
1597 
Update(const OUString & _sExp)1598 void FormulaDlg_Impl::Update(const OUString& _sExp)
1599 {
1600     CalcStruct(_sExp);
1601     FillDialog();
1602     FuncSelHdl(*m_xFuncPage);
1603 }
1604 
SetMeText(const OUString & _sText)1605 void FormulaDlg_Impl::SetMeText(const OUString& _sText)
1606 {
1607     FormEditData* pData = m_pHelper->getFormEditData();
1608     m_xMEdit->set_text(_sText);
1609     auto aSelection = pData->GetSelection();
1610     m_xMEdit->select_region(aSelection.Min(), aSelection.Max());
1611     UpdateOldSel();
1612 }
1613 
SetMeText(const OUString & _sText,sal_Int32 PrivStart,sal_Int32 PrivEnd,bool bMatrix,bool _bSelect,bool _bUpdate)1614 FormulaDlgMode FormulaDlg_Impl::SetMeText( const OUString& _sText, sal_Int32 PrivStart, sal_Int32 PrivEnd, bool bMatrix, bool _bSelect, bool _bUpdate)
1615 {
1616     FormulaDlgMode eMode = FormulaDlgMode::Formula;
1617     if (!m_bEditFlag)
1618         m_xMEdit->set_text(_sText);
1619 
1620     if ( _bSelect || !m_bEditFlag )
1621         m_xMEdit->select_region(PrivStart, PrivEnd);
1622     if ( _bUpdate )
1623     {
1624         UpdateOldSel();
1625         int nStartPos, nEndPos;
1626         m_xMEdit->get_selection_bounds(nStartPos, nEndPos);
1627         if (nStartPos > nEndPos)
1628             std::swap(nStartPos, nEndPos);
1629         m_pHelper->showReference(m_xMEdit->get_text().copy(nStartPos, nEndPos - nStartPos));
1630         eMode = FormulaDlgMode::Edit;
1631 
1632         m_xBtnMatrix->set_active( bMatrix );
1633     } // if ( _bUpdate )
1634     return eMode;
1635 }
1636 
CheckMatrix(OUString & aFormula)1637 bool FormulaDlg_Impl::CheckMatrix(OUString& aFormula)
1638 {
1639     m_xMEdit->grab_focus();
1640     sal_Int32 nLen = aFormula.getLength();
1641     bool bMatrix =  nLen > 3                    // Matrix-Formula
1642             && aFormula[0] == '{'
1643             && aFormula[1] == '='
1644             && aFormula[nLen-1] == '}';
1645     if ( bMatrix )
1646     {
1647         aFormula = aFormula.copy( 1, aFormula.getLength()-2 );
1648         m_xBtnMatrix->set_active( bMatrix );
1649         m_xBtnMatrix->set_sensitive(false);
1650     } // if ( bMatrix )
1651 
1652     m_xTabCtrl->set_current_page(u"structtab"_ustr);
1653     return bMatrix;
1654 }
1655 
IMPL_LINK_NOARG(FormulaDlg_Impl,StructSelHdl,StructPage &,void)1656 IMPL_LINK_NOARG( FormulaDlg_Impl, StructSelHdl, StructPage&, void)
1657 {
1658     m_bStructUpdate = false;
1659     if (m_xStructPage->IsVisible())
1660         m_xBtnForward->set_sensitive(false); //@New
1661     m_bStructUpdate = true;
1662 }
1663 
IMPL_LINK_NOARG(FormulaDlg_Impl,MatrixHdl,weld::Toggleable &,void)1664 IMPL_LINK_NOARG( FormulaDlg_Impl, MatrixHdl, weld::Toggleable&, void)
1665 {
1666     m_bUserMatrixFlag = true;
1667     UpdateValues(true);
1668 }
1669 
IMPL_LINK_NOARG(FormulaDlg_Impl,FuncSelHdl,FuncPage &,void)1670 IMPL_LINK_NOARG( FormulaDlg_Impl, FuncSelHdl, FuncPage&, void)
1671 {
1672     if (   (m_xFuncPage->GetFunctionEntryCount() > 0)
1673         && (m_xFuncPage->GetFunction() != -1) )
1674     {
1675         const IFunctionDescription* pDesc = m_xFuncPage->GetFuncDesc( m_xFuncPage->GetFunction() );
1676 
1677         if (pDesc != m_pFuncDesc)
1678             m_xBtnForward->set_sensitive(true); //new
1679 
1680         if (pDesc)
1681         {
1682             pDesc->initArgumentInfo();      // full argument info is needed
1683 
1684             OUString aSig = pDesc->getSignature();
1685             m_xFtHeadLine->set_label( pDesc->getFunctionName() );
1686             m_xFtFuncName->set_label( aSig );
1687             m_xFtFuncDesc->set_label( pDesc->getDescription() );
1688         }
1689     }
1690     else
1691     {
1692         m_xFtHeadLine->set_label( OUString() );
1693         m_xFtFuncName->set_label( OUString() );
1694         m_xFtFuncDesc->set_label( OUString() );
1695     }
1696 }
1697 
UpdateParaWin(const Selection & _rSelection,const OUString & _sRefStr)1698 void FormulaDlg_Impl::UpdateParaWin( const Selection& _rSelection, const OUString& _sRefStr)
1699 {
1700     Selection theSel = _rSelection;
1701     m_xEdRef->GetWidget()->replace_selection(_sRefStr);
1702     theSel.Max() = theSel.Min() + _sRefStr.getLength();
1703     m_xEdRef->SetSelection( theSel );
1704 
1705 
1706     // Manual Update of the results' fields:
1707 
1708     sal_uInt16 nPrivActiv = m_xParaWin->GetActiveLine();
1709     m_xParaWin->SetArgument( nPrivActiv, m_xEdRef->GetText());
1710     m_xParaWin->UpdateParas();
1711 
1712     RefEdit* pEd = GetCurrRefEdit();
1713     if (pEd)
1714         pEd->SetSelection( theSel );
1715 }
1716 
UpdateParaWin(Selection & _rSelection)1717 bool FormulaDlg_Impl::UpdateParaWin(Selection& _rSelection)
1718 {
1719     OUString      aStrEd;
1720     RefEdit* pEd = GetCurrRefEdit();
1721     if (pEd && !m_pTheRefEdit)
1722     {
1723         _rSelection = pEd->GetSelection();
1724         _rSelection.Normalize();
1725         aStrEd = pEd->GetText();
1726         m_xEdRef->SetRefString(aStrEd);
1727         m_xEdRef->SetSelection( _rSelection );
1728     }
1729     else
1730     {
1731         _rSelection = m_xEdRef->GetSelection();
1732         _rSelection.Normalize();
1733         aStrEd = m_xEdRef->GetText();
1734     }
1735     return m_pTheRefEdit == nullptr;
1736 }
1737 
SetEdSelection()1738 void FormulaDlg_Impl::SetEdSelection()
1739 {
1740     RefEdit* pEd = GetCurrRefEdit()/*aScParaWin.GetActiveEdit()*/;
1741     if (pEd)
1742     {
1743         Selection theSel = m_xEdRef->GetSelection();
1744         //  Edit may have the focus -> call ModifyHdl in addition
1745         //  to what's happening in GetFocus
1746         pEd->GetModifyHdl().Call(*pEd);
1747         pEd->GrabFocus();
1748         pEd->SetSelection(theSel);
1749     } // if ( pEd )
1750 }
1751 
FormulaModalDialog(weld::Window * pParent,IFunctionManager const * _pFunctionMgr,IControlReferenceHandler * _pDlg)1752 FormulaModalDialog::FormulaModalDialog(weld::Window* pParent,
1753                                        IFunctionManager const * _pFunctionMgr,
1754                                        IControlReferenceHandler* _pDlg)
1755     : GenericDialogController(pParent, u"formula/ui/formuladialog.ui"_ustr, u"FormulaDialog"_ustr)
1756     , m_pImpl(new FormulaDlg_Impl(*m_xDialog, *m_xBuilder, false/*_bSupportFunctionResult*/,
1757                                   false/*_bSupportResult*/, false/*_bSupportMatrix*/,
1758                                   this, _pFunctionMgr, _pDlg))
1759 {
1760     m_xDialog->set_title(m_pImpl->m_aTitle1);
1761 }
1762 
~FormulaModalDialog()1763 FormulaModalDialog::~FormulaModalDialog() { }
1764 
Update(const OUString & _sExp)1765 void FormulaModalDialog::Update(const OUString& _sExp)
1766 {
1767     m_pImpl->Update(_sExp);
1768 }
1769 
SetMeText(const OUString & _sText)1770 void FormulaModalDialog::SetMeText(const OUString& _sText)
1771 {
1772     m_pImpl->SetMeText(_sText);
1773 }
1774 
CheckMatrix(OUString & aFormula)1775 void FormulaModalDialog::CheckMatrix(OUString& aFormula)
1776 {
1777     m_pImpl->CheckMatrix(aFormula);
1778 }
1779 
Update()1780 void FormulaModalDialog::Update()
1781 {
1782     m_pImpl->Update();
1783 }
1784 
RefInputStartBefore(RefEdit * pEdit,RefButton * pButton)1785 ::std::pair<RefButton*, RefEdit*> FormulaModalDialog::RefInputStartBefore( RefEdit* pEdit, RefButton* pButton )
1786 {
1787     return m_pImpl->RefInputStartBefore( pEdit, pButton );
1788 }
1789 
RefInputStartAfter()1790 void FormulaModalDialog::RefInputStartAfter()
1791 {
1792     m_pImpl->RefInputStartAfter();
1793 }
1794 
RefInputDoneAfter()1795 void FormulaModalDialog::RefInputDoneAfter()
1796 {
1797     m_pImpl->RefInputDoneAfter( true/*bForced*/ );
1798 }
1799 
StoreFormEditData(FormEditData * pData)1800 void FormulaModalDialog::StoreFormEditData(FormEditData* pData)
1801 {
1802     m_pImpl->StoreFormEditData(pData);
1803 }
1804 
1805 //      Initialisation / General functions  for Dialog
FormulaDlg(SfxBindings * pB,SfxChildWindow * pCW,weld::Window * pParent,IFunctionManager const * _pFunctionMgr,IControlReferenceHandler * _pDlg)1806 FormulaDlg::FormulaDlg(SfxBindings* pB, SfxChildWindow* pCW,
1807                        weld::Window* pParent,
1808                        IFunctionManager const * _pFunctionMgr, IControlReferenceHandler* _pDlg)
1809     : SfxModelessDialogController( pB, pCW, pParent, u"formula/ui/formuladialog.ui"_ustr, u"FormulaDialog"_ustr)
1810     , m_pImpl(new FormulaDlg_Impl(*m_xDialog, *m_xBuilder, true/*_bSupportFunctionResult*/
1811                                              , true/*_bSupportResult*/
1812                                              , true/*_bSupportMatrix*/
1813                                              , this, _pFunctionMgr, _pDlg))
1814 {
1815     m_xDialog->set_title(m_pImpl->m_aTitle1);
1816 }
1817 
~FormulaDlg()1818 FormulaDlg::~FormulaDlg()
1819 {
1820 }
1821 
Update(const OUString & _sExp)1822 void FormulaDlg::Update(const OUString& _sExp)
1823 {
1824     m_pImpl->Update(_sExp);
1825 }
1826 
SetMeText(const OUString & _sText)1827 void FormulaDlg::SetMeText(const OUString& _sText)
1828 {
1829     m_pImpl->SetMeText(_sText);
1830 }
1831 
SetMeText(const OUString & _sText,sal_Int32 PrivStart,sal_Int32 PrivEnd,bool bMatrix,bool _bSelect,bool _bUpdate)1832 FormulaDlgMode FormulaDlg::SetMeText( const OUString& _sText, sal_Int32 PrivStart, sal_Int32 PrivEnd, bool bMatrix, bool _bSelect, bool _bUpdate)
1833 {
1834     return m_pImpl->SetMeText( _sText, PrivStart, PrivEnd, bMatrix, _bSelect, _bUpdate);
1835 }
1836 
CheckMatrix(OUString & aFormula)1837 bool FormulaDlg::CheckMatrix(OUString& aFormula)
1838 {
1839     return m_pImpl->CheckMatrix(aFormula);
1840 }
1841 
GetMeText() const1842 OUString FormulaDlg::GetMeText() const
1843 {
1844     return m_pImpl->m_xMEdit->get_text();
1845 }
1846 
Update()1847 void FormulaDlg::Update()
1848 {
1849     m_pImpl->Update();
1850 }
1851 
DoEnter()1852 void FormulaDlg::DoEnter()
1853 {
1854     m_pImpl->DoEnter(false);
1855 }
1856 
RefInputStartBefore(RefEdit * pEdit,RefButton * pButton)1857 ::std::pair<RefButton*, RefEdit*> FormulaDlg::RefInputStartBefore( RefEdit* pEdit, RefButton* pButton )
1858 {
1859     return m_pImpl->RefInputStartBefore( pEdit, pButton );
1860 }
1861 
RefInputStartAfter()1862 void FormulaDlg::RefInputStartAfter()
1863 {
1864     m_pImpl->RefInputStartAfter();
1865 }
1866 
RefInputDoneAfter(bool bForced)1867 void FormulaDlg::RefInputDoneAfter( bool bForced )
1868 {
1869     m_pImpl->RefInputDoneAfter( bForced );
1870 }
1871 
disableOk()1872 void FormulaDlg::disableOk()
1873 {
1874     m_pImpl->m_xBtnEnd->set_sensitive(false);
1875 }
1876 
StoreFormEditData(FormEditData * pData)1877 void FormulaDlg::StoreFormEditData(FormEditData* pData)
1878 {
1879     m_pImpl->StoreFormEditData(pData);
1880 }
1881 
getCurrentFunctionDescription() const1882 const IFunctionDescription* FormulaDlg::getCurrentFunctionDescription() const
1883 {
1884     SAL_WARN_IF( (m_pImpl->m_pFuncDesc && m_pImpl->m_pFuncDesc->getSuppressedArgumentCount() != m_pImpl->m_nArgs),
1885             "formula.ui", "FormulaDlg::getCurrentFunctionDescription: getSuppressedArgumentCount " <<
1886             m_pImpl->m_pFuncDesc->getSuppressedArgumentCount() << " != m_nArgs " << m_pImpl->m_nArgs << " for " <<
1887             m_pImpl->m_pFuncDesc->getFunctionName());
1888     return m_pImpl->m_pFuncDesc;
1889 }
1890 
UpdateParaWin(const Selection & _rSelection,const OUString & _sRefStr)1891 void FormulaDlg::UpdateParaWin( const Selection& _rSelection, const OUString& _sRefStr)
1892 {
1893     m_pImpl->UpdateParaWin( _rSelection, _sRefStr);
1894 }
1895 
UpdateParaWin(Selection & _rSelection)1896 bool FormulaDlg::UpdateParaWin(Selection& _rSelection)
1897 {
1898     return m_pImpl->UpdateParaWin(_rSelection);
1899 }
1900 
GetActiveEdit()1901 RefEdit* FormulaDlg::GetActiveEdit()
1902 {
1903     return m_pImpl->m_xParaWin->GetActiveEdit();
1904 }
1905 
GetFormulaHelper() const1906 const FormulaHelper& FormulaDlg::GetFormulaHelper() const
1907 {
1908     return m_pImpl->GetFormulaHelper();
1909 }
1910 
SetEdSelection()1911 void FormulaDlg::SetEdSelection()
1912 {
1913     m_pImpl->SetEdSelection();
1914 }
1915 
SaveValues()1916 void FormEditData::SaveValues()
1917 {
1918     Reset();
1919 }
1920 
Reset()1921 void FormEditData::Reset()
1922 {
1923     nMode = FormulaDlgMode::Formula;
1924     nFStart = 0;
1925     nOffset = 0;
1926     bMatrix = false;
1927     aSelection.Min() = 0;
1928     aSelection.Max() = 0;
1929     aUndoStr.clear();
1930 }
1931 
operator =(const FormEditData & r)1932 FormEditData& FormEditData::operator=( const FormEditData& r )
1933 {
1934     nMode           = r.nMode;
1935     nFStart         = r.nFStart;
1936     nOffset         = r.nOffset;
1937     aUndoStr        = r.aUndoStr;
1938     bMatrix         = r.bMatrix ;
1939     aSelection      = r.aSelection;
1940     return *this;
1941 }
1942 
FormEditData()1943 FormEditData::FormEditData()
1944 {
1945     Reset();
1946 }
1947 
~FormEditData()1948 FormEditData::~FormEditData()
1949 {
1950 }
1951 
FormEditData(const FormEditData & r)1952 FormEditData::FormEditData( const FormEditData& r )
1953 {
1954     *this = r;
1955 }
1956 
1957 
1958 } // formula
1959 
1960 
1961 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1962