1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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 <comphelper/diagnose_ex.hxx>
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>
56 using namespace ::com::sun::star
;
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 );
69 sal_Int32
GetFunctionPos(sal_Int32 nPos
);
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
);
81 OUString
GetPrevFuncExpression( bool bStartFromEnd
);
83 void StoreFormEditData(FormEditData
* pEditData
);
86 void Update(const OUString
& _sExp
);
88 void SaveArg( sal_uInt16 nEd
);
89 void UpdateSelection();
90 void DoEnter( bool bOk
);
92 void FillControls( bool &rbNext
, bool &rbPrev
);
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*/);
98 void SetEdSelection();
100 bool UpdateParaWin(Selection
& _rSelection
);
101 void UpdateParaWin( const Selection
& _rSelection
, const OUString
& _sRefStr
);
103 void SetData( sal_Int32 nFStart
, sal_Int32 nNextFStart
, sal_Int32 nNextFEnd
, sal_Int32
& PrivStart
, sal_Int32
& PrivEnd
);
105 RefEdit
* GetCurrRefEdit();
107 const FormulaHelper
& GetFormulaHelper() const { return m_aFormulaHelper
;}
108 void InitFormulaOpCodeMapper();
111 void FormulaCursor();
113 DECL_LINK( ModifyHdl
, ParaWin
&, void );
114 DECL_LINK( FxHdl
, ParaWin
&, void );
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 );
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
;
136 OUString m_aOldFormula
;
137 bool m_bStructUpdate
;
138 bool m_bUserMatrixFlag
;
140 const OUString m_aTitle1
;
141 const OUString m_aTitle2
;
142 FormulaHelper m_aFormulaHelper
;
144 OUString m_aEditHelpId
;
147 bool m_bMakingTree
; // in method of constructing tree
150 const IFunctionDescription
* m_pFuncDesc
;
152 ::std::vector
< OUString
> m_aArguments
;
153 Selection m_aFuncSel
;
155 sal_Int32 m_nFuncExpStart
; ///< current formula position for treeview results
157 int m_nSelectionStart
;
160 RefEdit
* m_pTheRefEdit
;
161 RefButton
* m_pTheRefButton
;
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
;
170 std::unique_ptr
<weld::Label
> m_xFtEditName
;
172 std::unique_ptr
<weld::Label
> m_xFtResult
;
173 std::unique_ptr
<weld::Entry
> m_xWndResult
;
175 std::unique_ptr
<weld::Label
> m_xFtFormula
;
176 std::unique_ptr
<weld::TextView
> m_xMEdit
;
178 std::unique_ptr
<weld::CheckButton
> m_xBtnMatrix
;
179 std::unique_ptr
<weld::Button
> m_xBtnCancel
;
181 std::unique_ptr
<weld::Button
> m_xBtnBackward
;
182 std::unique_ptr
<weld::Button
> m_xBtnForward
;
183 std::unique_ptr
<weld::Button
> m_xBtnEnd
;
185 std::unique_ptr
<weld::Label
> m_xFtFormResult
;
186 std::unique_ptr
<weld::Entry
> m_xWndFormResult
;
188 std::unique_ptr
<RefEdit
> m_xEdRef
;
189 std::unique_ptr
<RefButton
> m_xRefBtn
;
191 std::unique_ptr
<FuncPage
> m_xFuncPage
;
192 std::unique_ptr
<StructPage
> m_xStructPage
;
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
);
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
)
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)
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
)))
248 auto nWidth
= m_xMEdit
->get_approximate_digit_width() * 62;
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
);
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
);
262 m_xMEdit
->set_size_request(nWidth
,
263 m_xMEdit
->get_height_rows(5));
265 m_xEdRef
->SetReferences(_pDlg
, m_xFtEditName
.get());
266 m_xRefBtn
->SetReferences(_pDlg
, m_xEdRef
.get());
268 m_xParaWin
.reset(new ParaWin(m_xParaWinBox
.get(), _pDlg
));
270 m_xParaWinBox
->hide();
271 m_xFtEditName
->hide();
272 m_xEdRef
->GetWidget()->hide();
273 m_xRefBtn
->GetWidget()->hide();
275 m_xMEdit
->set_accessible_name(m_xFtFormula
->get_label());
277 m_aEditHelpId
= m_xMEdit
->get_help_id();
280 m_bStructUpdate
=true;
281 m_xParaWin
->SetArgModifiedHdl( LINK( this, FormulaDlg_Impl
, ModifyHdl
) );
282 m_xParaWin
->SetFxHdl( LINK( this, FormulaDlg_Impl
, FxHdl
) );
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
);
288 m_aOldHelp
= m_rDialog
.get_help_id(); // HelpId from resource always for "Page 1"
290 m_xFtResult
->set_visible( _bSupportResult
);
291 m_xWndResult
->set_visible( _bSupportResult
);
293 m_xFtFormResult
->set_visible( _bSupportFunctionResult
);
294 m_xWndFormResult
->set_visible( _bSupportFunctionResult
);
296 if ( _bSupportMatrix
)
297 m_xBtnMatrix
->connect_toggled( LINK( this, FormulaDlg_Impl
, MatrixHdl
) );
299 m_xBtnMatrix
->hide();
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
) );
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
) );
312 vcl::Font aFntLight
= m_xFtFormula
->get_font();
313 vcl::Font aFntBold
= aFntLight
;
314 aFntBold
.SetWeight( WEIGHT_BOLD
);
316 m_xParaWin
->SetArgumentFonts( aFntBold
, aFntLight
);
319 FormulaDlg_Impl::~FormulaDlg_Impl()
321 m_xTabCtrl
->remove_page(u
"functiontab"_ustr
);
322 m_xTabCtrl
->remove_page(u
"structtab"_ustr
);
327 void FormulaDlg_Impl::StoreFormEditData(FormEditData
* pData
)
329 if (!pData
) // it won't be destroyed via Close
332 int nStartPos
, nEndPos
;
333 m_xMEdit
->get_selection_bounds(nStartPos
, nEndPos
);
334 if (nStartPos
> nEndPos
)
335 std::swap(nStartPos
, nEndPos
);
337 pData
->SetFStart(nStartPos
);
338 pData
->SetSelection(Selection(nStartPos
, nEndPos
));
340 if (m_xTabCtrl
->get_current_page_ident() == "functiontab")
341 pData
->SetMode( FormulaDlgMode::Formula
);
343 pData
->SetMode( FormulaDlgMode::Edit
);
344 pData
->SetUndoStr(m_xMEdit
->get_text());
345 pData
->SetMatrixFlag(m_xBtnMatrix
->get_active());
348 void FormulaDlg_Impl::InitFormulaOpCodeMapper()
350 if ( m_xOpCodeMapper
.is() )
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();
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
);
361 m_aSpecialOpCodes
= m_xOpCodeMapper
->getAvailableMappings( sheet::FormulaLanguage::ODFF
, sheet::FormulaMapGroup::SPECIAL
);
364 void FormulaDlg_Impl::DeleteArgs()
366 ::std::vector
< OUString
>().swap(m_aArguments
);
370 sal_Int32
FormulaDlg_Impl::GetFunctionPos(sal_Int32 nPos
)
372 if ( !m_aTokenList
.hasElements() )
373 return SAL_MAX_INT32
;
375 const sal_Unicode sep
= m_pHelper
->getFunctionManager()->getSingleToken(IFunctionManager::eSep
);
377 sal_Int32 nFuncPos
= SAL_MAX_INT32
;
378 OUString aFormString
= m_aFormulaHelper
.GetCharClass().uppercase(m_xMEdit
->get_text());
380 const uno::Reference
< sheet::XFormulaParser
> xParser(m_pHelper
->getFormulaParser());
381 const table::CellAddress
aRefPos(m_pHelper
->getReferencePosition());
383 const sheet::FormulaToken
* pIter
= m_aTokenList
.getConstArray();
384 const sheet::FormulaToken
* pEnd
= pIter
+ m_aTokenList
.getLength();
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
)
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;
402 if ( !m_bUserMatrixFlag
&& FormulaCompiler::IsMatrixFunction(static_cast<OpCode
>(eOp
)) )
404 m_xBtnMatrix
->set_active(true);
407 if (eOp
== nOpPush
|| eOp
== nOpSpaces
|| eOp
== nOpWhitespace
)
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 )
420 if ( pNextToken
!= pEnd
)
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)
431 nTokPos
= nTokPos
+ aString
.getLength();
434 if ( eOp
== m_aSeparatorsOpCodes
[TOKEN_OPEN
].OpCode
)
439 else if ( eOp
== m_aSeparatorsOpCodes
[TOKEN_CLOSE
].OpCode
)
443 nFuncPos
= nPrevFuncPos
;
445 bool bIsFunction
= std::any_of( m_aFunctionOpCodes
.getConstArray(),
446 m_pFunctionOpCodesEnd
,
447 [&eOp
](const sheet::FormulaOpCodeMapEntry
& aEntry
) { return aEntry
.Token
.OpCode
== eOp
; });
449 if ( bIsFunction
&& nOpSpaces
!= eOp
&& nOpWhitespace
!= eOp
)
451 nPrevFuncPos
= nFuncPos
;
452 nFuncPos
= nOldTokPos
;
455 if ( nOldTokPos
<= nPos
&& nPos
< nTokPos
)
459 if ( nBracketCount
< 1 )
461 nFuncPos
= m_xMEdit
->get_text().getLength();
465 nFuncPos
= nPrevFuncPos
;
472 nOldTokPos
= nTokPos
;
473 } // while ( pIter != pEnd )
475 catch ( const uno::Exception
& )
477 TOOLS_WARN_EXCEPTION("formula.ui", "FormulaDlg_Impl::GetFunctionPos");
483 bool FormulaDlg_Impl::CalcValue( const OUString
& rStrExp
, OUString
& rStrResult
, bool bForceMatrixFormula
)
487 if ( !rStrExp
.isEmpty() )
489 // Only calculate the value when there isn't any more keyboard input:
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
);
496 bResult
= m_pHelper
->calculateValue( rStrExp
, rStrResult
, bForceMatrixFormula
|| m_xBtnMatrix
->get_active());
505 void FormulaDlg_Impl::UpdateValues( bool bForceRecalcStruct
)
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())
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())
521 const sal_Int32 nPos
= m_aFuncSel
.Min();
522 assert( 0 <= nPos
&& nPos
< m_pHelper
->getCurrentFormula().getLength());
524 const FormulaToken
* pToken
= nullptr;
525 for (pToken
= m_oTokenArrayIterator
->First(); pToken
; pToken
= m_oTokenArrayIterator
->Next())
527 pCompiler
->CreateStringFromToken( aBuf
, pToken
);
528 if (nPos
< aBuf
.getLength())
531 if (pToken
&& nPos
< aBuf
.getLength())
532 bForceArray
= pToken
->IsInForceArray();
537 if (m_pFuncDesc
&& CalcValue( m_pFuncDesc
->getFormula( m_aArguments
), aStrResult
, bForceArray
))
538 m_xWndResult
->set_text( aStrResult
);
544 if ( CalcValue( m_pHelper
->getCurrentFormula(), aStrResult
) )
545 m_xWndFormResult
->set_text( aStrResult
);
549 m_xWndFormResult
->set_text( aStrResult
);
551 CalcStruct( m_xMEdit
->get_text(), bForceRecalcStruct
);
554 void FormulaDlg_Impl::CalcStruct( const OUString
& rStrExp
, bool bForceRecalcStruct
)
556 sal_Int32 nLength
= rStrExp
.getLength();
558 if ( !(!rStrExp
.isEmpty() && (bForceRecalcStruct
|| m_aOldFormula
!= rStrExp
) && m_bStructUpdate
))
561 m_xStructPage
->ClearStruct();
563 OUString aString
= rStrExp
;
564 if (rStrExp
[nLength
-1] == '(')
566 aString
= aString
.copy( 0, nLength
-1);
569 aString
= aString
.replaceAll( "\n", "");
572 if ( CalcValue( aString
, aStrResult
) )
573 m_xWndFormResult
->set_text(aStrResult
);
575 UpdateTokenArray(aString
);
576 fillTree(m_xStructPage
.get());
578 m_aOldFormula
= rStrExp
;
579 if (rStrExp
[nLength
-1] == '(')
580 UpdateTokenArray(rStrExp
);
583 void FormulaDlg_Impl::MakeTree(StructPage
* _pTree
, weld::TreeIter
* pParent
, const FormulaToken
* pFuncToken
,
584 const FormulaToken
* _pToken
, tools::Long Count
)
586 if ( _pToken
== nullptr || Count
<= 0 )
589 tools::Long nParas
= _pToken
->GetParamCount();
590 OpCode eOp
= _pToken
->GetOpCode();
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())
598 uno::Sequence
<sheet::FormulaToken
> aArgs
{ itr
->second
};
601 const table::CellAddress
aRefPos(m_pHelper
->getReferencePosition());
602 const OUString aResult
= m_pHelper
->getFormulaParser()->printFormula( aArgs
, aRefPos
);
604 if ( nParas
> 0 || (nParas
== 0 && _pToken
->IsFunction()) )
606 std::unique_ptr
<weld::TreeIter
> xEntry
;
607 weld::TreeIter
* pEntry
;
609 bool bCalcSubformula
= false;
610 OUString aTest
= _pTree
->GetEntryText(pParent
);
612 if (aTest
== aResult
&& (eOp
== ocAdd
|| eOp
== ocMul
|| eOp
== ocAmpersand
))
618 xEntry
= m_xStructPage
->GetTlbStruct().make_iterator();
622 _pTree
->InsertEntry(aResult
, pParent
, STRUCT_ERROR
, 0, _pToken
, *xEntry
);
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
)))
627 // Not a binary or unary operator.
628 bCalcSubformula
= true;
629 _pTree
->InsertEntry(aResult
, pParent
, STRUCT_FOLDER
, 0, _pToken
, *xEntry
);
633 /* TODO: question remains, why not sub calculate operators? */
634 _pTree
->InsertEntry(aResult
, pParent
, STRUCT_FOLDER
, 0, _pToken
, *xEntry
);
637 pEntry
= xEntry
.get();
640 MakeTree(_pTree
, pEntry
, _pToken
, m_oTokenArrayIterator
->PrevRPN(), nParas
);
648 // gets the last subformula result
649 m_bMakingTree
= true;
650 aFormula
= GetPrevFuncExpression( true);
654 // gets subsequent subformula results (from the back)
655 aFormula
= GetPrevFuncExpression( false);
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
);
666 m_oTokenArrayIterator
->NextRPN(); /* TODO: what's this to be? ThisRPN()? */
667 MakeTree( _pTree
, pParent
, _pToken
, m_oTokenArrayIterator
->PrevRPN(), Count
);
671 std::unique_ptr
<weld::TreeIter
> xEntry(m_xStructPage
->GetTlbStruct().make_iterator());
674 _pTree
->InsertEntry( aResult
, pParent
, STRUCT_ERROR
, 0, _pToken
, *xEntry
);
676 else if (eOp
== ocPush
)
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
)
686 formula::ParamClass eParamClass
= ParamClass::Reference
;
687 if (pFuncToken
->IsInForceArray())
688 eParamClass
= ParamClass::ForceArray
;
691 std::shared_ptr
<FormulaCompiler
> pCompiler
= m_pHelper
->getCompiler();
693 eParamClass
= pCompiler
->GetForceArrayParameter( pFuncToken
, Count
- 1);
697 case ParamClass::Unknown
:
698 case ParamClass::Bounds
:
699 case ParamClass::Value
:
700 if (CalcValue( "=" + aResult
, aUnforcedResult
, false) && aUnforcedResult
!= aResult
)
701 aUnforcedResult
+= " ";
703 aUnforcedResult
.clear();
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
716 OUString aCellResult
;
717 if (CalcValue( "=" + aResult
, aCellResult
, bForceMatrix
) && aCellResult
!= aResult
)
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
);
725 _pTree
->InsertEntry(aResult
, pParent
, STRUCT_END
, 0, _pToken
, *xEntry
);
729 _pTree
->InsertEntry(aResult
, pParent
, STRUCT_END
, 0, _pToken
, *xEntry
);
732 MakeTree( _pTree
, pParent
, _pToken
, m_oTokenArrayIterator
->PrevRPN(), Count
);
735 catch (const uno::Exception
&)
737 DBG_UNHANDLED_EXCEPTION("formula.ui");
741 void FormulaDlg_Impl::fillTree(StructPage
* _pTree
)
743 InitFormulaOpCodeMapper();
744 FormulaToken
* pToken
= m_oTokenArrayIterator
->LastRPN();
746 if ( pToken
!= nullptr)
748 MakeTree( _pTree
, nullptr, nullptr, pToken
, 1);
749 m_bMakingTree
= false;
753 void FormulaDlg_Impl::UpdateTokenArray( const OUString
& rStrExp
)
756 m_aTokenList
.realloc(0);
759 const table::CellAddress
aRefPos(m_pHelper
->getReferencePosition());
760 m_aTokenList
= m_pHelper
->getFormulaParser()->parseFormula( rStrExp
, aRefPos
);
762 catch (const uno::Exception
&)
764 DBG_UNHANDLED_EXCEPTION("formula.ui");
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() )
773 for (sal_Int32 nPos
= 0; nPos
< nLen
; nPos
++)
775 m_aTokenMap
.emplace( pTokens
[nPos
], m_aTokenList
[nPos
] );
777 } // if ( pTokens && nLen == m_aTokenList.getLength() )
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();
788 void FormulaDlg_Impl::FillDialog(bool bFlag
)
790 bool bNext
= true, bPrev
= true;
792 FillControls( bNext
, bPrev
);
796 m_xBtnBackward
->set_sensitive(bPrev
);
797 m_xBtnForward
->set_sensitive(bNext
);
802 if ( CalcValue( m_pHelper
->getCurrentFormula(), aStrResult
) )
803 m_xWndFormResult
->set_text( aStrResult
);
807 m_xWndFormResult
->set_text( aStrResult
);
811 void FormulaDlg_Impl::FillListboxes()
813 // Switch between the "Pages"
814 FormEditData
* pData
= m_pHelper
->getFormEditData();
815 // 1. Page: select function
816 if ( m_pFuncDesc
&& m_pFuncDesc
->getCategory() )
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
);
825 sal_Int32 nPos
= m_xFuncPage
->GetFuncPos(m_pFuncDesc
);
827 m_xFuncPage
->SetFunction(nPos
);
831 // tdf#104487 - remember last used function category
832 m_xFuncPage
->SetCategory(FuncPage::GetRememeberdFunctionCategory());
833 m_xFuncPage
->SetFunction( -1 );
835 FuncSelHdl(*m_xFuncPage
);
837 m_pHelper
->setDispatcherLock( true ); // Activate Modal-Mode
839 // HelpId for 1. page is the one from the resource
840 m_rDialog
.set_help_id( m_aOldHelp
);
843 void FormulaDlg_Impl::FillControls( bool &rbNext
, bool &rbPrev
)
845 // Switch between the "Pages"
846 FormEditData
* pData
= m_pHelper
->getFormEditData();
850 // 2. Page or Edit: show selected function
852 sal_Int32 nFStart
= pData
->GetFStart();
853 OUString aFormula
= m_pHelper
->getCurrentFormula() + " )";
854 sal_Int32 nNextFStart
= nFStart
;
855 sal_Int32 nNextFEnd
= 0;
858 const IFunctionDescription
* pOldFuncDesc
= m_pFuncDesc
;
860 if ( m_aFormulaHelper
.GetNextFunc( aFormula
, false,
861 nNextFStart
, &nNextFEnd
, &m_pFuncDesc
, &m_aArguments
) )
863 const bool bTestFlag
= (pOldFuncDesc
!= m_pFuncDesc
);
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
);
878 sal_Int32 nOldStart
, nOldEnd
;
879 m_pHelper
->getSelection( nOldStart
, nOldEnd
);
880 if ( nOldStart
!= nNextFStart
|| nOldEnd
!= nNextFEnd
)
882 m_pHelper
->setSelection( nNextFStart
, nNextFEnd
);
884 m_aFuncSel
.Min() = nNextFStart
;
885 m_aFuncSel
.Max() = nNextFEnd
;
888 m_xMEdit
->set_text(m_pHelper
->getCurrentFormula());
889 sal_Int32 PrivStart
, PrivEnd
;
890 m_pHelper
->getSelection( PrivStart
, PrivEnd
);
892 m_xMEdit
->select_region(PrivStart
, PrivEnd
);
894 m_nArgs
= m_pFuncDesc
->getSuppressedArgumentCount();
895 sal_uInt16 nOffset
= pData
->GetOffset();
897 // Concatenate the Edit's for Focus-Control
900 m_xParaWin
->SetArgumentOffset(nOffset
);
901 sal_uInt16 nActiv
= 0;
902 sal_Int32 nArgPos
= m_aFormulaHelper
.GetArgStart( aFormula
, nFStart
, 0 );
904 int nStartPos
, nEndPos
;
905 m_xMEdit
->get_selection_bounds(nStartPos
, nEndPos
);
906 if (nStartPos
> nEndPos
)
907 std::swap(nStartPos
, nEndPos
);
909 sal_Int32 nEditPos
= nStartPos
;
912 for (sal_Int32 i
= 0; i
< m_nArgs
; i
++)
914 sal_Int32 nLength
= m_aArguments
[i
].getLength()+1;
915 m_xParaWin
->SetArgument( i
, m_aArguments
[i
]);
916 if (nArgPos
<= nEditPos
&& nEditPos
< nArgPos
+nLength
)
921 nArgPos
= nArgPos
+ nLength
;
923 m_xParaWin
->UpdateParas();
927 m_xParaWin
->SetActiveLine(nActiv
);
934 m_xFtEditName
->set_label(u
""_ustr
);
935 m_xMEdit
->set_help_id(m_aEditHelpId
);
937 // test if before/after are anymore functions
939 sal_Int32 nTempStart
= m_aFormulaHelper
.GetArgStart( aFormula
, nFStart
, 0 );
940 rbNext
= m_aFormulaHelper
.GetNextFunc( aFormula
, false, nTempStart
);
942 int nStartPos
, nEndPos
;
943 m_xMEdit
->get_selection_bounds(nStartPos
, nEndPos
);
944 if (nStartPos
> nEndPos
)
945 std::swap(nStartPos
, nEndPos
);
947 nTempStart
= nStartPos
;
948 pData
->SetFStart(nTempStart
);
949 rbPrev
= m_aFormulaHelper
.GetNextFunc( aFormula
, true, nTempStart
);
953 void FormulaDlg_Impl::ClearAllParas()
956 m_pFuncDesc
= nullptr;
957 m_xParaWin
->ClearAll();
958 m_xWndResult
->set_text(OUString());
959 m_xFtFuncName
->set_label(OUString());
960 FuncSelHdl(*m_xFuncPage
);
962 if (m_xFuncPage
->IsVisible())
964 m_xFtEditName
->hide();
965 m_xParaWinBox
->hide();
967 m_xBtnForward
->set_sensitive(true); //@new
968 m_xFtHeadLine
->show();
969 m_xFtFuncName
->show();
970 m_xFtFuncDesc
->show();
974 OUString
FormulaDlg_Impl::RepairFormula(const OUString
& aFormula
)
976 OUString
aResult('=');
979 UpdateTokenArray(aFormula
);
981 if ( m_aTokenList
.hasElements() )
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] != '=' )
992 catch ( const uno::Exception
& )
994 TOOLS_WARN_EXCEPTION("formula.ui", "FormulaDlg_Impl::RepairFormula");
999 void FormulaDlg_Impl::DoEnter(bool bOk
)
1001 // Accept input to the document or cancel
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
);
1011 m_pHelper
->switchBack();
1013 m_pHelper
->dispatch( bOk
, m_xBtnMatrix
->get_active());
1015 m_pHelper
->deleteFormData();
1018 m_pHelper
->doClose(bOk
);
1022 IMPL_LINK(FormulaDlg_Impl
, BtnHdl
, weld::Button
&, rBtn
, void)
1024 if (&rBtn
== m_xBtnCancel
.get())
1026 DoEnter(false); // closes the Dialog
1028 else if (&rBtn
== m_xBtnEnd
.get())
1030 DoEnter(true); // closes the Dialog
1032 else if (&rBtn
== m_xBtnForward
.get())
1034 const IFunctionDescription
* pDesc
;
1035 sal_Int32 nSelFunc
= m_xFuncPage
->GetFunction();
1037 pDesc
= m_xFuncPage
->GetFuncDesc();
1040 // Do not overwrite the selected formula expression, just edit the
1041 // unlisted function.
1042 m_pFuncDesc
= pDesc
= nullptr;
1045 if (pDesc
== m_pFuncDesc
|| !m_xFuncPage
->IsVisible())
1046 EditNextFunc( true );
1049 DblClkHdl(*m_xFuncPage
); //new
1050 m_xBtnForward
->set_sensitive(false); //new
1053 else if (&rBtn
== m_xBtnBackward
.get())
1055 m_bEditFlag
= false;
1056 m_xBtnForward
->set_sensitive(true);
1057 EditNextFunc( false );
1061 // Functions for 1. Page
1063 // Handler for Listboxes
1065 IMPL_LINK_NOARG( FormulaDlg_Impl
, DblClkHdl
, FuncPage
&, void)
1068 const IFunctionDescription
* pDesc
= m_xFuncPage
->GetFuncDesc();
1069 m_pHelper
->insertEntryToLRUList(pDesc
);
1071 OUString aFuncName
= m_xFuncPage
->GetSelFunctionName() + "()";
1072 m_pHelper
->setCurrentFormula(aFuncName
);
1073 m_xMEdit
->replace_selection(aFuncName
);
1075 int nStartPos
, nEndPos
;
1076 m_xMEdit
->get_selection_bounds(nStartPos
, nEndPos
);
1077 if (nStartPos
> nEndPos
)
1078 std::swap(nStartPos
, nEndPos
);
1080 nEndPos
= nEndPos
- 1;
1081 m_xMEdit
->select_region(nStartPos
, nEndPos
);
1083 FormulaHdl(*m_xMEdit
);
1085 nStartPos
= nEndPos
;
1086 m_xMEdit
->select_region(nStartPos
, nEndPos
);
1090 BtnHdl(*m_xBtnBackward
);
1093 m_xParaWin
->SetEdFocus();
1094 m_xBtnForward
->set_sensitive(false); //@New
1097 // Functions for right Page
1099 void FormulaDlg_Impl::SetData( sal_Int32 nFStart
, sal_Int32 nNextFStart
, sal_Int32 nNextFEnd
, sal_Int32
& PrivStart
, sal_Int32
& PrivEnd
)
1103 // Notice and set new selection
1104 m_pHelper
->getSelection( nFStart
, nFEnd
);
1105 m_pHelper
->setSelection( nNextFStart
, nNextFEnd
);
1107 m_xMEdit
->set_text(m_pHelper
->getCurrentFormula());
1110 m_pHelper
->getSelection( PrivStart
, PrivEnd
);
1113 m_xMEdit
->select_region(PrivStart
, PrivEnd
);
1117 FormEditData
* pData
= m_pHelper
->getFormEditData();
1118 pData
->SetFStart( nNextFStart
);
1119 pData
->SetOffset( 0 );
1124 void FormulaDlg_Impl::EditThisFunc(sal_Int32 nFStart
)
1126 FormEditData
* pData
= m_pHelper
->getFormEditData();
1130 OUString aFormula
= m_pHelper
->getCurrentFormula();
1132 if (nFStart
== NOT_FOUND
)
1134 nFStart
= pData
->GetFStart();
1138 pData
->SetFStart(nFStart
);
1141 sal_Int32 nNextFStart
= nFStart
;
1142 sal_Int32 nNextFEnd
= 0;
1146 bFound
= m_aFormulaHelper
.GetNextFunc( aFormula
, false, nNextFStart
, &nNextFEnd
);
1149 sal_Int32 PrivStart
, PrivEnd
;
1150 SetData( nFStart
, nNextFStart
, nNextFEnd
, PrivStart
, PrivEnd
);
1151 m_pHelper
->showReference( aFormula
.copy( PrivStart
, PrivEnd
-PrivStart
));
1159 bool FormulaDlg_Impl::EditNextFunc( bool bForward
, sal_Int32 nFStart
)
1161 FormEditData
* pData
= m_pHelper
->getFormEditData();
1165 OUString aFormula
= m_pHelper
->getCurrentFormula();
1167 if (nFStart
== NOT_FOUND
)
1169 nFStart
= pData
->GetFStart();
1173 pData
->SetFStart(nFStart
);
1176 sal_Int32 nNextFStart
= 0;
1177 sal_Int32 nNextFEnd
= 0;
1182 nNextFStart
= m_aFormulaHelper
.GetArgStart( aFormula
, nFStart
, 0 );
1183 bFound
= m_aFormulaHelper
.GetNextFunc( aFormula
, false, nNextFStart
, &nNextFEnd
);
1187 nNextFStart
= nFStart
;
1188 bFound
= m_aFormulaHelper
.GetNextFunc( aFormula
, true, nNextFStart
, &nNextFEnd
);
1193 sal_Int32 PrivStart
, PrivEnd
;
1194 SetData( nFStart
, nNextFStart
, nNextFEnd
, PrivStart
, PrivEnd
);
1200 OUString
FormulaDlg_Impl::GetPrevFuncExpression( bool bStartFromEnd
)
1202 OUString aExpression
;
1204 OUString
aFormula( m_pHelper
->getCurrentFormula());
1205 if (aFormula
.isEmpty())
1208 if (bStartFromEnd
|| m_nFuncExpStart
>= aFormula
.getLength())
1209 m_nFuncExpStart
= aFormula
.getLength() - 1;
1211 sal_Int32 nFStart
= m_nFuncExpStart
;
1212 sal_Int32 nFEnd
= 0;
1213 if (m_aFormulaHelper
.GetNextFunc( aFormula
, true, nFStart
, &nFEnd
))
1215 aExpression
= aFormula
.copy( nFStart
, nFEnd
- nFStart
); // nFEnd is exclusive
1216 m_nFuncExpStart
= nFStart
;
1222 void FormulaDlg_Impl::SaveArg( sal_uInt16 nEd
)
1227 for (sal_uInt16 i
= 0; i
<= nEd
; i
++)
1229 if ( m_aArguments
[i
].isEmpty() )
1230 m_aArguments
[i
] = " ";
1232 if (!m_xParaWin
->GetArgument(nEd
).isEmpty())
1233 m_aArguments
[nEd
] = m_xParaWin
->GetArgument(nEd
);
1235 sal_uInt16 nClearPos
= nEd
+1;
1236 for (sal_Int32 i
= nEd
+1; i
< m_nArgs
; i
++)
1238 if ( !m_xParaWin
->GetArgument(i
).isEmpty() )
1244 for (sal_Int32 i
= nClearPos
; i
< m_nArgs
; i
++)
1246 m_aArguments
[i
].clear();
1250 IMPL_LINK( FormulaDlg_Impl
, FxHdl
, ParaWin
&, rPtr
, void )
1252 if (&rPtr
!= m_xParaWin
.get())
1255 m_xBtnForward
->set_sensitive(true); //@ In order to be able to input another function.
1256 m_xTabCtrl
->set_current_page(u
"functiontab"_ustr
);
1258 OUString aUndoStr
= m_pHelper
->getCurrentFormula(); // it will be added before a ";"
1259 FormEditData
* pData
= m_pHelper
->getFormEditData();
1263 sal_uInt16 nArgNo
= m_xParaWin
->GetActiveLine();
1264 sal_uInt16 nEdFocus
= nArgNo
;
1269 sal_Int32 nFormulaStrPos
= pData
->GetFStart();
1271 OUString aFormula
= m_pHelper
->getCurrentFormula();
1272 sal_Int32 n1
= m_aFormulaHelper
.GetArgStart( aFormula
, nFormulaStrPos
, nEdFocus
+ pData
->GetOffset() );
1274 pData
->SaveValues();
1275 pData
->SetMode( FormulaDlgMode::Formula
);
1276 pData
->SetFStart( n1
);
1277 pData
->SetUndoStr( aUndoStr
);
1281 m_xFuncPage
->SetFocus(); //There Parawin is not visible anymore
1284 IMPL_LINK( FormulaDlg_Impl
, ModifyHdl
, ParaWin
&, rPtr
, void )
1286 if (&rPtr
== m_xParaWin
.get())
1288 SaveArg(m_xParaWin
->GetActiveLine());
1292 CalcStruct(m_xMEdit
->get_text());
1296 IMPL_LINK_NOARG( FormulaDlg_Impl
, FormulaHdl
, weld::TextView
&, void)
1299 FormEditData
* pData
= m_pHelper
->getFormEditData();
1304 OUString aInputFormula
= m_pHelper
->getCurrentFormula();
1305 OUString aString
= m_xMEdit
->get_text();
1307 int nStartPos
, nEndPos
;
1308 m_xMEdit
->get_selection_bounds(nStartPos
, nEndPos
);
1309 if (nStartPos
> nEndPos
)
1310 std::swap(nStartPos
, nEndPos
);
1312 if (aString
.isEmpty()) // in case everything was cleared
1315 m_xMEdit
->set_text(aString
);
1318 m_xMEdit
->select_region(nStartPos
, nEndPos
);
1320 else if (aString
[0]!='=') // in case it's replaced
1322 aString
= "=" + aString
;
1323 m_xMEdit
->set_text(aString
);
1326 m_xMEdit
->select_region(nStartPos
, nEndPos
);
1329 m_pHelper
->setSelection( 0, aInputFormula
.getLength());
1330 m_pHelper
->setCurrentFormula(aString
);
1331 m_pHelper
->setSelection(nStartPos
, nEndPos
);
1333 sal_Int32 nPos
= nStartPos
- 1;
1335 OUString aStrResult
;
1337 if ( CalcValue( m_pHelper
->getCurrentFormula(), aStrResult
) )
1338 m_xWndFormResult
->set_text( aStrResult
);
1342 m_xWndFormResult
->set_text( aStrResult
);
1344 CalcStruct(aString
);
1346 nPos
= GetFunctionPos(nPos
);
1348 if (nPos
< nStartPos
- 1)
1350 sal_Int32 nPos1
= aString
.indexOf( '(', nPos
);
1351 EditNextFunc( false, nPos1
);
1358 m_pHelper
->setSelection(nStartPos
, nEndPos
);
1359 m_bEditFlag
= false;
1362 void FormulaDlg_Impl::FormulaCursor()
1364 FormEditData
* pData
= m_pHelper
->getFormEditData();
1370 OUString aString
= m_xMEdit
->get_text();
1372 int nStartPos
, nEndPos
;
1373 m_xMEdit
->get_selection_bounds(nStartPos
, nEndPos
);
1374 if (nStartPos
> nEndPos
)
1375 std::swap(nStartPos
, nEndPos
);
1377 m_pHelper
->setSelection(nStartPos
, nEndPos
);
1382 m_xMEdit
->select_region(nStartPos
, nEndPos
);
1384 if (nStartPos
!= aString
.getLength())
1386 sal_Int32 nPos
= nStartPos
;
1388 sal_Int32 nFStart
= GetFunctionPos(nPos
- 1);
1392 sal_Int32 nPos1
= m_aFormulaHelper
.GetFunctionEnd( aString
, nFStart
);
1396 EditThisFunc(nFStart
);
1404 if (aString
[n
]==')')
1406 else if (aString
[n
]=='(')
1414 nFStart
= m_aFormulaHelper
.GetFunctionStart( aString
, n
, true);
1415 EditThisFunc(nFStart
);
1428 m_pHelper
->setSelection(nStartPos
, nEndPos
);
1430 m_bEditFlag
= false;
1433 void FormulaDlg_Impl::UpdateOldSel()
1435 m_xMEdit
->get_selection_bounds(m_nSelectionStart
, m_nSelectionEnd
);
1436 if (m_nSelectionStart
> m_nSelectionEnd
)
1437 std::swap(m_nSelectionStart
, m_nSelectionEnd
);
1440 IMPL_LINK_NOARG( FormulaDlg_Impl
, FormulaCursorHdl
, weld::TextView
&, void)
1442 int nStartPos
, nEndPos
;
1443 m_xMEdit
->get_selection_bounds(nStartPos
, nEndPos
);
1444 if (nStartPos
> nEndPos
)
1445 std::swap(nStartPos
, nEndPos
);
1447 if (nStartPos
!= m_nSelectionStart
|| nEndPos
!= m_nSelectionEnd
)
1449 m_nSelectionStart
= nStartPos
;
1450 m_nSelectionEnd
= nEndPos
;
1455 void FormulaDlg_Impl::UpdateSelection()
1457 m_pHelper
->setSelection( m_aFuncSel
.Min(), m_aFuncSel
.Max());
1460 m_pHelper
->setCurrentFormula( m_pFuncDesc
->getFormula( m_aArguments
) );
1461 m_nArgs
= m_pFuncDesc
->getSuppressedArgumentCount();
1465 m_pHelper
->setCurrentFormula(u
""_ustr
);
1469 m_xMEdit
->set_text(m_pHelper
->getCurrentFormula());
1470 sal_Int32 PrivStart
, PrivEnd
;
1471 m_pHelper
->getSelection( PrivStart
, PrivEnd
);
1472 m_aFuncSel
.Min() = PrivStart
;
1473 m_aFuncSel
.Max() = PrivEnd
;
1475 OUString aFormula
= m_xMEdit
->get_text();
1476 sal_Int32 nArgPos
= m_aFormulaHelper
.GetArgStart( aFormula
, PrivStart
, 0);
1478 sal_uInt16 nPos
= m_xParaWin
->GetActiveLine();
1479 if (nPos
>= m_aArguments
.size())
1481 SAL_WARN("formula.ui","FormulaDlg_Impl::UpdateSelection - shot in foot: nPos " <<
1482 nPos
<< " >= m_aArguments.size() " << m_aArguments
.size() <<
1483 " for aFormula '" << aFormula
<< "'");
1484 nPos
= m_aArguments
.size();
1489 for (sal_uInt16 i
= 0; i
< nPos
; i
++)
1491 nArgPos
+= (m_aArguments
[i
].getLength() + 1);
1493 sal_Int32 nLength
= (nPos
< m_aArguments
.size()) ? m_aArguments
[nPos
].getLength() : 0;
1495 m_pHelper
->setSelection(nArgPos
, nArgPos
+ nLength
);
1496 m_xMEdit
->select_region(nArgPos
, nArgPos
+ nLength
);
1500 ::std::pair
<RefButton
*, RefEdit
*> FormulaDlg_Impl::RefInputStartBefore(RefEdit
* pEdit
, RefButton
* pButton
)
1502 m_pTheRefEdit
= pEdit
;
1503 m_pTheRefButton
= pButton
;
1505 Selection aOrigSelection
;
1508 // grab selection before showing next widget in case the selection is blown away
1510 aOrigSelection
= m_pTheRefEdit
->GetSelection();
1513 // because its initially hidden, give it its optimal size so clicking the
1514 // refbutton has an initial size to work when retro-fitting this to .ui
1515 m_xEdRef
->GetWidget()->set_size_request(m_xEdRef
->GetWidget()->get_preferred_size().Width(), -1);
1516 m_xEdRef
->GetWidget()->show();
1518 if ( m_pTheRefEdit
)
1520 m_xEdRef
->SetRefString(m_pTheRefEdit
->GetText());
1521 m_xEdRef
->SetSelection(aOrigSelection
);
1522 m_xEdRef
->GetWidget()->set_help_id(m_pTheRefEdit
->GetWidget()->get_help_id());
1525 m_xRefBtn
->GetWidget()->set_visible(pButton
!= nullptr);
1527 ::std::pair
<RefButton
*, RefEdit
*> aPair
;
1528 aPair
.first
= pButton
? m_xRefBtn
.get() : nullptr;
1529 aPair
.second
= m_xEdRef
.get();
1533 void FormulaDlg_Impl::RefInputStartAfter()
1535 m_xRefBtn
->SetEndImage();
1540 OUString aStr
= m_aTitle2
+ " " + m_xFtEditName
->get_label() + "( ";
1542 if ( m_xParaWin
->GetActiveLine() > 0 )
1544 aStr
+= m_xParaWin
->GetActiveArgName();
1545 if ( m_xParaWin
->GetActiveLine() + 1 < m_nArgs
)
1549 m_rDialog
.set_title(m_rDialog
.strip_mnemonic(aStr
));
1552 void FormulaDlg_Impl::RefInputDoneAfter( bool bForced
)
1554 m_xRefBtn
->SetStartImage();
1555 if (!bForced
&& m_xRefBtn
->GetWidget()->get_visible())
1558 m_xEdRef
->GetWidget()->hide();
1559 m_xRefBtn
->GetWidget()->hide();
1560 if ( m_pTheRefEdit
)
1562 m_pTheRefEdit
->SetRefString( m_xEdRef
->GetText() );
1563 m_pTheRefEdit
->GrabFocus();
1565 if ( m_pTheRefButton
)
1566 m_pTheRefButton
->SetStartImage();
1568 sal_uInt16 nPrivActiv
= m_xParaWin
->GetActiveLine();
1569 m_xParaWin
->SetArgument( nPrivActiv
, m_xEdRef
->GetText() );
1570 ModifyHdl( *m_xParaWin
);
1571 m_pTheRefEdit
= nullptr;
1573 m_rDialog
.set_title(m_aTitle1
);
1576 RefEdit
* FormulaDlg_Impl::GetCurrRefEdit()
1578 return m_xEdRef
->GetWidget()->get_visible() ? m_xEdRef
.get() : m_xParaWin
->GetActiveEdit();
1581 void FormulaDlg_Impl::Update()
1583 FormEditData
* pData
= m_pHelper
->getFormEditData();
1584 const OUString sExpression
= m_xMEdit
->get_text();
1585 m_aOldFormula
.clear();
1586 UpdateTokenArray(sExpression
);
1588 CalcStruct(sExpression
);
1589 if (pData
->GetMode() == FormulaDlgMode::Formula
)
1590 m_xTabCtrl
->set_current_page(u
"functiontab"_ustr
);
1592 m_xTabCtrl
->set_current_page(u
"structtab"_ustr
);
1593 m_xBtnMatrix
->set_active(pData
->GetMatrixFlag());
1596 void FormulaDlg_Impl::Update(const OUString
& _sExp
)
1600 FuncSelHdl(*m_xFuncPage
);
1603 void FormulaDlg_Impl::SetMeText(const OUString
& _sText
)
1605 FormEditData
* pData
= m_pHelper
->getFormEditData();
1606 m_xMEdit
->set_text(_sText
);
1607 auto aSelection
= pData
->GetSelection();
1608 m_xMEdit
->select_region(aSelection
.Min(), aSelection
.Max());
1612 FormulaDlgMode
FormulaDlg_Impl::SetMeText( const OUString
& _sText
, sal_Int32 PrivStart
, sal_Int32 PrivEnd
, bool bMatrix
, bool _bSelect
, bool _bUpdate
)
1614 FormulaDlgMode eMode
= FormulaDlgMode::Formula
;
1616 m_xMEdit
->set_text(_sText
);
1618 if ( _bSelect
|| !m_bEditFlag
)
1619 m_xMEdit
->select_region(PrivStart
, PrivEnd
);
1623 int nStartPos
, nEndPos
;
1624 m_xMEdit
->get_selection_bounds(nStartPos
, nEndPos
);
1625 if (nStartPos
> nEndPos
)
1626 std::swap(nStartPos
, nEndPos
);
1627 m_pHelper
->showReference(m_xMEdit
->get_text().copy(nStartPos
, nEndPos
- nStartPos
));
1628 eMode
= FormulaDlgMode::Edit
;
1630 m_xBtnMatrix
->set_active( bMatrix
);
1631 } // if ( _bUpdate )
1635 bool FormulaDlg_Impl::CheckMatrix(OUString
& aFormula
)
1637 m_xMEdit
->grab_focus();
1638 sal_Int32 nLen
= aFormula
.getLength();
1639 bool bMatrix
= nLen
> 3 // Matrix-Formula
1640 && aFormula
[0] == '{'
1641 && aFormula
[1] == '='
1642 && aFormula
[nLen
-1] == '}';
1645 aFormula
= aFormula
.copy( 1, aFormula
.getLength()-2 );
1646 m_xBtnMatrix
->set_active( bMatrix
);
1647 m_xBtnMatrix
->set_sensitive(false);
1650 m_xTabCtrl
->set_current_page(u
"structtab"_ustr
);
1654 IMPL_LINK_NOARG( FormulaDlg_Impl
, StructSelHdl
, StructPage
&, void)
1656 m_bStructUpdate
= false;
1657 if (m_xStructPage
->IsVisible())
1658 m_xBtnForward
->set_sensitive(false); //@New
1659 m_bStructUpdate
= true;
1662 IMPL_LINK_NOARG( FormulaDlg_Impl
, MatrixHdl
, weld::Toggleable
&, void)
1664 m_bUserMatrixFlag
= true;
1668 IMPL_LINK_NOARG( FormulaDlg_Impl
, FuncSelHdl
, FuncPage
&, void)
1670 if ( (m_xFuncPage
->GetFunctionEntryCount() > 0)
1671 && (m_xFuncPage
->GetFunction() != -1) )
1673 const IFunctionDescription
* pDesc
= m_xFuncPage
->GetFuncDesc();
1675 if (pDesc
!= m_pFuncDesc
)
1676 m_xBtnForward
->set_sensitive(true); //new
1680 pDesc
->initArgumentInfo(); // full argument info is needed
1682 OUString aSig
= pDesc
->getSignature();
1683 m_xFtHeadLine
->set_label( pDesc
->getFunctionName() );
1684 m_xFtFuncName
->set_label( aSig
);
1685 m_xFtFuncDesc
->set_label( pDesc
->getDescription() );
1690 m_xFtHeadLine
->set_label( OUString() );
1691 m_xFtFuncName
->set_label( OUString() );
1692 m_xFtFuncDesc
->set_label( OUString() );
1696 void FormulaDlg_Impl::UpdateParaWin( const Selection
& _rSelection
, const OUString
& _sRefStr
)
1698 Selection theSel
= _rSelection
;
1699 m_xEdRef
->GetWidget()->replace_selection(_sRefStr
);
1700 theSel
.Max() = theSel
.Min() + _sRefStr
.getLength();
1701 m_xEdRef
->SetSelection( theSel
);
1704 // Manual Update of the results' fields:
1706 sal_uInt16 nPrivActiv
= m_xParaWin
->GetActiveLine();
1707 m_xParaWin
->SetArgument( nPrivActiv
, m_xEdRef
->GetText());
1708 m_xParaWin
->UpdateParas();
1710 RefEdit
* pEd
= GetCurrRefEdit();
1712 pEd
->SetSelection( theSel
);
1715 bool FormulaDlg_Impl::UpdateParaWin(Selection
& _rSelection
)
1718 RefEdit
* pEd
= GetCurrRefEdit();
1719 if (pEd
&& !m_pTheRefEdit
)
1721 _rSelection
= pEd
->GetSelection();
1722 _rSelection
.Normalize();
1723 aStrEd
= pEd
->GetText();
1724 m_xEdRef
->SetRefString(aStrEd
);
1725 m_xEdRef
->SetSelection( _rSelection
);
1729 _rSelection
= m_xEdRef
->GetSelection();
1730 _rSelection
.Normalize();
1731 aStrEd
= m_xEdRef
->GetText();
1733 return m_pTheRefEdit
== nullptr;
1736 void FormulaDlg_Impl::SetEdSelection()
1738 RefEdit
* pEd
= GetCurrRefEdit()/*aScParaWin.GetActiveEdit()*/;
1741 Selection theSel
= m_xEdRef
->GetSelection();
1742 // Edit may have the focus -> call ModifyHdl in addition
1743 // to what's happening in GetFocus
1744 pEd
->GetModifyHdl().Call(*pEd
);
1746 pEd
->SetSelection(theSel
);
1750 FormulaModalDialog::FormulaModalDialog(weld::Window
* pParent
,
1751 IFunctionManager
const * _pFunctionMgr
,
1752 IControlReferenceHandler
* _pDlg
)
1753 : GenericDialogController(pParent
, u
"formula/ui/formuladialog.ui"_ustr
, u
"FormulaDialog"_ustr
)
1754 , m_pImpl(new FormulaDlg_Impl(*m_xDialog
, *m_xBuilder
, false/*_bSupportFunctionResult*/,
1755 false/*_bSupportResult*/, false/*_bSupportMatrix*/,
1756 this, _pFunctionMgr
, _pDlg
))
1758 m_xDialog
->set_title(m_pImpl
->m_aTitle1
);
1761 FormulaModalDialog::~FormulaModalDialog() { }
1763 void FormulaModalDialog::Update(const OUString
& _sExp
)
1765 m_pImpl
->Update(_sExp
);
1768 void FormulaModalDialog::SetMeText(const OUString
& _sText
)
1770 m_pImpl
->SetMeText(_sText
);
1773 void FormulaModalDialog::CheckMatrix(OUString
& aFormula
)
1775 m_pImpl
->CheckMatrix(aFormula
);
1778 void FormulaModalDialog::Update()
1783 ::std::pair
<RefButton
*, RefEdit
*> FormulaModalDialog::RefInputStartBefore( RefEdit
* pEdit
, RefButton
* pButton
)
1785 return m_pImpl
->RefInputStartBefore( pEdit
, pButton
);
1788 void FormulaModalDialog::RefInputStartAfter()
1790 m_pImpl
->RefInputStartAfter();
1793 void FormulaModalDialog::RefInputDoneAfter()
1795 m_pImpl
->RefInputDoneAfter( true/*bForced*/ );
1798 void FormulaModalDialog::StoreFormEditData(FormEditData
* pData
)
1800 m_pImpl
->StoreFormEditData(pData
);
1803 // Initialisation / General functions for Dialog
1804 FormulaDlg::FormulaDlg(SfxBindings
* pB
, SfxChildWindow
* pCW
,
1805 weld::Window
* pParent
,
1806 IFunctionManager
const * _pFunctionMgr
, IControlReferenceHandler
* _pDlg
)
1807 : SfxModelessDialogController( pB
, pCW
, pParent
, u
"formula/ui/formuladialog.ui"_ustr
, u
"FormulaDialog"_ustr
)
1808 , m_pImpl(new FormulaDlg_Impl(*m_xDialog
, *m_xBuilder
, true/*_bSupportFunctionResult*/
1809 , true/*_bSupportResult*/
1810 , true/*_bSupportMatrix*/
1811 , this, _pFunctionMgr
, _pDlg
))
1813 m_xDialog
->set_title(m_pImpl
->m_aTitle1
);
1816 FormulaDlg::~FormulaDlg()
1820 void FormulaDlg::Update(const OUString
& _sExp
)
1822 m_pImpl
->Update(_sExp
);
1825 void FormulaDlg::SetMeText(const OUString
& _sText
)
1827 m_pImpl
->SetMeText(_sText
);
1830 FormulaDlgMode
FormulaDlg::SetMeText( const OUString
& _sText
, sal_Int32 PrivStart
, sal_Int32 PrivEnd
, bool bMatrix
, bool _bSelect
, bool _bUpdate
)
1832 return m_pImpl
->SetMeText( _sText
, PrivStart
, PrivEnd
, bMatrix
, _bSelect
, _bUpdate
);
1835 bool FormulaDlg::CheckMatrix(OUString
& aFormula
)
1837 return m_pImpl
->CheckMatrix(aFormula
);
1840 OUString
FormulaDlg::GetMeText() const
1842 return m_pImpl
->m_xMEdit
->get_text();
1845 void FormulaDlg::Update()
1850 void FormulaDlg::DoEnter()
1852 m_pImpl
->DoEnter(false);
1855 ::std::pair
<RefButton
*, RefEdit
*> FormulaDlg::RefInputStartBefore( RefEdit
* pEdit
, RefButton
* pButton
)
1857 return m_pImpl
->RefInputStartBefore( pEdit
, pButton
);
1860 void FormulaDlg::RefInputStartAfter()
1862 m_pImpl
->RefInputStartAfter();
1865 void FormulaDlg::RefInputDoneAfter( bool bForced
)
1867 m_pImpl
->RefInputDoneAfter( bForced
);
1870 void FormulaDlg::disableOk()
1872 m_pImpl
->m_xBtnEnd
->set_sensitive(false);
1875 void FormulaDlg::StoreFormEditData(FormEditData
* pData
)
1877 m_pImpl
->StoreFormEditData(pData
);
1880 const IFunctionDescription
* FormulaDlg::getCurrentFunctionDescription() const
1882 SAL_WARN_IF( (m_pImpl
->m_pFuncDesc
&& m_pImpl
->m_pFuncDesc
->getSuppressedArgumentCount() != m_pImpl
->m_nArgs
),
1883 "formula.ui", "FormulaDlg::getCurrentFunctionDescription: getSuppressedArgumentCount " <<
1884 m_pImpl
->m_pFuncDesc
->getSuppressedArgumentCount() << " != m_nArgs " << m_pImpl
->m_nArgs
<< " for " <<
1885 m_pImpl
->m_pFuncDesc
->getFunctionName());
1886 return m_pImpl
->m_pFuncDesc
;
1889 void FormulaDlg::UpdateParaWin( const Selection
& _rSelection
, const OUString
& _sRefStr
)
1891 m_pImpl
->UpdateParaWin( _rSelection
, _sRefStr
);
1894 bool FormulaDlg::UpdateParaWin(Selection
& _rSelection
)
1896 return m_pImpl
->UpdateParaWin(_rSelection
);
1899 RefEdit
* FormulaDlg::GetActiveEdit()
1901 return m_pImpl
->m_xParaWin
->GetActiveEdit();
1904 const FormulaHelper
& FormulaDlg::GetFormulaHelper() const
1906 return m_pImpl
->GetFormulaHelper();
1909 void FormulaDlg::SetEdSelection()
1911 m_pImpl
->SetEdSelection();
1914 void FormEditData::SaveValues()
1919 void FormEditData::Reset()
1921 nMode
= FormulaDlgMode::Formula
;
1925 aSelection
.Min() = 0;
1926 aSelection
.Max() = 0;
1930 FormEditData
& FormEditData::operator=( const FormEditData
& r
)
1933 nFStart
= r
.nFStart
;
1934 nOffset
= r
.nOffset
;
1935 aUndoStr
= r
.aUndoStr
;
1936 bMatrix
= r
.bMatrix
;
1937 aSelection
= r
.aSelection
;
1941 FormEditData::FormEditData()
1946 FormEditData::~FormEditData()
1950 FormEditData::FormEditData( const FormEditData
& r
)
1959 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */