/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #undef SC_DLLIMPLEMENTATION #include #include #include #include #include #include #include #include #include "calcoptionsdlg.hxx" #include ScTpFormulaOptions::ScTpFormulaOptions(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs) : SfxTabPage(pPage, pController, "modules/scalc/ui/optformula.ui", "OptFormula", &rCoreAttrs) , mnDecSep(0) , mxLbFormulaSyntax(m_xBuilder->weld_combo_box("formulasyntax")) , mxCbEnglishFuncName(m_xBuilder->weld_check_button("englishfuncname")) , mxBtnCustomCalcDefault(m_xBuilder->weld_radio_button("calcdefault")) , mxBtnCustomCalcCustom(m_xBuilder->weld_radio_button("calccustom")) , mxBtnCustomCalcDetails(m_xBuilder->weld_button("details")) , mxEdSepFuncArg(m_xBuilder->weld_entry("function")) , mxEdSepArrayCol(m_xBuilder->weld_entry("arraycolumn")) , mxEdSepArrayRow(m_xBuilder->weld_entry("arrayrow")) , mxBtnSepReset(m_xBuilder->weld_button("reset")) , mxLbOOXMLRecalcOptions(m_xBuilder->weld_combo_box("ooxmlrecalc")) , mxLbODFRecalcOptions(m_xBuilder->weld_combo_box("odfrecalc")) { mxLbFormulaSyntax->append_text(ScResId(SCSTR_FORMULA_SYNTAX_CALC_A1)); mxLbFormulaSyntax->append_text(ScResId(SCSTR_FORMULA_SYNTAX_XL_A1)); mxLbFormulaSyntax->append_text(ScResId(SCSTR_FORMULA_SYNTAX_XL_R1C1)); Link aLink2 = LINK( this, ScTpFormulaOptions, ButtonHdl ); mxBtnSepReset->connect_clicked(aLink2); mxBtnCustomCalcDetails->connect_clicked(aLink2); Link aToggleLink = LINK( this, ScTpFormulaOptions, ToggleHdl ); mxBtnCustomCalcDefault->connect_toggled(aToggleLink); mxBtnCustomCalcCustom->connect_toggled(aToggleLink); mxEdSepFuncArg->connect_insert_text(LINK( this, ScTpFormulaOptions, SepInsertTextHdl )); mxEdSepArrayCol->connect_insert_text(LINK( this, ScTpFormulaOptions, ColSepInsertTextHdl )); mxEdSepArrayRow->connect_insert_text(LINK( this, ScTpFormulaOptions, RowSepInsertTextHdl )); Link aLink = LINK( this, ScTpFormulaOptions, SepModifyHdl ); mxEdSepFuncArg->connect_changed(aLink); mxEdSepArrayCol->connect_changed(aLink); mxEdSepArrayRow->connect_changed(aLink); Link aLink3 = LINK( this, ScTpFormulaOptions, SepEditOnFocusHdl ); mxEdSepFuncArg->connect_focus_in(aLink3); mxEdSepArrayCol->connect_focus_in(aLink3); mxEdSepArrayRow->connect_focus_in(aLink3); // Get the decimal separator for current locale. OUString aSep = ScGlobal::getLocaleData().getNumDecimalSep(); mnDecSep = aSep.isEmpty() ? u'.' : aSep[0]; maSavedDocOptions = rCoreAttrs.Get(SID_SCDOCOPTIONS).GetDocOptions(); } ScTpFormulaOptions::~ScTpFormulaOptions() { } void ScTpFormulaOptions::ResetSeparators() { OUString aFuncArg, aArrayCol, aArrayRow; ScFormulaOptions::GetDefaultFormulaSeparators(aFuncArg, aArrayCol, aArrayRow); mxEdSepFuncArg->set_text(aFuncArg); mxEdSepArrayCol->set_text(aArrayCol); mxEdSepArrayRow->set_text(aArrayRow); } void ScTpFormulaOptions::OnFocusSeparatorInput(weld::Entry* pEdit) { if (!pEdit) return; // Make sure the entire text is selected. pEdit->select_region(0, -1); OUString sSepValue = pEdit->get_text(); if (!sSepValue.isEmpty()) maOldSepValue = sSepValue; } void ScTpFormulaOptions::UpdateCustomCalcRadioButtons(bool bDefault) { if (bDefault) { mxBtnCustomCalcDefault->set_active(true); mxBtnCustomCalcCustom->set_active(false); mxBtnCustomCalcDetails->set_sensitive(false); } else { mxBtnCustomCalcDefault->set_active(false); mxBtnCustomCalcCustom->set_active(true); mxBtnCustomCalcDetails->set_sensitive(true); } } void ScTpFormulaOptions::LaunchCustomCalcSettings() { ScCalcOptionsDialog aDlg(GetFrameWeld(), maCurrentConfig, maCurrentDocOptions.IsWriteCalcConfig()); if (aDlg.run() == RET_OK) { maCurrentConfig = aDlg.GetConfig(); maCurrentDocOptions.SetWriteCalcConfig(aDlg.GetWriteCalcConfig()); } } bool ScTpFormulaOptions::IsValidSeparator(std::u16string_view aSep, bool bArray) const { if (aSep.size() != 1) // Must be one-character long. return false; const sal_Unicode c = aSep[0]; if (c == mnDecSep) // decimal separator is not allowed. return false; if (c <= 0x20 || c == 0x7f) // Disallow non-printables including space and DEL. return false; if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9')) // Disallow alphanumeric. return false; if (bArray) { switch (c) { case '+': case '-': case '{': case '}': case '"': // All following just to prevent confusion, they are not // evaluated in inline arrays and theoretically would be // possible. case '%': case '/': case '*': case '=': case '<': case '>': case '[': case ']': case '(': case ')': case '\'': // Disallowed characters. Anything else we want to disallow ? return false; } } else if (c <= 0x7f) { switch (c) { default: // Anything bad except the knowns. return false; case ';': case ',': ; // nothing } } else { // Any Unicode character, would have to ask the compiler's localized // symbol map whether it's a known symbol but not a separator // (ocSep,ocArrayRowSep,ocArrayColSep), which we're about to set here. // But really.. return false; } return true; } IMPL_LINK( ScTpFormulaOptions, ButtonHdl, weld::Button&, rBtn, void ) { if (&rBtn == mxBtnSepReset.get()) ResetSeparators(); else if (&rBtn == mxBtnCustomCalcDetails.get()) LaunchCustomCalcSettings(); } IMPL_LINK( ScTpFormulaOptions, ToggleHdl, weld::Toggleable&, rBtn, void ) { if (!rBtn.get_active()) return; if (mxBtnCustomCalcDefault->get_active()) UpdateCustomCalcRadioButtons(true); else if (mxBtnCustomCalcCustom->get_active()) UpdateCustomCalcRadioButtons(false); } IMPL_LINK(ScTpFormulaOptions, SepInsertTextHdl, OUString&, rTest, bool) { if (!IsValidSeparator(rTest, false) && !maOldSepValue.isEmpty()) // Invalid separator. Restore the old value. rTest = maOldSepValue; return true; } IMPL_LINK(ScTpFormulaOptions, RowSepInsertTextHdl, OUString&, rTest, bool) { // Invalid separator or same as ColStr - Restore the old value. if ((!IsValidSeparator(rTest, true) || rTest == mxEdSepArrayCol->get_text()) && !maOldSepValue.isEmpty()) rTest = maOldSepValue; return true; } IMPL_LINK(ScTpFormulaOptions, ColSepInsertTextHdl, OUString&, rTest, bool) { // Invalid separator or same as RowStr - Restore the old value. if ((!IsValidSeparator(rTest, true) || rTest == mxEdSepArrayRow->get_text()) && !maOldSepValue.isEmpty()) rTest = maOldSepValue; return true; } IMPL_LINK( ScTpFormulaOptions, SepModifyHdl, weld::Entry&, rEdit, void ) { OnFocusSeparatorInput(&rEdit); } IMPL_LINK( ScTpFormulaOptions, SepEditOnFocusHdl, weld::Widget&, rControl, void ) { OnFocusSeparatorInput(dynamic_cast(&rControl)); } std::unique_ptr ScTpFormulaOptions::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet) { return std::make_unique(pPage, pController, *rCoreSet); } OUString ScTpFormulaOptions::GetAllStrings() { OUString sAllStrings; OUString labels[] = { "label1", "formulasyntaxlabel", "label3", "label6", "label7", "label8", "label2", "label4", "label9", "label10" }; for (const auto& label : labels) { if (const auto& pString = m_xBuilder->weld_label(label)) sAllStrings += pString->get_label() + " "; } OUString radioButton[] = { "calcdefault", "calccustom" }; for (const auto& radio : radioButton) { if (const auto& pString = m_xBuilder->weld_radio_button(radio)) sAllStrings += pString->get_label() + " "; } OUString buttons[] = { "reset", "details" }; for (const auto& btn : buttons) { if (const auto& pString = m_xBuilder->weld_button(btn)) sAllStrings += pString->get_label() + " "; } // check button sAllStrings += mxCbEnglishFuncName->get_label() + " "; return sAllStrings.replaceAll("_", ""); } bool ScTpFormulaOptions::FillItemSet(SfxItemSet* rCoreSet) { bool bRet = false; ScFormulaOptions aOpt; bool bEnglishFuncName = mxCbEnglishFuncName->get_active(); sal_Int16 aSyntaxPos = mxLbFormulaSyntax->get_active(); OUString aSep = mxEdSepFuncArg->get_text(); OUString aSepArrayCol = mxEdSepArrayCol->get_text(); OUString aSepArrayRow = mxEdSepArrayRow->get_text(); sal_Int16 nOOXMLRecalcMode = mxLbOOXMLRecalcOptions->get_active(); sal_Int16 nODFRecalcMode = mxLbODFRecalcOptions->get_active(); if (mxBtnCustomCalcDefault->get_active()) { // When Default is selected, reset all the calc config settings to default. maCurrentConfig.reset(); } if ( mxLbFormulaSyntax->get_saved_value() != mxLbFormulaSyntax->get_text(aSyntaxPos) || mxCbEnglishFuncName->get_saved_state() != (bEnglishFuncName ? 1 : 0) || mxEdSepFuncArg->get_saved_value() != aSep || mxEdSepArrayCol->get_saved_value() != aSepArrayCol || mxEdSepArrayRow->get_saved_value() != aSepArrayRow || mxLbOOXMLRecalcOptions->get_saved_value() != mxLbOOXMLRecalcOptions->get_text(nOOXMLRecalcMode) || mxLbODFRecalcOptions->get_saved_value() != mxLbODFRecalcOptions->get_text(nODFRecalcMode) || maSavedConfig != maCurrentConfig || maSavedDocOptions != maCurrentDocOptions ) { ::formula::FormulaGrammar::Grammar eGram = ::formula::FormulaGrammar::GRAM_DEFAULT; switch (aSyntaxPos) { case 0: eGram = ::formula::FormulaGrammar::GRAM_NATIVE; break; case 1: eGram = ::formula::FormulaGrammar::GRAM_NATIVE_XL_A1; break; case 2: eGram = ::formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1; break; } ScRecalcOptions eOOXMLRecalc = static_cast(nOOXMLRecalcMode); ScRecalcOptions eODFRecalc = static_cast(nODFRecalcMode); aOpt.SetFormulaSyntax(eGram); aOpt.SetUseEnglishFuncName(bEnglishFuncName); aOpt.SetFormulaSepArg(aSep); aOpt.SetFormulaSepArrayCol(aSepArrayCol); aOpt.SetFormulaSepArrayRow(aSepArrayRow); aOpt.SetCalcConfig(maCurrentConfig); aOpt.SetOOXMLRecalcOptions(eOOXMLRecalc); aOpt.SetODFRecalcOptions(eODFRecalc); aOpt.SetWriteCalcConfig( maCurrentDocOptions.IsWriteCalcConfig()); rCoreSet->Put( ScTpFormulaItem( std::move(aOpt) ) ); rCoreSet->Put( ScTpCalcItem( SID_SCDOCOPTIONS, maCurrentDocOptions ) ); bRet = true; } return bRet; } void ScTpFormulaOptions::Reset(const SfxItemSet* rCoreSet) { ScFormulaOptions aOpt; if(const ScTpFormulaItem* pItem = rCoreSet->GetItemIfSet(SID_SCFORMULAOPTIONS, false)) aOpt = pItem->GetFormulaOptions(); // formula grammar. ::formula::FormulaGrammar::Grammar eGram = aOpt.GetFormulaSyntax(); switch (eGram) { case ::formula::FormulaGrammar::GRAM_NATIVE: mxLbFormulaSyntax->set_active(0); break; case ::formula::FormulaGrammar::GRAM_NATIVE_XL_A1: mxLbFormulaSyntax->set_active(1); break; case ::formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1: mxLbFormulaSyntax->set_active(2); break; default: mxLbFormulaSyntax->set_active(0); } mxLbFormulaSyntax->save_value(); mxLbFormulaSyntax->set_sensitive( !officecfg::Office::Calc::Formula::Syntax::Grammar::isReadOnly() ); ScRecalcOptions eOOXMLRecalc = aOpt.GetOOXMLRecalcOptions(); mxLbOOXMLRecalcOptions->set_active(static_cast(eOOXMLRecalc)); mxLbOOXMLRecalcOptions->save_value(); mxLbOOXMLRecalcOptions->set_sensitive( !officecfg::Office::Calc::Formula::Load::OOXMLRecalcMode::isReadOnly() ); ScRecalcOptions eODFRecalc = aOpt.GetODFRecalcOptions(); mxLbODFRecalcOptions->set_active(static_cast(eODFRecalc)); mxLbODFRecalcOptions->save_value(); mxLbODFRecalcOptions->set_sensitive( !officecfg::Office::Calc::Formula::Load::ODFRecalcMode::isReadOnly() ); // english function name. mxCbEnglishFuncName->set_active( aOpt.GetUseEnglishFuncName() ); mxCbEnglishFuncName->save_state(); mxCbEnglishFuncName->set_sensitive( !officecfg::Office::Calc::Formula::Syntax::EnglishFunctionName::isReadOnly() ); // Separators OUString aSep = aOpt.GetFormulaSepArg(); OUString aSepArrayRow = aOpt.GetFormulaSepArrayRow(); OUString aSepArrayCol = aOpt.GetFormulaSepArrayCol(); if (IsValidSeparator(aSep, false) && IsValidSeparator(aSepArrayRow, true) && IsValidSeparator(aSepArrayCol, true)) { // Each and all separators must be valid. mxEdSepFuncArg->set_text(aSep); mxEdSepArrayCol->set_text(aSepArrayCol); mxEdSepArrayRow->set_text(aSepArrayRow); mxEdSepFuncArg->save_value(); mxEdSepArrayCol->save_value(); mxEdSepArrayRow->save_value(); } else ResetSeparators(); mxEdSepFuncArg->set_sensitive( !officecfg::Office::Calc::Formula::Syntax::SeparatorArg::isReadOnly() ); mxEdSepArrayCol->set_sensitive( !officecfg::Office::Calc::Formula::Syntax::SeparatorArrayCol::isReadOnly() ); mxEdSepArrayRow->set_sensitive( !officecfg::Office::Calc::Formula::Syntax::SeparatorArrayRow::isReadOnly() ); mxBtnSepReset->set_sensitive ( !officecfg::Office::Calc::Formula::Syntax::SeparatorArg::isReadOnly() && !officecfg::Office::Calc::Formula::Syntax::SeparatorArrayCol::isReadOnly() && !officecfg::Office::Calc::Formula::Syntax::SeparatorArrayRow::isReadOnly() ); // detailed calc settings. ScFormulaOptions aDefaults; maSavedConfig = aOpt.GetCalcConfig(); bool bDefault = aDefaults.GetCalcConfig() == maSavedConfig; UpdateCustomCalcRadioButtons(bDefault); maCurrentConfig = maSavedConfig; maCurrentDocOptions = maSavedDocOptions; } DeactivateRC ScTpFormulaOptions::DeactivatePage(SfxItemSet* /*pSet*/) { // What's this method for ? return DeactivateRC::KeepPage; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */