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 .
20 #undef SC_DLLIMPLEMENTATION
23 #include <tpformula.hxx>
24 #include <formulaopt.hxx>
26 #include <strings.hrc>
27 #include <scresid.hxx>
28 #include <formula/grammar.hxx>
29 #include <officecfg/Office/Calc.hxx>
30 #include "calcoptionsdlg.hxx"
32 #include <unotools/localedatawrapper.hxx>
34 ScTpFormulaOptions::ScTpFormulaOptions(weld::Container
* pPage
, weld::DialogController
* pController
, const SfxItemSet
& rCoreAttrs
)
35 : SfxTabPage(pPage
, pController
, u
"modules/scalc/ui/optformula.ui"_ustr
, u
"OptFormula"_ustr
, &rCoreAttrs
)
37 , mxLbFormulaSyntax(m_xBuilder
->weld_combo_box(u
"formulasyntax"_ustr
))
38 , mxCbEnglishFuncName(m_xBuilder
->weld_check_button(u
"englishfuncname"_ustr
))
39 , mxBtnCustomCalcDefault(m_xBuilder
->weld_radio_button(u
"calcdefault"_ustr
))
40 , mxBtnCustomCalcCustom(m_xBuilder
->weld_radio_button(u
"calccustom"_ustr
))
41 , mxBtnCustomCalcDetails(m_xBuilder
->weld_button(u
"details"_ustr
))
42 , mxEdSepFuncArg(m_xBuilder
->weld_entry(u
"function"_ustr
))
43 , mxEdSepArrayCol(m_xBuilder
->weld_entry(u
"arraycolumn"_ustr
))
44 , mxEdSepArrayRow(m_xBuilder
->weld_entry(u
"arrayrow"_ustr
))
45 , mxBtnSepReset(m_xBuilder
->weld_button(u
"reset"_ustr
))
46 , mxLbOOXMLRecalcOptions(m_xBuilder
->weld_combo_box(u
"ooxmlrecalc"_ustr
))
47 , mxLbODFRecalcOptions(m_xBuilder
->weld_combo_box(u
"odfrecalc"_ustr
))
48 , mxLbRowHeightReCalcOptions(m_xBuilder
->weld_combo_box(u
"rowheightrecalc"_ustr
))
50 mxLbFormulaSyntax
->append_text(ScResId(SCSTR_FORMULA_SYNTAX_CALC_A1
));
51 mxLbFormulaSyntax
->append_text(ScResId(SCSTR_FORMULA_SYNTAX_XL_A1
));
52 mxLbFormulaSyntax
->append_text(ScResId(SCSTR_FORMULA_SYNTAX_XL_R1C1
));
54 Link
<weld::Button
&,void> aLink2
= LINK( this, ScTpFormulaOptions
, ButtonHdl
);
55 mxBtnSepReset
->connect_clicked(aLink2
);
56 mxBtnCustomCalcDetails
->connect_clicked(aLink2
);
58 Link
<weld::Toggleable
&,void> aToggleLink
= LINK( this, ScTpFormulaOptions
, ToggleHdl
);
59 mxBtnCustomCalcDefault
->connect_toggled(aToggleLink
);
60 mxBtnCustomCalcCustom
->connect_toggled(aToggleLink
);
62 mxEdSepFuncArg
->connect_insert_text(LINK( this, ScTpFormulaOptions
, SepInsertTextHdl
));
63 mxEdSepArrayCol
->connect_insert_text(LINK( this, ScTpFormulaOptions
, ColSepInsertTextHdl
));
64 mxEdSepArrayRow
->connect_insert_text(LINK( this, ScTpFormulaOptions
, RowSepInsertTextHdl
));
66 Link
<weld::Entry
&,void> aLink
= LINK( this, ScTpFormulaOptions
, SepModifyHdl
);
67 mxEdSepFuncArg
->connect_changed(aLink
);
68 mxEdSepArrayCol
->connect_changed(aLink
);
69 mxEdSepArrayRow
->connect_changed(aLink
);
71 Link
<weld::Widget
&,void> aLink3
= LINK( this, ScTpFormulaOptions
, SepEditOnFocusHdl
);
72 mxEdSepFuncArg
->connect_focus_in(aLink3
);
73 mxEdSepArrayCol
->connect_focus_in(aLink3
);
74 mxEdSepArrayRow
->connect_focus_in(aLink3
);
76 // Get the decimal separator for current locale.
77 OUString aSep
= ScGlobal::getLocaleData().getNumDecimalSep();
78 mnDecSep
= aSep
.isEmpty() ? u
'.' : aSep
[0];
80 maSavedDocOptions
= rCoreAttrs
.Get(SID_SCDOCOPTIONS
).GetDocOptions();
83 ScTpFormulaOptions::~ScTpFormulaOptions()
87 void ScTpFormulaOptions::ResetSeparators()
89 OUString aFuncArg
, aArrayCol
, aArrayRow
;
90 ScFormulaOptions::GetDefaultFormulaSeparators(aFuncArg
, aArrayCol
, aArrayRow
);
91 mxEdSepFuncArg
->set_text(aFuncArg
);
92 mxEdSepArrayCol
->set_text(aArrayCol
);
93 mxEdSepArrayRow
->set_text(aArrayRow
);
96 void ScTpFormulaOptions::OnFocusSeparatorInput(weld::Entry
* pEdit
)
101 // Make sure the entire text is selected.
102 pEdit
->select_region(0, -1);
103 OUString sSepValue
= pEdit
->get_text();
104 if (!sSepValue
.isEmpty())
105 maOldSepValue
= sSepValue
;
108 void ScTpFormulaOptions::UpdateCustomCalcRadioButtons(bool bDefault
)
112 mxBtnCustomCalcDefault
->set_active(true);
113 mxBtnCustomCalcCustom
->set_active(false);
114 mxBtnCustomCalcDetails
->set_sensitive(false);
118 mxBtnCustomCalcDefault
->set_active(false);
119 mxBtnCustomCalcCustom
->set_active(true);
120 mxBtnCustomCalcDetails
->set_sensitive(true);
124 void ScTpFormulaOptions::LaunchCustomCalcSettings()
126 ScCalcOptionsDialog
aDlg(GetFrameWeld(), maCurrentConfig
, maCurrentDocOptions
.IsWriteCalcConfig());
127 if (aDlg
.run() == RET_OK
)
129 maCurrentConfig
= aDlg
.GetConfig();
130 maCurrentDocOptions
.SetWriteCalcConfig(aDlg
.GetWriteCalcConfig());
134 bool ScTpFormulaOptions::IsValidSeparator(std::u16string_view aSep
, bool bArray
) const
136 if (aSep
.size() != 1)
137 // Must be one-character long.
140 const sal_Unicode c
= aSep
[0];
143 // decimal separator is not allowed.
146 if (c
<= 0x20 || c
== 0x7f)
147 // Disallow non-printables including space and DEL.
150 if (('a' <= c
&& c
<= 'z') || ('A' <= c
&& c
<= 'Z') || ('0' <= c
&& c
<= '9'))
151 // Disallow alphanumeric.
163 // All following just to prevent confusion, they are not
164 // evaluated in inline arrays and theoretically would be
177 // Disallowed characters. Anything else we want to disallow ?
186 // Anything bad except the knowns.
195 // Any Unicode character, would have to ask the compiler's localized
196 // symbol map whether it's a known symbol but not a separator
197 // (ocSep,ocArrayRowSep,ocArrayColSep), which we're about to set here.
205 IMPL_LINK( ScTpFormulaOptions
, ButtonHdl
, weld::Button
&, rBtn
, void )
207 if (&rBtn
== mxBtnSepReset
.get())
209 else if (&rBtn
== mxBtnCustomCalcDetails
.get())
210 LaunchCustomCalcSettings();
213 IMPL_LINK( ScTpFormulaOptions
, ToggleHdl
, weld::Toggleable
&, rBtn
, void )
215 if (!rBtn
.get_active())
217 if (mxBtnCustomCalcDefault
->get_active())
218 UpdateCustomCalcRadioButtons(true);
219 else if (mxBtnCustomCalcCustom
->get_active())
220 UpdateCustomCalcRadioButtons(false);
223 IMPL_LINK(ScTpFormulaOptions
, SepInsertTextHdl
, OUString
&, rTest
, bool)
225 if (!IsValidSeparator(rTest
, false) && !maOldSepValue
.isEmpty())
226 // Invalid separator. Restore the old value.
227 rTest
= maOldSepValue
;
231 IMPL_LINK(ScTpFormulaOptions
, RowSepInsertTextHdl
, OUString
&, rTest
, bool)
233 // Invalid separator or same as ColStr - Restore the old value.
234 if ((!IsValidSeparator(rTest
, true) || rTest
== mxEdSepArrayCol
->get_text()) && !maOldSepValue
.isEmpty())
235 rTest
= maOldSepValue
;
239 IMPL_LINK(ScTpFormulaOptions
, ColSepInsertTextHdl
, OUString
&, rTest
, bool)
241 // Invalid separator or same as RowStr - Restore the old value.
242 if ((!IsValidSeparator(rTest
, true) || rTest
== mxEdSepArrayRow
->get_text()) && !maOldSepValue
.isEmpty())
243 rTest
= maOldSepValue
;
247 IMPL_LINK( ScTpFormulaOptions
, SepModifyHdl
, weld::Entry
&, rEdit
, void )
249 OnFocusSeparatorInput(&rEdit
);
252 IMPL_LINK( ScTpFormulaOptions
, SepEditOnFocusHdl
, weld::Widget
&, rControl
, void )
254 OnFocusSeparatorInput(dynamic_cast<weld::Entry
*>(&rControl
));
257 std::unique_ptr
<SfxTabPage
> ScTpFormulaOptions::Create(weld::Container
* pPage
, weld::DialogController
* pController
, const SfxItemSet
* rCoreSet
)
259 return std::make_unique
<ScTpFormulaOptions
>(pPage
, pController
, *rCoreSet
);
262 OUString
ScTpFormulaOptions::GetAllStrings()
264 OUString sAllStrings
;
265 OUString labels
[] = { u
"label1"_ustr
, u
"formulasyntaxlabel"_ustr
,
266 u
"label3"_ustr
, u
"label6"_ustr
,
267 u
"label7"_ustr
, u
"label8"_ustr
,
268 u
"label2"_ustr
, u
"label4"_ustr
,
269 u
"label9"_ustr
, u
"label10"_ustr
};
271 for (const auto& label
: labels
)
273 if (const auto pString
= m_xBuilder
->weld_label(label
))
274 sAllStrings
+= pString
->get_label() + " ";
277 OUString radioButton
[] = { u
"calcdefault"_ustr
, u
"calccustom"_ustr
};
279 for (const auto& radio
: radioButton
)
281 if (const auto pString
= m_xBuilder
->weld_radio_button(radio
))
282 sAllStrings
+= pString
->get_label() + " ";
285 OUString buttons
[] = { u
"reset"_ustr
, u
"details"_ustr
};
287 for (const auto& btn
: buttons
)
289 if (const auto pString
= m_xBuilder
->weld_button(btn
))
290 sAllStrings
+= pString
->get_label() + " ";
294 sAllStrings
+= mxCbEnglishFuncName
->get_label() + " ";
296 return sAllStrings
.replaceAll("_", "");
299 bool ScTpFormulaOptions::FillItemSet(SfxItemSet
* rCoreSet
)
302 ScFormulaOptions aOpt
;
303 bool bEnglishFuncName
= mxCbEnglishFuncName
->get_active();
304 sal_Int16 aSyntaxPos
= mxLbFormulaSyntax
->get_active();
305 OUString aSep
= mxEdSepFuncArg
->get_text();
306 OUString aSepArrayCol
= mxEdSepArrayCol
->get_text();
307 OUString aSepArrayRow
= mxEdSepArrayRow
->get_text();
308 sal_Int16 nOOXMLRecalcMode
= mxLbOOXMLRecalcOptions
->get_active();
309 sal_Int16 nODFRecalcMode
= mxLbODFRecalcOptions
->get_active();
310 sal_Int16 nReCalcOptRowHeights
= mxLbRowHeightReCalcOptions
->get_active();
312 if (mxBtnCustomCalcDefault
->get_active())
314 // When Default is selected, reset all the calc config settings to default.
315 maCurrentConfig
.reset();
318 if ( mxLbFormulaSyntax
->get_saved_value() != mxLbFormulaSyntax
->get_text(aSyntaxPos
)
319 || mxCbEnglishFuncName
->get_saved_state() != (bEnglishFuncName
? 1 : 0)
320 || mxEdSepFuncArg
->get_saved_value() != aSep
321 || mxEdSepArrayCol
->get_saved_value() != aSepArrayCol
322 || mxEdSepArrayRow
->get_saved_value() != aSepArrayRow
323 || mxLbOOXMLRecalcOptions
->get_saved_value() != mxLbOOXMLRecalcOptions
->get_text(nOOXMLRecalcMode
)
324 || mxLbODFRecalcOptions
->get_saved_value() != mxLbODFRecalcOptions
->get_text(nODFRecalcMode
)
325 || mxLbRowHeightReCalcOptions
->get_saved_value() != mxLbRowHeightReCalcOptions
->get_text(nReCalcOptRowHeights
)
326 || maSavedConfig
!= maCurrentConfig
327 || maSavedDocOptions
!= maCurrentDocOptions
)
329 ::formula::FormulaGrammar::Grammar eGram
= ::formula::FormulaGrammar::GRAM_DEFAULT
;
334 eGram
= ::formula::FormulaGrammar::GRAM_NATIVE
;
337 eGram
= ::formula::FormulaGrammar::GRAM_NATIVE_XL_A1
;
340 eGram
= ::formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1
;
344 ScRecalcOptions eOOXMLRecalc
= static_cast<ScRecalcOptions
>(nOOXMLRecalcMode
);
345 ScRecalcOptions eODFRecalc
= static_cast<ScRecalcOptions
>(nODFRecalcMode
);
346 ScRecalcOptions eReCalcOptRowHeights
= static_cast<ScRecalcOptions
>(nReCalcOptRowHeights
);
348 aOpt
.SetFormulaSyntax(eGram
);
349 aOpt
.SetUseEnglishFuncName(bEnglishFuncName
);
350 aOpt
.SetFormulaSepArg(aSep
);
351 aOpt
.SetFormulaSepArrayCol(aSepArrayCol
);
352 aOpt
.SetFormulaSepArrayRow(aSepArrayRow
);
353 aOpt
.SetCalcConfig(maCurrentConfig
);
354 aOpt
.SetOOXMLRecalcOptions(eOOXMLRecalc
);
355 aOpt
.SetODFRecalcOptions(eODFRecalc
);
356 aOpt
.SetReCalcOptiRowHeights(eReCalcOptRowHeights
);
357 aOpt
.SetWriteCalcConfig( maCurrentDocOptions
.IsWriteCalcConfig());
359 rCoreSet
->Put( ScTpFormulaItem( std::move(aOpt
) ) );
360 rCoreSet
->Put( ScTpCalcItem( SID_SCDOCOPTIONS
, maCurrentDocOptions
) );
367 void ScTpFormulaOptions::Reset(const SfxItemSet
* rCoreSet
)
369 ScFormulaOptions aOpt
;
370 if(const ScTpFormulaItem
* pItem
= rCoreSet
->GetItemIfSet(SID_SCFORMULAOPTIONS
, false))
371 aOpt
= pItem
->GetFormulaOptions();
374 ::formula::FormulaGrammar::Grammar eGram
= aOpt
.GetFormulaSyntax();
378 case ::formula::FormulaGrammar::GRAM_NATIVE
:
379 mxLbFormulaSyntax
->set_active(0);
381 case ::formula::FormulaGrammar::GRAM_NATIVE_XL_A1
:
382 mxLbFormulaSyntax
->set_active(1);
384 case ::formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1
:
385 mxLbFormulaSyntax
->set_active(2);
388 mxLbFormulaSyntax
->set_active(0);
391 mxLbFormulaSyntax
->save_value();
392 mxLbFormulaSyntax
->set_sensitive( !officecfg::Office::Calc::Formula::Syntax::Grammar::isReadOnly() );
394 ScRecalcOptions eOOXMLRecalc
= aOpt
.GetOOXMLRecalcOptions();
395 mxLbOOXMLRecalcOptions
->set_active(static_cast<sal_uInt16
>(eOOXMLRecalc
));
396 mxLbOOXMLRecalcOptions
->save_value();
397 mxLbOOXMLRecalcOptions
->set_sensitive( !officecfg::Office::Calc::Formula::Load::OOXMLRecalcMode::isReadOnly() );
399 ScRecalcOptions eODFRecalc
= aOpt
.GetODFRecalcOptions();
400 mxLbODFRecalcOptions
->set_active(static_cast<sal_uInt16
>(eODFRecalc
));
401 mxLbODFRecalcOptions
->save_value();
402 mxLbODFRecalcOptions
->set_sensitive( !officecfg::Office::Calc::Formula::Load::ODFRecalcMode::isReadOnly() );
404 // Recalc optimal row heights at load
405 ScRecalcOptions eReCalcOptRowHeights
= aOpt
.GetReCalcOptiRowHeights();
406 mxLbRowHeightReCalcOptions
->set_active(static_cast<sal_uInt16
>(eReCalcOptRowHeights
));
407 mxLbRowHeightReCalcOptions
->save_value();
408 mxLbRowHeightReCalcOptions
->set_sensitive(
409 !officecfg::Office::Calc::Formula::Load::RecalcOptimalRowHeightMode::isReadOnly() );
411 // english function name.
412 mxCbEnglishFuncName
->set_active( aOpt
.GetUseEnglishFuncName() );
413 mxCbEnglishFuncName
->save_state();
414 mxCbEnglishFuncName
->set_sensitive( !officecfg::Office::Calc::Formula::Syntax::EnglishFunctionName::isReadOnly() );
417 OUString aSep
= aOpt
.GetFormulaSepArg();
418 OUString aSepArrayRow
= aOpt
.GetFormulaSepArrayRow();
419 OUString aSepArrayCol
= aOpt
.GetFormulaSepArrayCol();
421 if (IsValidSeparator(aSep
, false) && IsValidSeparator(aSepArrayRow
, true) && IsValidSeparator(aSepArrayCol
, true))
423 // Each and all separators must be valid.
424 mxEdSepFuncArg
->set_text(aSep
);
425 mxEdSepArrayCol
->set_text(aSepArrayCol
);
426 mxEdSepArrayRow
->set_text(aSepArrayRow
);
428 mxEdSepFuncArg
->save_value();
429 mxEdSepArrayCol
->save_value();
430 mxEdSepArrayRow
->save_value();
435 mxEdSepFuncArg
->set_sensitive( !officecfg::Office::Calc::Formula::Syntax::SeparatorArg::isReadOnly() );
436 mxEdSepArrayCol
->set_sensitive( !officecfg::Office::Calc::Formula::Syntax::SeparatorArrayCol::isReadOnly() );
437 mxEdSepArrayRow
->set_sensitive( !officecfg::Office::Calc::Formula::Syntax::SeparatorArrayRow::isReadOnly() );
438 mxBtnSepReset
->set_sensitive ( !officecfg::Office::Calc::Formula::Syntax::SeparatorArg::isReadOnly() &&
439 !officecfg::Office::Calc::Formula::Syntax::SeparatorArrayCol::isReadOnly() &&
440 !officecfg::Office::Calc::Formula::Syntax::SeparatorArrayRow::isReadOnly() );
442 // detailed calc settings.
443 ScFormulaOptions aDefaults
;
445 maSavedConfig
= aOpt
.GetCalcConfig();
446 bool bDefault
= aDefaults
.GetCalcConfig() == maSavedConfig
;
447 UpdateCustomCalcRadioButtons(bDefault
);
449 maCurrentConfig
= maSavedConfig
;
451 maCurrentDocOptions
= maSavedDocOptions
;
454 DeactivateRC
ScTpFormulaOptions::DeactivatePage(SfxItemSet
* /*pSet*/)
456 // What's this method for ?
457 return DeactivateRC::KeepPage
;
460 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */