solenv/clang-format/excludelist | 1 vcl/Library_vcl.mk | 1 vcl/source/control/FieldFormatter.hxx | 68 ++++++++ vcl/source/control/FormattedField.cxx | 265 ++++++++++++++++++++++++++++++++++ vcl/source/control/fmtfield.cxx | 229 ----------------------------- 5 files changed, 338 insertions(+), 226 deletions(-)
New commits: commit 8b998ed161f0c7e72530e5f02aa9be13edb4f703 Author: Christopher Sherlock <chris.sherloc...@gmail.com> AuthorDate: Mon Dec 23 16:24:15 2024 +1100 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Tue Feb 25 08:53:46 2025 +0100 vcl: move FormattedField to own file Change-Id: I00e0734ff06c307377e04e2b4d61c637616068b2 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/179184 Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> Tested-by: Jenkins diff --git a/solenv/clang-format/excludelist b/solenv/clang-format/excludelist index b4ccc7e98f2a..e0dbabc2be18 100644 --- a/solenv/clang-format/excludelist +++ b/solenv/clang-format/excludelist @@ -14554,6 +14554,7 @@ vcl/source/cnttype/mcnttype.hxx vcl/source/components/dtranscomp.cxx vcl/source/components/factory.cxx vcl/source/components/fontident.cxx +vcl/source/control/FormattedField.cxx vcl/source/control/button.cxx vcl/source/control/calendar.cxx vcl/source/control/combobox.cxx diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index 483fcc5fe8b0..db63b6e6ba9d 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -236,6 +236,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/control/fixedhyper \ vcl/source/control/hyperlabel \ vcl/source/control/fmtfield \ + vcl/source/control/FormattedField \ vcl/source/control/InterimItemWindow \ vcl/source/control/imgctrl \ vcl/source/control/imivctl1 \ diff --git a/vcl/source/control/FieldFormatter.hxx b/vcl/source/control/FieldFormatter.hxx new file mode 100644 index 000000000000..6b7c164bb701 --- /dev/null +++ b/vcl/source/control/FieldFormatter.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 . + */ + +#include <tools/gen.hxx> + +#include <vcl/toolkit/fmtfield.hxx> + +class FieldFormatter : public Formatter +{ +private: + FormattedField& m_rSpinButton; + +public: + FieldFormatter(FormattedField& rSpinButton) + : m_rSpinButton(rSpinButton) + { + } + + // Formatter overrides + virtual Selection GetEntrySelection() const override { return m_rSpinButton.GetSelection(); } + + virtual OUString GetEntryText() const override { return m_rSpinButton.GetText(); } + + void SetEntryText(const OUString& rText, const Selection& rSel) override + { + m_rSpinButton.SpinField::SetText(rText, rSel); + } + + virtual void SetEntryTextColor(const ::Color* pColor) override + { + if (pColor) + m_rSpinButton.SetControlForeground(*pColor); + else + m_rSpinButton.SetControlForeground(); + } + + virtual SelectionOptions GetEntrySelectionOptions() const override + { + return m_rSpinButton.GetSettings().GetStyleSettings().GetSelectionOptions(); + } + + virtual void FieldModified() override { m_rSpinButton.SpinField::Modify(); } + + virtual void UpdateCurrentValue(double dCurrentValue) override + { + Formatter::UpdateCurrentValue(dCurrentValue); + m_rSpinButton.SetUpperEnabled(!m_bHasMax || dCurrentValue < m_dMaxValue); + m_rSpinButton.SetLowerEnabled(!m_bHasMin || dCurrentValue > m_dMinValue); + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/source/control/FormattedField.cxx b/vcl/source/control/FormattedField.cxx new file mode 100644 index 000000000000..c67e289ffa2b --- /dev/null +++ b/vcl/source/control/FormattedField.cxx @@ -0,0 +1,265 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 . + */ + +#include <rtl/math.hxx> +#include <svl/numformat.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/string.hxx> +#include <tools/debug.hxx> + +#include <vcl/builder.hxx> +#include <vcl/event.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/toolkit/fmtfield.hxx> +#include <vcl/uitest/formattedfielduiobject.hxx> +#include <vcl/weldutils.hxx> + +#include "FieldFormatter.hxx" + +#include <svl/zformat.hxx> + +#include <limits> + +FormattedField::FormattedField(vcl::Window* pParent, WinBits nStyle) + : SpinField(pParent, nStyle, WindowType::FORMATTEDFIELD) + , m_pFormatter(nullptr) +{ +} + +void FormattedField::dispose() +{ + m_pFormatter = nullptr; + m_xOwnFormatter.reset(); + SpinField::dispose(); +} + +void FormattedField::SetText(const OUString& rStr) +{ + GetFormatter().SetFieldText(rStr, Selection(0, 0)); +} + +void FormattedField::SetText(const OUString& rStr, const Selection& rNewSelection) +{ + GetFormatter().SetFieldText(rStr, rNewSelection); + SetSelection(rNewSelection); +} + +bool FormattedField::set_property(const OUString &rKey, const OUString &rValue) +{ + if (rKey == "digits") + GetFormatter().SetDecimalDigits(rValue.toInt32()); + else if (rKey == "wrap") + GetFormatter().SetWrapOnLimits(toBool(rValue)); + else + return SpinField::set_property(rKey, rValue); + return true; +} + +void FormattedField::Up() +{ + Formatter& rFormatter = GetFormatter(); + auto nScale = weld::SpinButton::Power10(rFormatter.GetDecimalDigits()); + + sal_Int64 nValue = std::round(rFormatter.GetValue() * nScale); + sal_Int64 nSpinSize = std::round(rFormatter.GetSpinSize() * nScale); + assert(nSpinSize != 0); + sal_Int64 nRemainder = rFormatter.GetDisableRemainderFactor() || nSpinSize == 0 ? 0 : nValue % nSpinSize; + if (nValue >= 0) + nValue = (nRemainder == 0) ? nValue + nSpinSize : nValue + nSpinSize - nRemainder; + else + nValue = (nRemainder == 0) ? nValue + nSpinSize : nValue - nRemainder; + + // setValue handles under- and overflows (min/max) automatically + rFormatter.SetValue(static_cast<double>(nValue) / nScale); + SetModifyFlag(); + Modify(); + + SpinField::Up(); +} + +void FormattedField::Down() +{ + Formatter& rFormatter = GetFormatter(); + auto nScale = weld::SpinButton::Power10(rFormatter.GetDecimalDigits()); + + sal_Int64 nValue = std::round(rFormatter.GetValue() * nScale); + sal_Int64 nSpinSize = std::round(rFormatter.GetSpinSize() * nScale); + assert(nSpinSize != 0); + sal_Int64 nRemainder = rFormatter.GetDisableRemainderFactor() || nSpinSize == 0 ? 0 : nValue % nSpinSize; + if (nValue >= 0) + nValue = (nRemainder == 0) ? nValue - nSpinSize : nValue - nRemainder; + else + nValue = (nRemainder == 0) ? nValue - nSpinSize : nValue - nSpinSize - nRemainder; + + // setValue handles under- and overflows (min/max) automatically + rFormatter.SetValue(static_cast<double>(nValue) / nScale); + SetModifyFlag(); + Modify(); + + SpinField::Down(); +} + +void FormattedField::First() +{ + Formatter& rFormatter = GetFormatter(); + if (rFormatter.HasMinValue()) + { + rFormatter.SetValue(rFormatter.GetMinValue()); + SetModifyFlag(); + Modify(); + } + + SpinField::First(); +} + +void FormattedField::Last() +{ + Formatter& rFormatter = GetFormatter(); + if (rFormatter.HasMaxValue()) + { + rFormatter.SetValue(rFormatter.GetMaxValue()); + SetModifyFlag(); + Modify(); + } + + SpinField::Last(); +} + +void FormattedField::Modify() +{ + GetFormatter().Modify(); +} + +bool FormattedField::PreNotify(NotifyEvent& rNEvt) +{ + if (rNEvt.GetType() == NotifyEventType::KEYINPUT) + GetFormatter().SetLastSelection(GetSelection()); + return SpinField::PreNotify(rNEvt); +} + +bool FormattedField::EventNotify(NotifyEvent& rNEvt) +{ + if ((rNEvt.GetType() == NotifyEventType::KEYINPUT) && !IsReadOnly()) + { + const KeyEvent& rKEvt = *rNEvt.GetKeyEvent(); + sal_uInt16 nMod = rKEvt.GetKeyCode().GetModifier(); + switch ( rKEvt.GetKeyCode().GetCode() ) + { + case KEY_UP: + case KEY_DOWN: + case KEY_PAGEUP: + case KEY_PAGEDOWN: + { + Formatter& rFormatter = GetFormatter(); + if (!nMod && rFormatter.GetOrCreateFormatter().IsTextFormat(rFormatter.GetFormatKey())) + { + // the base class would translate this into calls to Up/Down/First/Last, + // but we don't want this if we are text-formatted + return true; + } + } + } + } + + if ((rNEvt.GetType() == NotifyEventType::COMMAND) && !IsReadOnly()) + { + const CommandEvent* pCommand = rNEvt.GetCommandEvent(); + if (pCommand->GetCommand() == CommandEventId::Wheel) + { + const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData(); + Formatter& rFormatter = GetFormatter(); + if ((pData->GetMode() == CommandWheelMode::SCROLL) && + rFormatter.GetOrCreateFormatter().IsTextFormat(rFormatter.GetFormatKey())) + { + // same as above : prevent the base class from doing Up/Down-calls + // (normally I should put this test into the Up/Down methods itself, shouldn't I ?) + // FS - 71553 - 19.01.00 + return true; + } + } + } + + if (rNEvt.GetType() == NotifyEventType::LOSEFOCUS && m_pFormatter) + m_pFormatter->EntryLostFocus(); + + return SpinField::EventNotify( rNEvt ); +} + +Formatter& FormattedField::GetFormatter() +{ + if (!m_pFormatter) + { + m_xOwnFormatter.reset(new FieldFormatter(*this)); + m_pFormatter = m_xOwnFormatter.get(); + } + return *m_pFormatter; +} + +void FormattedField::SetFormatter(Formatter* pFormatter) +{ + m_xOwnFormatter.reset(); + m_pFormatter = pFormatter; +} + +// currently used by online +void FormattedField::SetValueFromString(const OUString& rStr) +{ + sal_Int32 nEnd; + rtl_math_ConversionStatus eStatus; + Formatter& rFormatter = GetFormatter(); + double fValue = ::rtl::math::stringToDouble(rStr, '.', rFormatter.GetDecimalDigits(), &eStatus, &nEnd ); + + if (eStatus == rtl_math_ConversionStatus_Ok && + nEnd == rStr.getLength()) + { + rFormatter.SetValue(fValue); + SetModifyFlag(); + Modify(); + + // Notify the value has changed + SpinField::Up(); + } + else + { + SAL_WARN("vcl", "fail to convert the value: " << rStr); + } +} + +void FormattedField::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) +{ + SpinField::DumpAsPropertyTree(rJsonWriter); + Formatter& rFormatter = GetFormatter(); + + if (dynamic_cast<weld::TimeFormatter*>(&rFormatter)) + { + // weld::TimeFormatter uses h24 format + rJsonWriter.put("type", "time"); + } + rJsonWriter.put("min", rFormatter.GetMinValue()); + rJsonWriter.put("max", rFormatter.GetMaxValue()); + rJsonWriter.put("value", rFormatter.GetValue()); + rJsonWriter.put("step", rFormatter.GetSpinSize()); +} + +FactoryFunction FormattedField::GetUITestFactory() const +{ + return FormattedFieldUIObject::create; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/source/control/fmtfield.cxx b/vcl/source/control/fmtfield.cxx index 6b83403e2931..bf6888b6ce77 100644 --- a/vcl/source/control/fmtfield.cxx +++ b/vcl/source/control/fmtfield.cxx @@ -29,6 +29,9 @@ #include <vcl/toolkit/fmtfield.hxx> #include <vcl/uitest/formattedfielduiobject.hxx> #include <vcl/weldutils.hxx> + +#include "FieldFormatter.hxx" + #include <svl/zformat.hxx> #include <limits> @@ -1147,230 +1150,4 @@ void DoubleCurrencyField::UpdateCurrencyFormat() static_cast<DoubleCurrencyFormatter*>(m_pFormatter)->GuardSetFormat(sNewFormat.makeStringAndClear(), eLanguage); } -FormattedField::FormattedField(vcl::Window* pParent, WinBits nStyle) - : SpinField(pParent, nStyle, WindowType::FORMATTEDFIELD) - , m_pFormatter(nullptr) -{ -} - -void FormattedField::dispose() -{ - m_pFormatter = nullptr; - m_xOwnFormatter.reset(); - SpinField::dispose(); -} - -void FormattedField::SetText(const OUString& rStr) -{ - GetFormatter().SetFieldText(rStr, Selection(0, 0)); -} - -void FormattedField::SetText(const OUString& rStr, const Selection& rNewSelection) -{ - GetFormatter().SetFieldText(rStr, rNewSelection); - SetSelection(rNewSelection); -} - -bool FormattedField::set_property(const OUString &rKey, const OUString &rValue) -{ - if (rKey == "digits") - GetFormatter().SetDecimalDigits(rValue.toInt32()); - else if (rKey == "wrap") - GetFormatter().SetWrapOnLimits(toBool(rValue)); - else - return SpinField::set_property(rKey, rValue); - return true; -} - -void FormattedField::Up() -{ - Formatter& rFormatter = GetFormatter(); - auto nScale = weld::SpinButton::Power10(rFormatter.GetDecimalDigits()); - - sal_Int64 nValue = std::round(rFormatter.GetValue() * nScale); - sal_Int64 nSpinSize = std::round(rFormatter.GetSpinSize() * nScale); - assert(nSpinSize != 0); - sal_Int64 nRemainder = rFormatter.GetDisableRemainderFactor() || nSpinSize == 0 ? 0 : nValue % nSpinSize; - if (nValue >= 0) - nValue = (nRemainder == 0) ? nValue + nSpinSize : nValue + nSpinSize - nRemainder; - else - nValue = (nRemainder == 0) ? nValue + nSpinSize : nValue - nRemainder; - - // setValue handles under- and overflows (min/max) automatically - rFormatter.SetValue(static_cast<double>(nValue) / nScale); - SetModifyFlag(); - Modify(); - - SpinField::Up(); -} - -void FormattedField::Down() -{ - Formatter& rFormatter = GetFormatter(); - auto nScale = weld::SpinButton::Power10(rFormatter.GetDecimalDigits()); - - sal_Int64 nValue = std::round(rFormatter.GetValue() * nScale); - sal_Int64 nSpinSize = std::round(rFormatter.GetSpinSize() * nScale); - assert(nSpinSize != 0); - sal_Int64 nRemainder = rFormatter.GetDisableRemainderFactor() || nSpinSize == 0 ? 0 : nValue % nSpinSize; - if (nValue >= 0) - nValue = (nRemainder == 0) ? nValue - nSpinSize : nValue - nRemainder; - else - nValue = (nRemainder == 0) ? nValue - nSpinSize : nValue - nSpinSize - nRemainder; - - // setValue handles under- and overflows (min/max) automatically - rFormatter.SetValue(static_cast<double>(nValue) / nScale); - SetModifyFlag(); - Modify(); - - SpinField::Down(); -} - -void FormattedField::First() -{ - Formatter& rFormatter = GetFormatter(); - if (rFormatter.HasMinValue()) - { - rFormatter.SetValue(rFormatter.GetMinValue()); - SetModifyFlag(); - Modify(); - } - - SpinField::First(); -} - -void FormattedField::Last() -{ - Formatter& rFormatter = GetFormatter(); - if (rFormatter.HasMaxValue()) - { - rFormatter.SetValue(rFormatter.GetMaxValue()); - SetModifyFlag(); - Modify(); - } - - SpinField::Last(); -} - -void FormattedField::Modify() -{ - GetFormatter().Modify(); -} - -bool FormattedField::PreNotify(NotifyEvent& rNEvt) -{ - if (rNEvt.GetType() == NotifyEventType::KEYINPUT) - GetFormatter().SetLastSelection(GetSelection()); - return SpinField::PreNotify(rNEvt); -} - -bool FormattedField::EventNotify(NotifyEvent& rNEvt) -{ - if ((rNEvt.GetType() == NotifyEventType::KEYINPUT) && !IsReadOnly()) - { - const KeyEvent& rKEvt = *rNEvt.GetKeyEvent(); - sal_uInt16 nMod = rKEvt.GetKeyCode().GetModifier(); - switch ( rKEvt.GetKeyCode().GetCode() ) - { - case KEY_UP: - case KEY_DOWN: - case KEY_PAGEUP: - case KEY_PAGEDOWN: - { - Formatter& rFormatter = GetFormatter(); - if (!nMod && rFormatter.GetOrCreateFormatter().IsTextFormat(rFormatter.GetFormatKey())) - { - // the base class would translate this into calls to Up/Down/First/Last, - // but we don't want this if we are text-formatted - return true; - } - } - } - } - - if ((rNEvt.GetType() == NotifyEventType::COMMAND) && !IsReadOnly()) - { - const CommandEvent* pCommand = rNEvt.GetCommandEvent(); - if (pCommand->GetCommand() == CommandEventId::Wheel) - { - const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData(); - Formatter& rFormatter = GetFormatter(); - if ((pData->GetMode() == CommandWheelMode::SCROLL) && - rFormatter.GetOrCreateFormatter().IsTextFormat(rFormatter.GetFormatKey())) - { - // same as above : prevent the base class from doing Up/Down-calls - // (normally I should put this test into the Up/Down methods itself, shouldn't I ?) - // FS - 71553 - 19.01.00 - return true; - } - } - } - - if (rNEvt.GetType() == NotifyEventType::LOSEFOCUS && m_pFormatter) - m_pFormatter->EntryLostFocus(); - - return SpinField::EventNotify( rNEvt ); -} - -Formatter& FormattedField::GetFormatter() -{ - if (!m_pFormatter) - { - m_xOwnFormatter.reset(new FieldFormatter(*this)); - m_pFormatter = m_xOwnFormatter.get(); - } - return *m_pFormatter; -} - -void FormattedField::SetFormatter(Formatter* pFormatter) -{ - m_xOwnFormatter.reset(); - m_pFormatter = pFormatter; -} - -// currently used by online -void FormattedField::SetValueFromString(const OUString& rStr) -{ - sal_Int32 nEnd; - rtl_math_ConversionStatus eStatus; - Formatter& rFormatter = GetFormatter(); - double fValue = ::rtl::math::stringToDouble(rStr, '.', rFormatter.GetDecimalDigits(), &eStatus, &nEnd ); - - if (eStatus == rtl_math_ConversionStatus_Ok && - nEnd == rStr.getLength()) - { - rFormatter.SetValue(fValue); - SetModifyFlag(); - Modify(); - - // Notify the value has changed - SpinField::Up(); - } - else - { - SAL_WARN("vcl", "fail to convert the value: " << rStr); - } -} - -void FormattedField::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) -{ - SpinField::DumpAsPropertyTree(rJsonWriter); - Formatter& rFormatter = GetFormatter(); - - if (dynamic_cast<weld::TimeFormatter*>(&rFormatter)) - { - // weld::TimeFormatter uses h24 format - rJsonWriter.put("type", "time"); - } - rJsonWriter.put("min", rFormatter.GetMinValue()); - rJsonWriter.put("max", rFormatter.GetMaxValue()); - rJsonWriter.put("value", rFormatter.GetValue()); - rJsonWriter.put("step", rFormatter.GetSpinSize()); -} - -FactoryFunction FormattedField::GetUITestFactory() const -{ - return FormattedFieldUIObject::create; -} - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */