diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /extensions/source/propctrlr/standardcontrol.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream/4%7.4.7.tar.xz libreoffice-upstream/4%7.4.7.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | extensions/source/propctrlr/standardcontrol.cxx | 865 |
1 files changed, 865 insertions, 0 deletions
diff --git a/extensions/source/propctrlr/standardcontrol.cxx b/extensions/source/propctrlr/standardcontrol.cxx new file mode 100644 index 000000000..95b4143c7 --- /dev/null +++ b/extensions/source/propctrlr/standardcontrol.cxx @@ -0,0 +1,865 @@ +/* -*- 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 . + */ + +#include "standardcontrol.hxx" +#include "pcrcommon.hxx" + +#include <com/sun/star/beans/IllegalTypeException.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/util/Time.hpp> +#include <com/sun/star/util/Color.hpp> +#include <com/sun/star/util/MeasureUnit.hpp> +#include <com/sun/star/inspection/PropertyControlType.hpp> +#include <comphelper/string.hxx> +#include <o3tl/float_int_conversion.hxx> +#include <toolkit/helper/vclunohelper.hxx> + + +// ugly dependencies for the OColorControl +#include <svx/svxids.hrc> + +#include <tools/datetime.hxx> +#include <unotools/datetime.hxx> +#include <o3tl/string_view.hxx> + +#include <limits> +#include <memory> + +namespace pcr +{ + using namespace ::com::sun::star; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::inspection; + + //= OTimeControl + OTimeControl::OTimeControl(std::unique_ptr<weld::FormattedSpinButton> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly) + : OTimeControl_Base(PropertyControlType::TimeField, std::move(xBuilder), std::move(xWidget), bReadOnly) + , m_xFormatter(new weld::TimeFormatter(*getTypedControlWindow())) + { + m_xFormatter->SetExtFormat(ExtTimeFieldFormat::LongDuration); + } + + void SAL_CALL OTimeControl::setValue( const Any& _rValue ) + { + util::Time aUNOTime; + if ( !( _rValue >>= aUNOTime ) ) + { + getTypedControlWindow()->set_text(""); + m_xFormatter->SetTime(tools::Time(tools::Time::EMPTY)); + } + else + { + m_xFormatter->SetTime(::tools::Time(aUNOTime)); + } + } + + Any SAL_CALL OTimeControl::getValue() + { + Any aPropValue; + if ( !getTypedControlWindow()->get_text().isEmpty() ) + { + aPropValue <<= m_xFormatter->GetTime().GetUNOTime(); + } + return aPropValue; + } + + Type SAL_CALL OTimeControl::getValueType() + { + return ::cppu::UnoType<util::Time>::get(); + } + + //= ODateControl + ODateControl::ODateControl(std::unique_ptr<weld::Container> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly) + : ODateControl_Base(PropertyControlType::DateField, std::move(xBuilder), std::move(xWidget), bReadOnly) + , m_xEntry(m_xBuilder->weld_entry("entry")) + , m_xCalendarBox(std::make_unique<SvtCalendarBox>(m_xBuilder->weld_menu_button("button"), false)) + { + m_xEntryFormatter.reset(new weld::DateFormatter(*m_xEntry)); + + m_xEntryFormatter->SetStrictFormat(true); + m_xEntryFormatter->SetMin(::Date(1, 1, 1600)); + m_xEntryFormatter->SetMax(::Date(1, 1, 9999)); + + m_xEntryFormatter->SetExtDateFormat(ExtDateFieldFormat::SystemShortYYYY); + m_xEntryFormatter->EnableEmptyField(true); + + m_xCalendarBox->connect_activated(LINK(this, ODateControl, ActivateHdl)); + + m_xCalendarBox->get_button().connect_toggled(LINK(this, ODateControl, ToggleHdl)); + } + + void SAL_CALL ODateControl::disposing() + { + m_xEntryFormatter.reset(); + m_xEntry.reset(); + m_xCalendarBox.reset(); + ODateControl_Base::disposing(); + } + + void SAL_CALL ODateControl::setValue( const Any& _rValue ) + { + util::Date aUNODate; + if ( !( _rValue >>= aUNODate ) ) + { + m_xEntry->set_text(OUString()); + } + else + { + ::Date aDate( aUNODate.Day, aUNODate.Month, aUNODate.Year ); + m_xEntryFormatter->SetDate(aDate); + } + } + + IMPL_LINK_NOARG(ODateControl, ActivateHdl, SvtCalendarBox&, void) + { + m_xEntryFormatter->SetDate(m_xCalendarBox->get_date()); + setModified(); + m_xEntry->grab_focus(); + } + + IMPL_LINK(ODateControl, ToggleHdl, weld::Toggleable&, rToggle, void) + { + if (!rToggle.get_active()) + return; + ::Date aDate = m_xEntryFormatter->GetDate(); + if (aDate.IsEmpty()) + { + // with an empty date preselect today in the calendar + aDate = ::Date(::Date::SYSTEM); + } + m_xCalendarBox->set_date(aDate); + } + + Any SAL_CALL ODateControl::getValue() + { + Any aPropValue; + if (!m_xEntry->get_text().isEmpty()) + { + ::Date aDate(m_xEntryFormatter->GetDate()); + aPropValue <<= aDate.GetUNODate(); + } + return aPropValue; + } + + Type SAL_CALL ODateControl::getValueType() + { + return ::cppu::UnoType<util::Date>::get(); + } + + //= OEditControl + OEditControl::OEditControl(std::unique_ptr<weld::Entry> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bPW, bool bReadOnly) + : OEditControl_Base( bPW ? PropertyControlType::CharacterField : PropertyControlType::TextField, std::move(xBuilder), std::move(xWidget), bReadOnly ) + { + m_bIsPassword = bPW; + + auto pWidget = getTypedControlWindow(); + pWidget->set_sensitive(true); + pWidget->set_editable(!bReadOnly); + + if (m_bIsPassword) + pWidget->set_max_length( 1 ); + } + + void SAL_CALL OEditControl::setValue( const Any& _rValue ) + { + OUString sText; + if ( m_bIsPassword ) + { + sal_Int16 nValue = 0; + _rValue >>= nValue; + if ( nValue ) + { + sText = OUString(static_cast<sal_Unicode>(nValue)); + } + } + else + _rValue >>= sText; + + getTypedControlWindow()->set_text( sText ); + } + + Any SAL_CALL OEditControl::getValue() + { + Any aPropValue; + + OUString sText( getTypedControlWindow()->get_text() ); + if ( m_bIsPassword ) + { + if ( !sText.isEmpty() ) + aPropValue <<= static_cast<sal_Int16>(sText[0]); + } + else + aPropValue <<= sText; + + return aPropValue; + } + + Type SAL_CALL OEditControl::getValueType() + { + return m_bIsPassword ? ::cppu::UnoType<sal_Int16>::get() : ::cppu::UnoType<OUString>::get(); + } + + void OEditControl::setModified() + { + OEditControl_Base::setModified(); + + // for password controls, we fire a commit for every single change + if ( m_bIsPassword ) + notifyModifiedValue(); + } + + static sal_Int64 ImplCalcLongValue( double nValue, sal_uInt16 nDigits ) + { + double n = nValue; + for ( sal_uInt16 d = 0; d < nDigits; ++d ) + n *= 10; + + return o3tl::saturating_cast<sal_Int64>(n); + } + + static double ImplCalcDoubleValue(sal_Int64 nValue, sal_uInt16 nDigits ) + { + double n = nValue; + for ( sal_uInt16 d = 0; d < nDigits; ++d ) + n /= 10; + return n; + } + + ODateTimeControl::ODateTimeControl(std::unique_ptr<weld::Container> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly) + : ODateTimeControl_Base(PropertyControlType::DateTimeField, std::move(xBuilder), std::move(xWidget), bReadOnly) + , m_xDate(std::make_unique<SvtCalendarBox>(m_xBuilder->weld_menu_button("datefield"))) + , m_xTime(m_xBuilder->weld_formatted_spin_button("timefield")) + , m_xFormatter(new weld::TimeFormatter(*m_xTime)) + { + m_xFormatter->SetExtFormat(ExtTimeFieldFormat::LongDuration); + } + + void SAL_CALL ODateTimeControl::setValue( const Any& _rValue ) + { + if ( !_rValue.hasValue() ) + { + m_xDate->set_date(::Date(::Date::SYSTEM)); + m_xTime->set_text(""); + m_xFormatter->SetTime(tools::Time(tools::Time::EMPTY)); + } + else + { + util::DateTime aUNODateTime; + OSL_VERIFY( _rValue >>= aUNODateTime ); + + ::DateTime aDateTime( ::DateTime::EMPTY ); + ::utl::typeConvert( aUNODateTime, aDateTime ); + + m_xDate->set_date(aDateTime); + m_xFormatter->SetTime(aDateTime); + } + } + + Any SAL_CALL ODateTimeControl::getValue() + { + Any aPropValue; + if (!m_xTime->get_text().isEmpty()) + { + ::DateTime aDateTime(m_xDate->get_date(), m_xFormatter->GetTime()); + + util::DateTime aUNODateTime; + ::utl::typeConvert( aDateTime, aUNODateTime ); + + aPropValue <<= aUNODateTime; + } + return aPropValue; + } + + Type SAL_CALL ODateTimeControl::getValueType() + { + return ::cppu::UnoType<util::DateTime>::get(); + } + + //= OHyperlinkControl + OHyperlinkControl::OHyperlinkControl(std::unique_ptr<weld::Container> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly) + : OHyperlinkControl_Base(PropertyControlType::HyperlinkField, std::move(xBuilder), std::move(xWidget), bReadOnly) + , m_xEntry(m_xBuilder->weld_entry("entry")) + , m_xButton(m_xBuilder->weld_button("button")) + , m_aActionListeners(m_aMutex) + { + auto pWidget = getTypedControlWindow(); + pWidget->set_sensitive(true); + m_xEntry->set_editable(!bReadOnly); + + m_xButton->connect_clicked(LINK(this, OHyperlinkControl, OnHyperlinkClicked)); + } + + Any SAL_CALL OHyperlinkControl::getValue() + { + OUString sText = m_xEntry->get_text(); + return Any( sText ); + } + + void SAL_CALL OHyperlinkControl::setValue( const Any& _value ) + { + OUString sText; + _value >>= sText; + m_xEntry->set_text( sText ); + } + + Type SAL_CALL OHyperlinkControl::getValueType() + { + return ::cppu::UnoType<OUString>::get(); + } + + void SAL_CALL OHyperlinkControl::addActionListener( const Reference< XActionListener >& listener ) + { + if ( listener.is() ) + m_aActionListeners.addInterface( listener ); + } + + void SAL_CALL OHyperlinkControl::removeActionListener( const Reference< XActionListener >& listener ) + { + m_aActionListeners.removeInterface( listener ); + } + + void SAL_CALL OHyperlinkControl::disposing() + { + m_xButton.reset(); + m_xEntry.reset(); + OHyperlinkControl_Base::disposing(); + + EventObject aEvent( *this ); + m_aActionListeners.disposeAndClear( aEvent ); + } + + IMPL_LINK_NOARG( OHyperlinkControl, OnHyperlinkClicked, weld::Button&, void ) + { + ActionEvent aEvent( *this, "clicked" ); + m_aActionListeners.forEach< XActionListener >( + [&aEvent] (uno::Reference<awt::XActionListener> const& xListener) + { return xListener->actionPerformed(aEvent); }); + } + + //= ONumericControl + ONumericControl::ONumericControl(std::unique_ptr<weld::MetricSpinButton> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly) + : ONumericControl_Base(PropertyControlType::NumericField, std::move(xBuilder), std::move(xWidget), bReadOnly) + , m_eValueUnit( FieldUnit::NONE ) + , m_nFieldToUNOValueFactor( 1 ) + { + Optional< double > value( getMaxValue() ); + value.Value = -value.Value; + setMinValue( value ); + } + + ::sal_Int16 SAL_CALL ONumericControl::getDecimalDigits() + { + return getTypedControlWindow()->get_digits(); + } + + void SAL_CALL ONumericControl::setDecimalDigits( ::sal_Int16 decimaldigits ) + { + weld::MetricSpinButton* pControlWindow = getTypedControlWindow(); + sal_Int64 min, max; + pControlWindow->get_range(min, max, FieldUnit::NONE); + pControlWindow->set_digits(decimaldigits); + pControlWindow->set_range(min, max, FieldUnit::NONE); + } + + Optional< double > SAL_CALL ONumericControl::getMinValue() + { + Optional< double > aReturn( true, 0 ); + + sal_Int64 minValue = getTypedControlWindow()->get_min(FieldUnit::NONE); + if ( minValue == std::numeric_limits<sal_Int64>::min() ) + aReturn.IsPresent = false; + else + aReturn.Value = static_cast<double>(minValue); + + return aReturn; + } + + void SAL_CALL ONumericControl::setMinValue( const Optional< double >& _minvalue ) + { + if ( !_minvalue.IsPresent ) + getTypedControlWindow()->set_min( std::numeric_limits<sal_Int64>::min(), FieldUnit::NONE ); + else + getTypedControlWindow()->set_min( impl_apiValueToFieldValue_nothrow( _minvalue.Value ) , m_eValueUnit); + } + + Optional< double > SAL_CALL ONumericControl::getMaxValue() + { + Optional< double > aReturn( true, 0 ); + + sal_Int64 maxValue = getTypedControlWindow()->get_max(FieldUnit::NONE); + if ( maxValue == std::numeric_limits<sal_Int64>::max() ) + aReturn.IsPresent = false; + else + aReturn.Value = static_cast<double>(maxValue); + + return aReturn; + } + + void SAL_CALL ONumericControl::setMaxValue( const Optional< double >& _maxvalue ) + { + if ( !_maxvalue.IsPresent ) + getTypedControlWindow()->set_max( std::numeric_limits<sal_Int64>::max(), FieldUnit::NONE ); + else + getTypedControlWindow()->set_max( impl_apiValueToFieldValue_nothrow( _maxvalue.Value ), m_eValueUnit ); + } + + ::sal_Int16 SAL_CALL ONumericControl::getDisplayUnit() + { + return VCLUnoHelper::ConvertToMeasurementUnit( getTypedControlWindow()->get_unit(), 1 ); + } + + void SAL_CALL ONumericControl::setDisplayUnit( ::sal_Int16 _displayunit ) + { + if ( ( _displayunit < MeasureUnit::MM_100TH ) || ( _displayunit > MeasureUnit::PERCENT ) ) + throw IllegalArgumentException(); + if ( ( _displayunit == MeasureUnit::MM_100TH ) + || ( _displayunit == MeasureUnit::MM_10TH ) + || ( _displayunit == MeasureUnit::INCH_1000TH ) + || ( _displayunit == MeasureUnit::INCH_100TH ) + || ( _displayunit == MeasureUnit::INCH_10TH ) + || ( _displayunit == MeasureUnit::PERCENT ) + ) + throw IllegalArgumentException(); + + sal_Int16 nDummyFactor = 1; + FieldUnit eFieldUnit = VCLUnoHelper::ConvertToFieldUnit( _displayunit, nDummyFactor ); + if ( nDummyFactor != 1 ) + // everything which survived the checks above should result in a factor of 1, i.e., + // it should have a direct counterpart as FieldUnit + throw RuntimeException(); + getTypedControlWindow()->set_unit(eFieldUnit); + } + + ::sal_Int16 SAL_CALL ONumericControl::getValueUnit() + { + return VCLUnoHelper::ConvertToMeasurementUnit( m_eValueUnit, m_nFieldToUNOValueFactor ); + } + + void SAL_CALL ONumericControl::setValueUnit( ::sal_Int16 _valueunit ) + { + if ( ( _valueunit < MeasureUnit::MM_100TH ) || ( _valueunit > MeasureUnit::PERCENT ) ) + throw IllegalArgumentException(); + m_eValueUnit = VCLUnoHelper::ConvertToFieldUnit( _valueunit, m_nFieldToUNOValueFactor ); + } + + void SAL_CALL ONumericControl::setValue( const Any& _rValue ) + { + if ( !_rValue.hasValue() ) + { + getTypedControlWindow()->set_text( "" ); + } + else + { + double nValue( 0 ); + OSL_VERIFY( _rValue >>= nValue ); + auto nControlValue = impl_apiValueToFieldValue_nothrow( nValue ); + getTypedControlWindow()->set_value( nControlValue, m_eValueUnit ); + } + } + + sal_Int64 ONumericControl::impl_apiValueToFieldValue_nothrow( double _nApiValue ) const + { + sal_Int64 nControlValue = ImplCalcLongValue( _nApiValue, getTypedControlWindow()->get_digits() ); + nControlValue /= m_nFieldToUNOValueFactor; + return nControlValue; + } + + double ONumericControl::impl_fieldValueToApiValue_nothrow(sal_Int64 nFieldValue) const + { + double nApiValue = ImplCalcDoubleValue( nFieldValue, getTypedControlWindow()->get_digits() ); + nApiValue *= m_nFieldToUNOValueFactor; + return nApiValue; + } + + Any SAL_CALL ONumericControl::getValue() + { + Any aPropValue; + if ( !getTypedControlWindow()->get_text().isEmpty() ) + { + double nValue = impl_fieldValueToApiValue_nothrow( getTypedControlWindow()->get_value( m_eValueUnit ) ); + aPropValue <<= nValue; + } + return aPropValue; + } + + Type SAL_CALL ONumericControl::getValueType() + { + return ::cppu::UnoType<double>::get(); + } + + //= OColorControl + OColorControl::OColorControl(std::unique_ptr<ColorListBox> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly) + : OColorControl_Base(PropertyControlType::ColorListBox, std::move(xBuilder), std::move(xWidget), bReadOnly) + { + getTypedControlWindow()->SetSlotId(SID_FM_CTL_PROPERTIES); + } + + void SAL_CALL OColorControl::setValue( const Any& _rValue ) + { + css::util::Color nColor = sal_uInt32(COL_TRANSPARENT); + if (_rValue.hasValue()) + _rValue >>= nColor; + getTypedControlWindow()->SelectEntry(::Color(ColorTransparency, nColor)); + } + + Any SAL_CALL OColorControl::getValue() + { + Any aPropValue; + ::Color aRgbCol = getTypedControlWindow()->GetSelectEntryColor(); + if (aRgbCol == COL_TRANSPARENT) + return aPropValue; + aPropValue <<= aRgbCol; + return aPropValue; + } + + Type SAL_CALL OColorControl::getValueType() + { + return ::cppu::UnoType<sal_Int32>::get(); + } + + void OColorControl::setModified() + { + OColorControl_Base::setModified(); + + // fire a commit + notifyModifiedValue(); + } + + //= OListboxControl + OListboxControl::OListboxControl(std::unique_ptr<weld::ComboBox> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly) + : OListboxControl_Base(PropertyControlType::ListBox, std::move(xBuilder), std::move(xWidget), bReadOnly) + { + } + + Any SAL_CALL OListboxControl::getValue() + { + OUString sControlValue( getTypedControlWindow()->get_active_text() ); + + Any aPropValue; + if ( !sControlValue.isEmpty() ) + aPropValue <<= sControlValue; + return aPropValue; + } + + Type SAL_CALL OListboxControl::getValueType() + { + return ::cppu::UnoType<OUString>::get(); + } + + void SAL_CALL OListboxControl::setValue( const Any& _rValue ) + { + if ( !_rValue.hasValue() ) + getTypedControlWindow()->set_active(-1); + else + { + OUString sSelection; + _rValue >>= sSelection; + + if (getTypedControlWindow()->find_text(sSelection) == -1) + getTypedControlWindow()->insert_text(0, sSelection); + + if (sSelection != getTypedControlWindow()->get_active_text()) + getTypedControlWindow()->set_active_text(sSelection); + } + } + + void SAL_CALL OListboxControl::clearList() + { + getTypedControlWindow()->clear(); + } + + void SAL_CALL OListboxControl::prependListEntry( const OUString& NewEntry ) + { + getTypedControlWindow()->insert_text(0, NewEntry); + } + + void SAL_CALL OListboxControl::appendListEntry( const OUString& NewEntry ) + { + getTypedControlWindow()->append_text(NewEntry); + } + + Sequence< OUString > SAL_CALL OListboxControl::getListEntries() + { + const sal_Int32 nCount = getTypedControlWindow()->get_count(); + Sequence< OUString > aRet(nCount); + OUString* pIter = aRet.getArray(); + for (sal_Int32 i = 0; i < nCount ; ++i,++pIter) + *pIter = getTypedControlWindow()->get_text(i); + + return aRet; + } + + void OListboxControl::setModified() + { + OListboxControl_Base::setModified(); + + // fire a commit + notifyModifiedValue(); + } + + //= OComboboxControl + OComboboxControl::OComboboxControl(std::unique_ptr<weld::ComboBox> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly) + : OComboboxControl_Base(PropertyControlType::ComboBox, std::move(xBuilder), std::move(xWidget), bReadOnly) + { + getTypedControlWindow()->connect_changed( LINK( this, OComboboxControl, OnEntrySelected ) ); + } + + void SAL_CALL OComboboxControl::setValue( const Any& _rValue ) + { + OUString sText; + _rValue >>= sText; + weld::ComboBox* pControlWindow = getTypedControlWindow(); + // tdf#138701 leave current cursor valid if the contents won't change + if (pControlWindow->get_active_text() != sText) + pControlWindow->set_entry_text(sText); + } + + Any SAL_CALL OComboboxControl::getValue() + { + return Any( getTypedControlWindow()->get_active_text() ); + } + + Type SAL_CALL OComboboxControl::getValueType() + { + return ::cppu::UnoType<OUString>::get(); + } + + void SAL_CALL OComboboxControl::clearList() + { + getTypedControlWindow()->clear(); + } + + void SAL_CALL OComboboxControl::prependListEntry( const OUString& NewEntry ) + { + getTypedControlWindow()->insert_text(0, NewEntry); + } + + void SAL_CALL OComboboxControl::appendListEntry( const OUString& NewEntry ) + { + getTypedControlWindow()->append_text( NewEntry ); + } + + Sequence< OUString > SAL_CALL OComboboxControl::getListEntries( ) + { + const sal_Int32 nCount = getTypedControlWindow()->get_count(); + Sequence< OUString > aRet(nCount); + OUString* pIter = aRet.getArray(); + for (sal_Int32 i = 0; i < nCount ; ++i,++pIter) + *pIter = getTypedControlWindow()->get_text(i); + + return aRet; + } + + IMPL_LINK_NOARG( OComboboxControl, OnEntrySelected, weld::ComboBox&, void ) + { + // fire a commit + notifyModifiedValue(); + } + + namespace + { + + StlSyntaxSequence< OUString > lcl_convertMultiLineToList( std::u16string_view _rCompsedTextWithLineBreaks ) + { + sal_Int32 nLines = comphelper::string::getTokenCount(_rCompsedTextWithLineBreaks, '\n'); + StlSyntaxSequence< OUString > aStrings( nLines ); + if (nLines) + { + StlSyntaxSequence< OUString >::iterator stringItem = aStrings.begin(); + sal_Int32 nIdx {0}; + do + { + *stringItem = o3tl::getToken(_rCompsedTextWithLineBreaks, 0, '\n', nIdx ); + ++stringItem; + } + while (nIdx>0); + } + return aStrings; + } + + OUString lcl_convertListToMultiLine( const StlSyntaxSequence< OUString >& _rStrings ) + { + OUStringBuffer sMultiLineText; + for ( StlSyntaxSequence< OUString >::const_iterator item = _rStrings.begin(); + item != _rStrings.end(); + ) + { + sMultiLineText.append(*item); + if ( ++item != _rStrings.end() ) + sMultiLineText.append("\n"); + } + return sMultiLineText.makeStringAndClear(); + } + + + OUString lcl_convertListToDisplayText( const StlSyntaxSequence< OUString >& _rStrings ) + { + OUStringBuffer aComposed; + for ( StlSyntaxSequence< OUString >::const_iterator strings = _rStrings.begin(); + strings != _rStrings.end(); + ++strings + ) + { + if ( strings != _rStrings.begin() ) + aComposed.append( ';' ); + aComposed.append( '\"' ); + aComposed.append( *strings ); + aComposed.append( '\"' ); + } + return aComposed.makeStringAndClear(); + } + } + + void OMultilineEditControl::CheckEntryTextViewMisMatch() + { + // if there are newlines or something else which the entry cannot show, then make + // just the multiline dropdown editable as the canonical source for text + m_xEntry->set_sensitive(m_xEntry->get_text() == m_xTextView->get_text()); + } + + void OMultilineEditControl::SetStringListValue(const StlSyntaxSequence<OUString>& rStrings) + { + m_xEntry->set_text(lcl_convertListToDisplayText(rStrings)); + m_xTextView->set_text(lcl_convertListToMultiLine(rStrings)); + CheckEntryTextViewMisMatch(); + } + + StlSyntaxSequence<OUString> OMultilineEditControl::GetStringListValue() const + { + return lcl_convertMultiLineToList(m_xTextView->get_text()); + } + + void OMultilineEditControl::SetTextValue(const OUString& rText) + { + OSL_PRECOND( m_nOperationMode == eMultiLineText, "OMultilineEditControl::SetTextValue: illegal call!" ); + + m_xTextView->set_text(rText); + m_xEntry->set_text(rText); + CheckEntryTextViewMisMatch(); + } + + OUString OMultilineEditControl::GetTextValue() const + { + OSL_PRECOND( m_nOperationMode == eMultiLineText, "OMultilineEditControl::GetTextValue: illegal call!" ); + return m_xTextView->get_text(); + } + + //= OMultilineEditControl + OMultilineEditControl::OMultilineEditControl(std::unique_ptr<weld::Container> xWidget, std::unique_ptr<weld::Builder> xBuilder, MultiLineOperationMode eMode, bool bReadOnly) + : OMultilineEditControl_Base(eMode == eMultiLineText ? PropertyControlType::MultiLineTextField : PropertyControlType::StringListField, + std::move(xBuilder), std::move(xWidget), bReadOnly) + , m_nOperationMode(eMode) + , m_xEntry(m_xBuilder->weld_entry("entry")) + , m_xButton(m_xBuilder->weld_menu_button("button")) + , m_xPopover(m_xBuilder->weld_widget("popover")) + , m_xTextView(m_xBuilder->weld_text_view("textview")) + , m_xOk(m_xBuilder->weld_button("ok")) + { + m_xButton->set_popover(m_xPopover.get()); + m_xTextView->set_size_request(m_xTextView->get_approximate_digit_width() * 30, m_xTextView->get_height_rows(8)); + m_xOk->connect_clicked(LINK(this, OMultilineEditControl, ButtonHandler)); + } + + IMPL_LINK_NOARG(OMultilineEditControl, TextViewModifiedHdl, weld::TextView&, void) + { + // tdf#139070 during editing update the entry to look like how it will + // look once editing is finished so that the default behaviour of vcl + // to strip newlines and the default behaviour of gtk to show a newline + // symbol is suppressed + OUString sText = m_xTextView->get_text(); + auto aSeq = lcl_convertMultiLineToList(sText); + if (aSeq.getLength() > 1) + m_xEntry->set_text(lcl_convertListToDisplayText(aSeq)); + else + m_xEntry->set_text(sText); + CheckEntryTextViewMisMatch(); + setModified(); + } + + void OMultilineEditControl::editChanged() + { + m_xTextView->set_text(m_xEntry->get_text()); + CheckEntryTextViewMisMatch(); + setModified(); + } + + IMPL_LINK_NOARG(OMultilineEditControl, ButtonHandler, weld::Button&, void) + { + m_xButton->set_active(false); + notifyModifiedValue(); + } + + void SAL_CALL OMultilineEditControl::setValue( const Any& _rValue ) + { + impl_checkDisposed_throw(); + + switch (m_nOperationMode) + { + case eMultiLineText: + { + OUString sText; + if ( !( _rValue >>= sText ) && _rValue.hasValue() ) + throw IllegalTypeException(); + SetTextValue(sText); + break; + } + case eStringList: + { + Sequence< OUString > aStringLines; + if ( !( _rValue >>= aStringLines ) && _rValue.hasValue() ) + throw IllegalTypeException(); + SetStringListValue( StlSyntaxSequence<OUString>(aStringLines) ); + break; + } + } + } + + Any SAL_CALL OMultilineEditControl::getValue() + { + impl_checkDisposed_throw(); + + Any aValue; + switch (m_nOperationMode) + { + case eMultiLineText: + aValue <<= GetTextValue(); + break; + case eStringList: + aValue <<= GetStringListValue(); + break; + } + return aValue; + } + + Type SAL_CALL OMultilineEditControl::getValueType() + { + if (m_nOperationMode == eMultiLineText) + return ::cppu::UnoType<OUString>::get(); + return cppu::UnoType<Sequence< OUString >>::get(); + } + +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |