From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- forms/source/component/BaseListBox.hxx | 30 + forms/source/component/Button.cxx | 780 +++++ forms/source/component/Button.hxx | 201 ++ forms/source/component/CheckBox.cxx | 293 ++ forms/source/component/CheckBox.hxx | 83 + forms/source/component/Columns.cxx | 900 +++++ forms/source/component/Columns.hxx | 322 ++ forms/source/component/ComboBox.cxx | 888 +++++ forms/source/component/ComboBox.hxx | 145 + forms/source/component/Currency.cxx | 253 ++ forms/source/component/Currency.hxx | 85 + forms/source/component/DatabaseForm.cxx | 4044 ++++++++++++++++++++++ forms/source/component/DatabaseForm.hxx | 527 +++ forms/source/component/Date.cxx | 326 ++ forms/source/component/Date.hxx | 116 + forms/source/component/Edit.cxx | 717 ++++ forms/source/component/Edit.hxx | 178 + forms/source/component/EditBase.cxx | 377 ++ forms/source/component/EditBase.hxx | 96 + forms/source/component/EventThread.cxx | 196 ++ forms/source/component/EventThread.hxx | 105 + forms/source/component/File.cxx | 275 ++ forms/source/component/File.hxx | 96 + forms/source/component/Filter.cxx | 890 +++++ forms/source/component/Filter.hxx | 138 + forms/source/component/FixedText.cxx | 125 + forms/source/component/FixedText.hxx | 67 + forms/source/component/FormComponent.cxx | 2799 +++++++++++++++ forms/source/component/FormattedField.cxx | 1022 ++++++ forms/source/component/FormattedField.hxx | 182 + forms/source/component/FormattedFieldWrapper.cxx | 360 ++ forms/source/component/FormattedFieldWrapper.hxx | 87 + forms/source/component/FormsCollection.cxx | 141 + forms/source/component/FormsCollection.hxx | 149 + forms/source/component/Grid.cxx | 992 ++++++ forms/source/component/Grid.hxx | 200 ++ forms/source/component/GroupBox.cxx | 162 + forms/source/component/GroupBox.hxx | 82 + forms/source/component/GroupManager.cxx | 421 +++ forms/source/component/GroupManager.hxx | 194 ++ forms/source/component/Hidden.cxx | 177 + forms/source/component/Hidden.hxx | 76 + forms/source/component/ImageButton.cxx | 249 ++ forms/source/component/ImageButton.hxx | 101 + forms/source/component/ImageControl.cxx | 992 ++++++ forms/source/component/ImageControl.hxx | 196 ++ forms/source/component/ListBox.cxx | 2198 ++++++++++++ forms/source/component/ListBox.hxx | 332 ++ forms/source/component/Numeric.cxx | 202 ++ forms/source/component/Numeric.hxx | 88 + forms/source/component/Pattern.cxx | 237 ++ forms/source/component/Pattern.hxx | 94 + forms/source/component/RadioButton.cxx | 402 +++ forms/source/component/RadioButton.hxx | 93 + forms/source/component/Time.cxx | 334 ++ forms/source/component/Time.hxx | 115 + forms/source/component/cachedrowset.cxx | 175 + forms/source/component/cachedrowset.hxx | 78 + forms/source/component/clickableimage.cxx | 838 +++++ forms/source/component/clickableimage.hxx | 283 ++ forms/source/component/cloneable.cxx | 59 + forms/source/component/entrylisthelper.cxx | 325 ++ forms/source/component/entrylisthelper.hxx | 196 ++ forms/source/component/errorbroadcaster.cxx | 94 + forms/source/component/errorbroadcaster.hxx | 60 + forms/source/component/findpos.cxx | 47 + forms/source/component/findpos.hxx | 31 + forms/source/component/formcontrolfont.cxx | 578 ++++ forms/source/component/imgprod.cxx | 491 +++ forms/source/component/imgprod.hxx | 89 + forms/source/component/navigationbar.cxx | 487 +++ forms/source/component/navigationbar.hxx | 116 + forms/source/component/propertybaghelper.cxx | 339 ++ forms/source/component/refvaluecomponent.cxx | 294 ++ forms/source/component/refvaluecomponent.hxx | 87 + forms/source/component/scrollbar.cxx | 317 ++ forms/source/component/scrollbar.hxx | 93 + forms/source/component/spinbutton.cxx | 271 ++ forms/source/component/spinbutton.hxx | 89 + 79 files changed, 30367 insertions(+) create mode 100644 forms/source/component/BaseListBox.hxx create mode 100644 forms/source/component/Button.cxx create mode 100644 forms/source/component/Button.hxx create mode 100644 forms/source/component/CheckBox.cxx create mode 100644 forms/source/component/CheckBox.hxx create mode 100644 forms/source/component/Columns.cxx create mode 100644 forms/source/component/Columns.hxx create mode 100644 forms/source/component/ComboBox.cxx create mode 100644 forms/source/component/ComboBox.hxx create mode 100644 forms/source/component/Currency.cxx create mode 100644 forms/source/component/Currency.hxx create mode 100644 forms/source/component/DatabaseForm.cxx create mode 100644 forms/source/component/DatabaseForm.hxx create mode 100644 forms/source/component/Date.cxx create mode 100644 forms/source/component/Date.hxx create mode 100644 forms/source/component/Edit.cxx create mode 100644 forms/source/component/Edit.hxx create mode 100644 forms/source/component/EditBase.cxx create mode 100644 forms/source/component/EditBase.hxx create mode 100644 forms/source/component/EventThread.cxx create mode 100644 forms/source/component/EventThread.hxx create mode 100644 forms/source/component/File.cxx create mode 100644 forms/source/component/File.hxx create mode 100644 forms/source/component/Filter.cxx create mode 100644 forms/source/component/Filter.hxx create mode 100644 forms/source/component/FixedText.cxx create mode 100644 forms/source/component/FixedText.hxx create mode 100644 forms/source/component/FormComponent.cxx create mode 100644 forms/source/component/FormattedField.cxx create mode 100644 forms/source/component/FormattedField.hxx create mode 100644 forms/source/component/FormattedFieldWrapper.cxx create mode 100644 forms/source/component/FormattedFieldWrapper.hxx create mode 100644 forms/source/component/FormsCollection.cxx create mode 100644 forms/source/component/FormsCollection.hxx create mode 100644 forms/source/component/Grid.cxx create mode 100644 forms/source/component/Grid.hxx create mode 100644 forms/source/component/GroupBox.cxx create mode 100644 forms/source/component/GroupBox.hxx create mode 100644 forms/source/component/GroupManager.cxx create mode 100644 forms/source/component/GroupManager.hxx create mode 100644 forms/source/component/Hidden.cxx create mode 100644 forms/source/component/Hidden.hxx create mode 100644 forms/source/component/ImageButton.cxx create mode 100644 forms/source/component/ImageButton.hxx create mode 100644 forms/source/component/ImageControl.cxx create mode 100644 forms/source/component/ImageControl.hxx create mode 100644 forms/source/component/ListBox.cxx create mode 100644 forms/source/component/ListBox.hxx create mode 100644 forms/source/component/Numeric.cxx create mode 100644 forms/source/component/Numeric.hxx create mode 100644 forms/source/component/Pattern.cxx create mode 100644 forms/source/component/Pattern.hxx create mode 100644 forms/source/component/RadioButton.cxx create mode 100644 forms/source/component/RadioButton.hxx create mode 100644 forms/source/component/Time.cxx create mode 100644 forms/source/component/Time.hxx create mode 100644 forms/source/component/cachedrowset.cxx create mode 100644 forms/source/component/cachedrowset.hxx create mode 100644 forms/source/component/clickableimage.cxx create mode 100644 forms/source/component/clickableimage.hxx create mode 100644 forms/source/component/cloneable.cxx create mode 100644 forms/source/component/entrylisthelper.cxx create mode 100644 forms/source/component/entrylisthelper.hxx create mode 100644 forms/source/component/errorbroadcaster.cxx create mode 100644 forms/source/component/errorbroadcaster.hxx create mode 100644 forms/source/component/findpos.cxx create mode 100644 forms/source/component/findpos.hxx create mode 100644 forms/source/component/formcontrolfont.cxx create mode 100644 forms/source/component/imgprod.cxx create mode 100644 forms/source/component/imgprod.hxx create mode 100644 forms/source/component/navigationbar.cxx create mode 100644 forms/source/component/navigationbar.hxx create mode 100644 forms/source/component/propertybaghelper.cxx create mode 100644 forms/source/component/refvaluecomponent.cxx create mode 100644 forms/source/component/refvaluecomponent.hxx create mode 100644 forms/source/component/scrollbar.cxx create mode 100644 forms/source/component/scrollbar.hxx create mode 100644 forms/source/component/spinbutton.cxx create mode 100644 forms/source/component/spinbutton.hxx (limited to 'forms/source/component') diff --git a/forms/source/component/BaseListBox.hxx b/forms/source/component/BaseListBox.hxx new file mode 100644 index 000000000..fe0930ea7 --- /dev/null +++ b/forms/source/component/BaseListBox.hxx @@ -0,0 +1,30 @@ +/* -*- 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 . + */ + +#pragma once + +#include + +namespace frm +{ +const sal_uInt16 ENTRY_NOT_FOUND = 0xFFFF; +const sal_uInt16 BOUNDCOLUMN = 0x0001; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/forms/source/component/Button.cxx b/forms/source/component/Button.cxx new file mode 100644 index 000000000..3c08b6524 --- /dev/null +++ b/forms/source/component/Button.cxx @@ -0,0 +1,780 @@ +/* -*- 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 "Button.hxx" +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace frm +{ + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; +using ::com::sun::star::frame::XDispatchProviderInterceptor; + + +//= OButtonModel + + +OButtonModel::OButtonModel(const Reference& _rxFactory) + :OClickableImageBaseModel( _rxFactory, VCL_CONTROLMODEL_COMMANDBUTTON, FRM_SUN_CONTROL_COMMANDBUTTON ) + // use the old control name for compatibility reasons + ,m_aResetHelper( *this, m_aMutex ) + ,m_eDefaultState( TRISTATE_FALSE ) +{ + m_nClassId = FormComponentType::COMMANDBUTTON; +} + + +Any SAL_CALL OButtonModel::queryAggregation( const Type& _type ) +{ + Any aReturn = OClickableImageBaseModel::queryAggregation( _type ); + if ( !aReturn.hasValue() ) + aReturn = OButtonModel_Base::queryInterface( _type ); + return aReturn; +} + + +Sequence< Type > OButtonModel::_getTypes() +{ + return ::comphelper::concatSequences( + OClickableImageBaseModel::_getTypes(), + OButtonModel_Base::getTypes() + ); +} + + +OButtonModel::OButtonModel( const OButtonModel* _pOriginal, const Reference& _rxFactory ) + :OClickableImageBaseModel( _pOriginal, _rxFactory ) + ,m_aResetHelper( *this, m_aMutex ) + ,m_eDefaultState( _pOriginal->m_eDefaultState ) +{ + m_nClassId = FormComponentType::COMMANDBUTTON; + + implInitializeImageURL(); +} + + +OButtonModel::~OButtonModel() +{ +} + + +void OButtonModel::describeFixedProperties( Sequence< Property >& _rProps ) const +{ + OClickableImageBaseModel::describeFixedProperties( _rProps ); + sal_Int32 nOldCount = _rProps.getLength(); + _rProps.realloc( nOldCount + 6); + css::beans::Property* pProperties = _rProps.getArray() + nOldCount; + *pProperties++ = css::beans::Property(PROPERTY_BUTTONTYPE, PROPERTY_ID_BUTTONTYPE, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND); + *pProperties++ = css::beans::Property(PROPERTY_DEFAULT_STATE, PROPERTY_ID_DEFAULT_STATE, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND); + *pProperties++ = css::beans::Property(PROPERTY_DISPATCHURLINTERNAL, PROPERTY_ID_DISPATCHURLINTERNAL, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND); + *pProperties++ = css::beans::Property(PROPERTY_TARGET_URL, PROPERTY_ID_TARGET_URL, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND); + *pProperties++ = css::beans::Property(PROPERTY_TARGET_FRAME, PROPERTY_ID_TARGET_FRAME, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND); + *pProperties++ = css::beans::Property(PROPERTY_TABINDEX, PROPERTY_ID_TABINDEX, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND); + DBG_ASSERT( pProperties == _rProps.getArray() + _rProps.getLength(), "<...>::describeFixedProperties/getInfoHelper: forgot to adjust the count ?"); +} + + +css::uno::Reference< css::util::XCloneable > SAL_CALL OButtonModel::createClone() +{ + rtl::Reference pClone = new OButtonModel(this, getContext()); + pClone->clonedFrom(this); + return pClone; +} + + +// XServiceInfo + +css::uno::Sequence OButtonModel::getSupportedServiceNames() +{ + css::uno::Sequence aSupported = OClickableImageBaseModel::getSupportedServiceNames(); + aSupported.realloc( aSupported.getLength() + 2 ); + + OUString* pArray = aSupported.getArray(); + pArray[ aSupported.getLength() - 2 ] = FRM_SUN_COMPONENT_COMMANDBUTTON; + pArray[ aSupported.getLength() - 1 ] = FRM_COMPONENT_COMMANDBUTTON; + + return aSupported; +} + + +OUString OButtonModel::getServiceName() +{ + return FRM_COMPONENT_COMMANDBUTTON; // old (non-sun) name for compatibility ! +} + + +void OButtonModel::write(const Reference& _rxOutStream) +{ + OClickableImageBaseModel::write(_rxOutStream); + + _rxOutStream->writeShort(0x0003); // Version + + { + OStreamSection aSection( _rxOutStream ); + // this will allow readers to skip unknown bytes in their dtor + + _rxOutStream->writeShort( static_cast(m_eButtonType) ); + + OUString sTmp = INetURLObject::decode( m_sTargetURL, INetURLObject::DecodeMechanism::Unambiguous); + _rxOutStream << sTmp; + _rxOutStream << m_sTargetFrame; + writeHelpTextCompatibly(_rxOutStream); + _rxOutStream << isDispatchUrlInternal(); + } +} + + +void OButtonModel::read(const Reference& _rxInStream) +{ + OClickableImageBaseModel::read(_rxInStream); + + sal_uInt16 nVersion = _rxInStream->readShort(); // Version + switch (nVersion) + { + case 0x0001: + { + m_eButtonType = static_cast(_rxInStream->readShort()); + + _rxInStream >> m_sTargetURL; + _rxInStream >> m_sTargetFrame; + } + break; + + case 0x0002: + { + m_eButtonType = static_cast(_rxInStream->readShort()); + + _rxInStream >> m_sTargetURL; + _rxInStream >> m_sTargetFrame; + readHelpTextCompatibly(_rxInStream); + } + break; + + case 0x0003: + { + OStreamSection aSection( _rxInStream ); + // this will skip any unknown bytes in its dtor + + // button type + m_eButtonType = static_cast(_rxInStream->readShort()); + + // URL + _rxInStream >> m_sTargetURL; + + // target frame + _rxInStream >> m_sTargetFrame; + + // help text + readHelpTextCompatibly(_rxInStream); + + // DispatchInternal + bool bDispatch; + _rxInStream >> bDispatch; + setDispatchUrlInternal(bDispatch); + } + break; + + default: + OSL_FAIL("OButtonModel::read : unknown version !"); + m_eButtonType = FormButtonType_PUSH; + m_sTargetURL.clear(); + m_sTargetFrame.clear(); + break; + } +} + + +void SAL_CALL OButtonModel::disposing() +{ + m_aResetHelper.disposing(); + OClickableImageBaseModel::disposing(); +} + + +void SAL_CALL OButtonModel::reset() +{ + if ( !m_aResetHelper.approveReset() ) + return; + + impl_resetNoBroadcast_nothrow(); + + m_aResetHelper.notifyResetted(); +} + + +void SAL_CALL OButtonModel::addResetListener( const Reference< XResetListener >& _listener ) +{ + m_aResetHelper.addResetListener( _listener ); +} + + +void SAL_CALL OButtonModel::removeResetListener( const Reference< XResetListener >& _listener ) +{ + m_aResetHelper.removeResetListener( _listener ); +} + + +void SAL_CALL OButtonModel::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const +{ + switch ( _nHandle ) + { + case PROPERTY_ID_DEFAULT_STATE: + _rValue <<= static_cast(m_eDefaultState); + break; + + default: + OClickableImageBaseModel::getFastPropertyValue( _rValue, _nHandle ); + break; + } +} + + +void SAL_CALL OButtonModel::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue ) +{ + switch ( _nHandle ) + { + case PROPERTY_ID_DEFAULT_STATE: + { + sal_Int16 nDefaultState = sal_Int16(TRISTATE_FALSE); + OSL_VERIFY( _rValue >>= nDefaultState ); + m_eDefaultState = static_cast(nDefaultState); + impl_resetNoBroadcast_nothrow(); + } + break; + + default: + OClickableImageBaseModel::setFastPropertyValue_NoBroadcast( _nHandle, _rValue ); + break; + } +} + + +sal_Bool SAL_CALL OButtonModel::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) +{ + bool bModified = false; + switch ( _nHandle ) + { + case PROPERTY_ID_DEFAULT_STATE: + bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, static_cast(m_eDefaultState) ); + break; + + default: + bModified = OClickableImageBaseModel::convertFastPropertyValue( _rConvertedValue, _rOldValue, _nHandle, _rValue ); + break; + } + return bModified; +} + + +Any OButtonModel::getPropertyDefaultByHandle( sal_Int32 _nHandle ) const +{ + Any aDefault; + switch ( _nHandle ) + { + case PROPERTY_ID_DEFAULT_STATE: + aDefault <<= sal_Int16(TRISTATE_FALSE); + break; + + default: + aDefault = OClickableImageBaseModel::getPropertyDefaultByHandle( _nHandle ); + break; + } + return aDefault; +} + + +void OButtonModel::impl_resetNoBroadcast_nothrow() +{ + try + { + setPropertyValue( PROPERTY_STATE, getPropertyValue( PROPERTY_DEFAULT_STATE ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("forms.component"); + } +} + + +// OButtonControl + + +Sequence OButtonControl::_getTypes() +{ + return ::comphelper::concatSequences( + OButtonControl_BASE::getTypes(), + OClickableImageBaseControl::_getTypes(), + OFormNavigationHelper::getTypes() + ); +} + + +css::uno::Sequence OButtonControl::getSupportedServiceNames() +{ + css::uno::Sequence aSupported = OClickableImageBaseControl::getSupportedServiceNames(); + aSupported.realloc(aSupported.getLength() + 2); + + OUString*pArray = aSupported.getArray(); + pArray[aSupported.getLength()-2] = FRM_SUN_CONTROL_COMMANDBUTTON; + pArray[aSupported.getLength()-1] = STARDIV_ONE_FORM_CONTROL_COMMANDBUTTON; + return aSupported; +} + + +OButtonControl::OButtonControl(const Reference& _rxFactory) + :OClickableImageBaseControl(_rxFactory, VCL_CONTROL_COMMANDBUTTON) + ,OFormNavigationHelper( _rxFactory ) + ,m_nClickEvent( nullptr ) + ,m_nTargetUrlFeatureId( -1 ) + ,m_bEnabledByPropertyValue( false ) +{ + osl_atomic_increment(&m_refCount); + { + // Register as ActionListener + Reference xButton; + query_aggregation( m_xAggregate, xButton); + if (xButton.is()) + xButton->addActionListener(this); + } + // For Listener: refcount at one + osl_atomic_decrement(&m_refCount); +} + + +OButtonControl::~OButtonControl() +{ + if (m_nClickEvent) + Application::RemoveUserEvent(m_nClickEvent); +} + +// UNO binding + +Any SAL_CALL OButtonControl::queryAggregation(const Type& _rType) +{ + // if asked for the XTypeProvider, don't let OButtonControl_BASE do this + Any aReturn; + if ( !_rType.equals( cppu::UnoType::get() ) ) + aReturn = OButtonControl_BASE::queryInterface( _rType ); + + if ( !aReturn.hasValue() ) + aReturn = OClickableImageBaseControl::queryAggregation( _rType ); + + if ( !aReturn.hasValue() ) + aReturn = OFormNavigationHelper::queryInterface( _rType ); + + return aReturn; +} + + +void SAL_CALL OButtonControl::disposing() +{ + startOrStopModelPropertyListening( false ); + + OClickableImageBaseControl::disposing(); + OFormNavigationHelper::dispose(); +} + + +void SAL_CALL OButtonControl::disposing( const EventObject& _rSource ) +{ + OControl::disposing( _rSource ); + OFormNavigationHelper::disposing( _rSource ); +} + +// ActionListener + +void OButtonControl::actionPerformed(const ActionEvent& /*rEvent*/) +{ + // Asynchronous for css::util::URL-Button + ImplSVEvent * n = Application::PostUserEvent( LINK(this, OButtonControl, OnClick) ); + { + ::osl::MutexGuard aGuard( m_aMutex ); + m_nClickEvent = n; + } +} + + +IMPL_LINK_NOARG(OButtonControl, OnClick, void*, void) +{ + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + m_nClickEvent = nullptr; + + if (m_aApproveActionListeners.getLength()) + { + // if there are listeners, start the action in an own thread, to not allow + // them to block us here (we're in the application's main thread) + getImageProducerThread()->addEvent(); + } + else + { + // Else, don't. We then must not notify the Listeners in any case, + // not even if added later on. + aGuard.clear(); + + // recognize the button type + Reference xSet(getModel(), UNO_QUERY); + if (!xSet.is()) + return; + + if (FormButtonType_PUSH == *o3tl::doAccess(xSet->getPropertyValue(PROPERTY_BUTTONTYPE))) + { + // notify the action listeners for a push button + ::comphelper::OInterfaceIteratorHelper3 aIter(m_aActionListeners); + ActionEvent aEvt(static_cast(this), m_aActionCommand); + while(aIter.hasMoreElements() ) + { + // catch exceptions + // and catch them on a per-listener basis - if one listener fails, the others still need + // to get notified + try + { + aIter.next()->actionPerformed(aEvt); + } +#ifdef DBG_UTIL + catch( const RuntimeException& ) + { + // silence this + } +#endif + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "forms.component", "OButtonControl::OnClick: caught an exception other than RuntimeException!" ); + } + } + } + else + actionPerformed_Impl( false, css::awt::MouseEvent() ); + } +} + + +void OButtonControl::actionPerformed_Impl( bool _bNotifyListener, const css::awt::MouseEvent& _rEvt ) +{ + { + sal_Int16 nFeatureId = -1; + { + ::osl::MutexGuard aGuard( m_aMutex ); + nFeatureId = m_nTargetUrlFeatureId; + } + + if ( nFeatureId != -1 ) + { + if ( !approveAction() ) + return; + + SolarMutexGuard aGuard; + dispatch( nFeatureId ); + return; + } + } + + OClickableImageBaseControl::actionPerformed_Impl( _bNotifyListener, _rEvt ); +} + +// XButton + +void OButtonControl::setLabel(const OUString& Label) +{ + Reference xButton; + query_aggregation( m_xAggregate, xButton ); + if (xButton.is()) + xButton->setLabel(Label); +} + + +void SAL_CALL OButtonControl::setActionCommand(const OUString& _rCommand) +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + m_aActionCommand = _rCommand; + } + + Reference xButton; + query_aggregation( m_xAggregate, xButton); + if (xButton.is()) + xButton->setActionCommand(_rCommand); +} + + +void SAL_CALL OButtonControl::addActionListener(const Reference& _rxListener) +{ + m_aActionListeners.addInterface(_rxListener); +} + + +void SAL_CALL OButtonControl::removeActionListener(const Reference& _rxListener) +{ + m_aActionListeners.removeInterface(_rxListener); +} + +namespace { + +class DoPropertyListening +{ +private: + Reference< XPropertySet > m_xProps; + Reference< XPropertyChangeListener > m_xListener; + bool m_bStartListening; + +public: + DoPropertyListening( + const Reference< XInterface >& _rxComponent, + const Reference< XPropertyChangeListener >& _rxListener, + bool _bStart + ); + + void handleListening( const OUString& _rPropertyName ); +}; + +} + +DoPropertyListening::DoPropertyListening( + const Reference< XInterface >& _rxComponent, const Reference< XPropertyChangeListener >& _rxListener, + bool _bStart ) + :m_xProps( _rxComponent, UNO_QUERY ) + ,m_xListener( _rxListener ) + ,m_bStartListening( _bStart ) +{ + DBG_ASSERT( m_xProps.is() || !_rxComponent.is(), "DoPropertyListening::DoPropertyListening: valid component, but no property set!" ); + DBG_ASSERT( m_xListener.is(), "DoPropertyListening::DoPropertyListening: invalid listener!" ); +} + + +void DoPropertyListening::handleListening( const OUString& _rPropertyName ) +{ + if ( m_xProps.is() ) + { + if ( m_bStartListening ) + m_xProps->addPropertyChangeListener( _rPropertyName, m_xListener ); + else + m_xProps->removePropertyChangeListener( _rPropertyName, m_xListener ); + } +} + + +void OButtonControl::startOrStopModelPropertyListening( bool _bStart ) +{ + DoPropertyListening aListeningHandler( getModel(), this, _bStart ); + aListeningHandler.handleListening( PROPERTY_TARGET_URL ); + aListeningHandler.handleListening( PROPERTY_BUTTONTYPE ); + aListeningHandler.handleListening( PROPERTY_ENABLED ); +} + + +sal_Bool SAL_CALL OButtonControl::setModel( const Reference< XControlModel >& _rxModel ) +{ + startOrStopModelPropertyListening( false ); + bool bResult = OClickableImageBaseControl::setModel( _rxModel ); + startOrStopModelPropertyListening( true ); + + m_bEnabledByPropertyValue = true; + Reference< XPropertySet > xModelProps( _rxModel, UNO_QUERY ); + if ( xModelProps.is() ) + xModelProps->getPropertyValue( PROPERTY_ENABLED ) >>= m_bEnabledByPropertyValue; + + modelFeatureUrlPotentiallyChanged( ); + + return bResult; +} + + +void OButtonControl::modelFeatureUrlPotentiallyChanged( ) +{ + sal_Int16 nOldUrlFeatureId = m_nTargetUrlFeatureId; + + // Do we have another TargetURL now? If so, we need to update our dispatches + m_nTargetUrlFeatureId = getModelUrlFeatureId( ); + if ( nOldUrlFeatureId != m_nTargetUrlFeatureId ) + { + invalidateSupportedFeaturesSet(); + if ( !isDesignMode() ) + updateDispatches( ); + } +} + + +void SAL_CALL OButtonControl::propertyChange( const PropertyChangeEvent& _rEvent ) +{ + if ( _rEvent.PropertyName == PROPERTY_TARGET_URL + || _rEvent.PropertyName == PROPERTY_BUTTONTYPE + ) + { + modelFeatureUrlPotentiallyChanged( ); + } + else if ( _rEvent.PropertyName == PROPERTY_ENABLED ) + { + _rEvent.NewValue >>= m_bEnabledByPropertyValue; + } +} + + +namespace +{ + bool isFormControllerURL( const OUString& _rURL ) + { + return ( _rURL.getLength() > RTL_CONSTASCII_LENGTH( ".uno:FormController/" ) ) + && ( _rURL.startsWith( ".uno:FormController/" ) ); + } +} + + +sal_Int16 OButtonControl::getModelUrlFeatureId( ) const +{ + sal_Int16 nFeatureId = -1; + + // some URL related properties of the model + OUString sUrl; + FormButtonType eButtonType = FormButtonType_PUSH; + + Reference< XPropertySet > xModelProps( const_cast< OButtonControl* >( this )->getModel(), UNO_QUERY ); + if ( xModelProps.is() ) + { + xModelProps->getPropertyValue( PROPERTY_TARGET_URL ) >>= sUrl; + xModelProps->getPropertyValue( PROPERTY_BUTTONTYPE ) >>= eButtonType; + } + + // are we a URL button? + if ( eButtonType == FormButtonType_URL ) + { + // is it a feature URL? + if ( isFormControllerURL( sUrl ) ) + { + nFeatureId = OFormNavigationMapper::getFeatureId( sUrl ); + } + } + + return nFeatureId; +} + + +void SAL_CALL OButtonControl::setDesignMode( sal_Bool _bOn ) +{ + OClickableImageBaseControl::setDesignMode( _bOn ); + + if ( _bOn ) + disconnectDispatchers(); + else + connectDispatchers(); + // this will connect if not already connected and just update else +} + + +void OButtonControl::getSupportedFeatures( ::std::vector< sal_Int16 >& /* [out] */ _rFeatureIds ) +{ + if ( -1 != m_nTargetUrlFeatureId ) + _rFeatureIds.push_back( m_nTargetUrlFeatureId ); +} + + +void OButtonControl::featureStateChanged( sal_Int16 _nFeatureId, bool _bEnabled ) +{ + if ( _nFeatureId == m_nTargetUrlFeatureId ) + { + // enable or disable our peer, according to the new state + Reference< XVclWindowPeer > xPeer( getPeer(), UNO_QUERY ); + if ( xPeer.is() ) + xPeer->setProperty( PROPERTY_ENABLED, Any( m_bEnabledByPropertyValue && _bEnabled ) ); + // if we're disabled according to our model's property, then + // we don't care for the feature state, but *are* disabled. + // If the model's property states that we're enabled, then we *do* + // care for the feature state + } + + // base class + OFormNavigationHelper::featureStateChanged( _nFeatureId, _bEnabled ); +} + + +void OButtonControl::allFeatureStatesChanged( ) +{ + if ( -1 != m_nTargetUrlFeatureId ) + // we have only one supported feature, so simulate it has changed ... + featureStateChanged( m_nTargetUrlFeatureId, isEnabled( m_nTargetUrlFeatureId ) ); + + // base class + OFormNavigationHelper::allFeatureStatesChanged( ); +} + + +bool OButtonControl::isEnabled( sal_Int16 _nFeatureId ) const +{ + if ( const_cast< OButtonControl* >( this )->isDesignMode() ) + // TODO: the model property? + return true; + + return OFormNavigationHelper::isEnabled( _nFeatureId ); +} + + +void SAL_CALL OButtonControl::registerDispatchProviderInterceptor( const Reference< XDispatchProviderInterceptor >& _rxInterceptor ) +{ + OClickableImageBaseControl::registerDispatchProviderInterceptor( _rxInterceptor ); + OFormNavigationHelper::registerDispatchProviderInterceptor( _rxInterceptor ); +} + + +void SAL_CALL OButtonControl::releaseDispatchProviderInterceptor( const Reference< XDispatchProviderInterceptor >& _rxInterceptor ) +{ + OClickableImageBaseControl::releaseDispatchProviderInterceptor( _rxInterceptor ); + OFormNavigationHelper::releaseDispatchProviderInterceptor( _rxInterceptor ); +} + +} // namespace frm + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_form_OButtonModel_get_implementation(css::uno::XComponentContext* component, + css::uno::Sequence const &) +{ + return cppu::acquire(new frm::OButtonModel(component)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_form_OButtonControl_get_implementation(css::uno::XComponentContext* component, + css::uno::Sequence const &) +{ + return cppu::acquire(new frm::OButtonControl(component)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/forms/source/component/Button.hxx b/forms/source/component/Button.hxx new file mode 100644 index 000000000..7ccaf7d8a --- /dev/null +++ b/forms/source/component/Button.hxx @@ -0,0 +1,201 @@ +/* -*- 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 . + */ + +#pragma once + +#include "clickableimage.hxx" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +struct ImplSVEvent; + +namespace frm +{ + +typedef ::cppu::ImplHelper1 < css::form::XReset + > OButtonModel_Base; +class OButtonModel :public OClickableImageBaseModel + ,public OButtonModel_Base +{ +public: + OButtonModel( + const css::uno::Reference< css::uno::XComponentContext>& _rxFactory + ); + OButtonModel( + const OButtonModel* _pOriginal, + const css::uno::Reference< css::uno::XComponentContext>& _rxFactory + ); + virtual ~OButtonModel() override; + + // UNO + DECLARE_UNO3_AGG_DEFAULTS( OButtonModel, OClickableImageBaseModel ) + virtual css::uno::Any SAL_CALL queryAggregation( const css::uno::Type& _rType ) override; + + css::uno::Sequence< css::uno::Type> _getTypes() override; + +// css::lang::XServiceInfo + OUString SAL_CALL getImplementationName() override + { return "com.sun.star.form.OButtonModel"; } + + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + +// css::io::XPersistObject + virtual OUString SAL_CALL getServiceName() override; + virtual void SAL_CALL write(const css::uno::Reference< css::io::XObjectOutputStream>& _rxOutStream) override; + virtual void SAL_CALL read(const css::uno::Reference< css::io::XObjectInputStream>& _rxInStream) override; + + // XReset + virtual void SAL_CALL reset( ) override; + virtual void SAL_CALL addResetListener( const css::uno::Reference< css::form::XResetListener >& aListener ) override; + virtual void SAL_CALL removeResetListener( const css::uno::Reference< css::form::XResetListener >& aListener ) override; + + // OControlModel's property handling + virtual void describeFixedProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps + ) const override; + + // XPropertySet and friends + virtual void SAL_CALL getFastPropertyValue(css::uno::Any& rValue, sal_Int32 nHandle) const override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const css::uno::Any& rValue ) override; + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any& _rConvertedValue, css::uno::Any& _rOldValue, sal_Int32 _nHandle, const css::uno::Any& _rValue ) override; + virtual css::uno::Any getPropertyDefaultByHandle( sal_Int32 nHandle ) const override; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + +protected: + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone( ) override; + +private: + void impl_resetNoBroadcast_nothrow(); + + using ::cppu::OPropertySetHelper::getFastPropertyValue; + +private: + ResetHelper m_aResetHelper; + + // + ToggleState m_eDefaultState; // the default check state + // +protected: + using OClickableImageBaseModel::disposing; +}; + + +// OButtonControl + +typedef ::cppu::ImplHelper3 < css::awt::XButton + , css::awt::XActionListener + , css::beans::XPropertyChangeListener + > OButtonControl_BASE; + +class OButtonControl :public OButtonControl_BASE + ,public OClickableImageBaseControl + ,public OFormNavigationHelper +{ +private: + ImplSVEvent * m_nClickEvent; + sal_Int16 m_nTargetUrlFeatureId; + /// caches the value of the "Enabled" property of our model + bool m_bEnabledByPropertyValue; + +protected: + + // UNO binding + virtual css::uno::Sequence< css::uno::Type> _getTypes() override; + +public: + explicit OButtonControl(const css::uno::Reference< css::uno::XComponentContext>& _rxFactory); + virtual ~OButtonControl() override; + + // XServiceInfo + OUString SAL_CALL getImplementationName() override + { return "com.sun.star.form.OButtonControl"; } + + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // UNO binding + DECLARE_UNO3_AGG_DEFAULTS(OButtonControl, OClickableImageBaseControl) + virtual css::uno::Any SAL_CALL queryAggregation(const css::uno::Type& _rType) override; + + // XActionListener + virtual void SAL_CALL actionPerformed(const css::awt::ActionEvent& rEvent) override; + + // XButton + virtual void SAL_CALL addActionListener(const css::uno::Reference< css::awt::XActionListener>& _rxListener) override; + virtual void SAL_CALL removeActionListener(const css::uno::Reference< css::awt::XActionListener>& _rxListener) override; + virtual void SAL_CALL setLabel(const OUString& Label) override; + virtual void SAL_CALL setActionCommand(const OUString& _rCommand) override; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // XPropertyChangeListener + virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override; + + // XEventListener + virtual void SAL_CALL disposing(const css::lang::EventObject& _rSource) override; + + // XControl + virtual sal_Bool SAL_CALL setModel( const css::uno::Reference< css::awt::XControlModel >& _rxModel ) override; + void SAL_CALL setDesignMode(sal_Bool bOn) override; + +protected: + // OFormNavigationHelper overriables + virtual void getSupportedFeatures( ::std::vector< sal_Int16 >& /* [out] */ _rFeatureIds ) override; + virtual void featureStateChanged( sal_Int16 _nFeatureId, bool _bEnabled ) override; + virtual void allFeatureStatesChanged( ) override; + virtual bool isEnabled( sal_Int16 _nFeatureId ) const override; + + // XDispatchProviderInterception disambiguation + virtual void SAL_CALL registerDispatchProviderInterceptor( const css::uno::Reference< css::frame::XDispatchProviderInterceptor >& Interceptor ) override; + virtual void SAL_CALL releaseDispatchProviderInterceptor( const css::uno::Reference< css::frame::XDispatchProviderInterceptor >& Interceptor ) override; + + // OImageControl overridables + virtual void actionPerformed_Impl( bool bNotifyListener, const css::awt::MouseEvent& _rEvt ) override; + +private: + DECL_LINK( OnClick, void*, void ); + + /// to be called whenever the feature URL represented by our model has potentially changed + void modelFeatureUrlPotentiallyChanged( ); + + /// retrieves the feature id (see OFormNavigationHelper) of the TargetURL of the model. + sal_Int16 getModelUrlFeatureId( ) const; + + /// starts or stops listening for changes in model properties we're interested in + void startOrStopModelPropertyListening( bool _bStart ); +}; + + +} // namespace frm + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/forms/source/component/CheckBox.cxx b/forms/source/component/CheckBox.cxx new file mode 100644 index 000000000..fcfdabc53 --- /dev/null +++ b/forms/source/component/CheckBox.cxx @@ -0,0 +1,293 @@ +/* -*- 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 "CheckBox.hxx" +#include +#include +#include +#include +#include +#include + +namespace frm +{ +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::form::binding; + +OCheckBoxControl::OCheckBoxControl(const Reference& _rxFactory) + :OBoundControl(_rxFactory, VCL_CONTROL_CHECKBOX) +{ +} + + +css::uno::Sequence SAL_CALL OCheckBoxControl::getSupportedServiceNames() +{ + css::uno::Sequence aSupported = OBoundControl::getSupportedServiceNames(); + aSupported.realloc(aSupported.getLength() + 2); + + OUString* pArray = aSupported.getArray(); + pArray[aSupported.getLength()-2] = FRM_SUN_CONTROL_CHECKBOX; + pArray[aSupported.getLength()-1] = STARDIV_ONE_FORM_CONTROL_CHECKBOX; + return aSupported; +} + + +//= OCheckBoxModel + +OCheckBoxModel::OCheckBoxModel(const Reference& _rxFactory) + :OReferenceValueComponent( _rxFactory, VCL_CONTROLMODEL_CHECKBOX, FRM_SUN_CONTROL_CHECKBOX ) + // use the old control name for compytibility reasons +{ + + m_nClassId = FormComponentType::CHECKBOX; + initValueProperty( PROPERTY_STATE, PROPERTY_ID_STATE ); +} + + +OCheckBoxModel::OCheckBoxModel( const OCheckBoxModel* _pOriginal, const Reference& _rxFactory ) + :OReferenceValueComponent( _pOriginal, _rxFactory ) +{ +} + + +OCheckBoxModel::~OCheckBoxModel() +{ +} + + +css::uno::Reference< css::util::XCloneable > SAL_CALL OCheckBoxModel::createClone() +{ + rtl::Reference pClone = new OCheckBoxModel(this, getContext()); + pClone->clonedFrom(this); + return pClone; +} + + +// XServiceInfo + +css::uno::Sequence SAL_CALL OCheckBoxModel::getSupportedServiceNames() +{ + css::uno::Sequence aSupported = OReferenceValueComponent::getSupportedServiceNames(); + + sal_Int32 nOldLen = aSupported.getLength(); + aSupported.realloc( nOldLen + 9 ); + OUString* pStoreTo = aSupported.getArray() + nOldLen; + + *pStoreTo++ = BINDABLE_CONTROL_MODEL; + *pStoreTo++ = DATA_AWARE_CONTROL_MODEL; + *pStoreTo++ = VALIDATABLE_CONTROL_MODEL; + + *pStoreTo++ = BINDABLE_DATA_AWARE_CONTROL_MODEL; + *pStoreTo++ = VALIDATABLE_BINDABLE_CONTROL_MODEL; + + *pStoreTo++ = FRM_SUN_COMPONENT_CHECKBOX; + *pStoreTo++ = FRM_SUN_COMPONENT_DATABASE_CHECKBOX; + *pStoreTo++ = BINDABLE_DATABASE_CHECK_BOX; + + *pStoreTo++ = FRM_COMPONENT_CHECKBOX; + + return aSupported; +} + + +void OCheckBoxModel::describeFixedProperties( Sequence< Property >& _rProps ) const +{ + OReferenceValueComponent::describeFixedProperties( _rProps ); + sal_Int32 nOldCount = _rProps.getLength(); + _rProps.realloc( nOldCount + 1); + css::beans::Property* pProperties = _rProps.getArray() + nOldCount; + *pProperties++ = css::beans::Property(PROPERTY_TABINDEX, PROPERTY_ID_TABINDEX, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND); + DBG_ASSERT( pProperties == _rProps.getArray() + _rProps.getLength(), "<...>::describeFixedProperties/getInfoHelper: forgot to adjust the count ?"); +} + + +OUString SAL_CALL OCheckBoxModel::getServiceName() +{ + return FRM_COMPONENT_CHECKBOX; // old (non-sun) name for compatibility ! +} + + +void SAL_CALL OCheckBoxModel::write(const Reference& _rxOutStream) +{ + OReferenceValueComponent::write(_rxOutStream); + + // Version + _rxOutStream->writeShort(0x0003); + // Properties + _rxOutStream << getReferenceValue(); + _rxOutStream << static_cast(getDefaultChecked()); + writeHelpTextCompatibly(_rxOutStream); + // from version 0x0003 : common properties + writeCommonProperties(_rxOutStream); +} + + +void SAL_CALL OCheckBoxModel::read(const Reference& _rxInStream) +{ + OReferenceValueComponent::read(_rxInStream); + osl::MutexGuard aGuard(m_aMutex); + + // Version + sal_uInt16 nVersion = _rxInStream->readShort(); + + OUString sReferenceValue; + sal_Int16 nDefaultChecked( 0 ); + switch ( nVersion ) + { + case 0x0001: + _rxInStream >> sReferenceValue; + nDefaultChecked = _rxInStream->readShort(); + break; + case 0x0002: + _rxInStream >> sReferenceValue; + _rxInStream >> nDefaultChecked; + readHelpTextCompatibly( _rxInStream ); + break; + case 0x0003: + _rxInStream >> sReferenceValue; + _rxInStream >> nDefaultChecked; + readHelpTextCompatibly(_rxInStream); + readCommonProperties(_rxInStream); + break; + default: + OSL_FAIL("OCheckBoxModel::read : unknown version !"); + defaultCommonProperties(); + break; + } + setReferenceValue( sReferenceValue ); + setDefaultChecked( static_cast< ToggleState >( nDefaultChecked ) ); + + // After reading in, display the default values + if ( !getControlSource().isEmpty() ) + // (not if we don't have a control source - the "State" property acts like it is persistent, then + resetNoBroadcast(); +} + +bool OCheckBoxModel::DbUseBool() +{ + return getReferenceValue().isEmpty() && getNoCheckReferenceValue().isEmpty(); +} + + +Any OCheckBoxModel::translateDbColumnToControlValue() +{ + Any aValue; + + + // Set value in ControlModel + bool bValue = bool(); // avoid warning + if(DbUseBool()) + { + bValue = m_xColumn->getBoolean(); + } + else + { + const OUString sVal(m_xColumn->getString()); + if (sVal == getReferenceValue()) + bValue = true; + else if (sVal == getNoCheckReferenceValue()) + bValue = false; + else + aValue <<= static_cast(getDefaultChecked()); + } + if ( m_xColumn->wasNull() ) + { + bool bTriState = true; + if ( m_xAggregateSet.is() ) + m_xAggregateSet->getPropertyValue( PROPERTY_TRISTATE ) >>= bTriState; + aValue <<= static_cast( bTriState ? TRISTATE_INDET : getDefaultChecked() ); + } + else if ( !aValue.hasValue() ) + { + // Since above either bValue is initialised, either aValue.hasValue(), + // bValue cannot be used uninitialised here. + // But GCC does not see/understand that, which breaks -Werror builds, + // so we explicitly default-initialise it. + aValue <<= static_cast( bValue ? TRISTATE_TRUE : TRISTATE_FALSE ); + } + + return aValue; +} + + +bool OCheckBoxModel::commitControlValueToDbColumn( bool /*_bPostReset*/ ) +{ + OSL_PRECOND( m_xColumnUpdate.is(), "OCheckBoxModel::commitControlValueToDbColumn: not bound!" ); + if ( !m_xColumnUpdate ) + return true; + + Any aControlValue( m_xAggregateSet->getPropertyValue( PROPERTY_STATE ) ); + try + { + sal_Int16 nValue = TRISTATE_INDET; + aControlValue >>= nValue; + switch (nValue) + { + case TRISTATE_INDET: + m_xColumnUpdate->updateNull(); + break; + case TRISTATE_TRUE: + if (DbUseBool()) + m_xColumnUpdate->updateBoolean( true ); + else + m_xColumnUpdate->updateString( getReferenceValue() ); + break; + case TRISTATE_FALSE: + if (DbUseBool()) + m_xColumnUpdate->updateBoolean( false ); + else + m_xColumnUpdate->updateString( getNoCheckReferenceValue() ); + break; + default: + OSL_FAIL("OCheckBoxModel::commitControlValueToDbColumn: invalid value !"); + } + } + catch(const Exception&) + { + OSL_FAIL("OCheckBoxModel::commitControlValueToDbColumn: could not commit !"); + } + return true; +} + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_form_OCheckBoxModel_get_implementation(css::uno::XComponentContext* component, + css::uno::Sequence const &) +{ + return cppu::acquire(new frm::OCheckBoxModel(component)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_form_OCheckBoxControl_get_implementation(css::uno::XComponentContext* component, + css::uno::Sequence const &) +{ + return cppu::acquire(new frm::OCheckBoxControl(component)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/forms/source/component/CheckBox.hxx b/forms/source/component/CheckBox.hxx new file mode 100644 index 000000000..8023e7446 --- /dev/null +++ b/forms/source/component/CheckBox.hxx @@ -0,0 +1,83 @@ +/* -*- 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 . + */ + +#pragma once + +#include "refvaluecomponent.hxx" + + +namespace frm +{ + +class OCheckBoxModel final : public OReferenceValueComponent +{ + bool DbUseBool(); + +public: + OCheckBoxModel( + const css::uno::Reference< css::uno::XComponentContext>& _rxFactory + ); + OCheckBoxModel( + const OCheckBoxModel* _pOriginal, + const css::uno::Reference< css::uno::XComponentContext>& _rxFactory + ); + virtual ~OCheckBoxModel() override; + + // XServiceInfo + OUString SAL_CALL getImplementationName() override + { return "com.sun.star.form.OCheckBoxModel"; } + + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // XPersistObject + virtual OUString SAL_CALL getServiceName() override; + virtual void SAL_CALL + write(const css::uno::Reference< css::io::XObjectOutputStream>& _rxOutStream) override; + virtual void SAL_CALL + read(const css::uno::Reference< css::io::XObjectInputStream>& _rxInStream) override; + + // OControlModel's property handling + virtual void describeFixedProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps + ) const override; + +private: + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone( ) override; + + // OBoundControlModel overridables + virtual css::uno::Any translateDbColumnToControlValue( ) override; + virtual bool commitControlValueToDbColumn( bool _bPostReset ) override; +}; + +class OCheckBoxControl : public OBoundControl +{ +public: + explicit OCheckBoxControl(const css::uno::Reference< css::uno::XComponentContext>& _rxContext); + + // XServiceInfo + OUString SAL_CALL getImplementationName() override + { return "com.sun.star.form.OCheckBoxControl"; } + + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; +}; + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/forms/source/component/Columns.cxx b/forms/source/component/Columns.cxx new file mode 100644 index 000000000..7ab2e0801 --- /dev/null +++ b/forms/source/component/Columns.cxx @@ -0,0 +1,900 @@ +/* -*- 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 "Columns.hxx" +#include +#include +#include "findpos.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace frm +{ + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::form::binding; + +const sal_uInt16 WIDTH = 0x0001; +const sal_uInt16 ALIGN = 0x0002; +const sal_uInt16 OLD_HIDDEN = 0x0004; +const sal_uInt16 COMPATIBLE_HIDDEN = 0x0008; + + +const css::uno::Sequence& getColumnTypes() +{ + static css::uno::Sequence aColumnTypes = []() + { + css::uno::Sequence tmp(10); + OUString* pNames = tmp.getArray(); + pNames[TYPE_CHECKBOX] = "CheckBox"; + pNames[TYPE_COMBOBOX] = "ComboBox"; + pNames[TYPE_CURRENCYFIELD] = "CurrencyField"; + pNames[TYPE_DATEFIELD] = "DateField"; + pNames[TYPE_FORMATTEDFIELD] = "FormattedField"; + pNames[TYPE_LISTBOX] = "ListBox"; + pNames[TYPE_NUMERICFIELD] = "NumericField"; + pNames[TYPE_PATTERNFIELD] = "PatternField"; + pNames[TYPE_TEXTFIELD] = "TextField"; + pNames[TYPE_TIMEFIELD] = "TimeField"; + return tmp; + }(); + return aColumnTypes; +} + + +sal_Int32 getColumnTypeByModelName(const OUString& aModelName) +{ + static const OUStringLiteral aModelPrefix (u"com.sun.star.form.component."); + static const OUStringLiteral aCompatibleModelPrefix (u"stardiv.one.form.component."); + + sal_Int32 nTypeId = -1; + if (aModelName == FRM_COMPONENT_EDIT) + nTypeId = TYPE_TEXTFIELD; + else + { + sal_Int32 nPrefixPos = aModelName.indexOf(aModelPrefix); +#ifdef DBG_UTIL + sal_Int32 nCompatiblePrefixPos = aModelName.indexOf(aCompatibleModelPrefix); + DBG_ASSERT( (nPrefixPos != -1) || (nCompatiblePrefixPos != -1), + "::getColumnTypeByModelName() : wrong service!"); +#endif + + OUString aColumnType = (nPrefixPos != -1) + ? aModelName.copy(aModelPrefix.getLength()) + : aModelName.copy(aCompatibleModelPrefix.getLength()); + + const css::uno::Sequence& rColumnTypes = getColumnTypes(); + nTypeId = ::detail::findPos(aColumnType, rColumnTypes); + } + return nTypeId; +} + +const Sequence& OGridColumn::getUnoTunnelId() +{ + static const comphelper::UnoIdInit theOGridColumnImplementationId; + return theOGridColumnImplementationId.getSeq(); +} + + +sal_Int64 SAL_CALL OGridColumn::getSomething( const Sequence& _rIdentifier) +{ + sal_Int64 nReturn(0); + + if ( comphelper::isUnoTunnelId(_rIdentifier) ) + { + nReturn = comphelper::getSomething_cast(this); + } + else + { + Reference< XUnoTunnel > xAggTunnel; + if ( query_aggregation( m_xAggregate, xAggTunnel ) ) + return xAggTunnel->getSomething( _rIdentifier ); + } + return nReturn; +} + + +Sequence SAL_CALL OGridColumn::getImplementationId() +{ + return css::uno::Sequence(); +} + + +Sequence SAL_CALL OGridColumn::getTypes() +{ + TypeBag aTypes( OGridColumn_BASE::getTypes() ); + // erase the types which we do not support + aTypes.removeType( cppu::UnoType::get() ); + aTypes.removeType( cppu::UnoType::get() ); + aTypes.removeType( cppu::UnoType::get() ); + aTypes.removeType( cppu::UnoType::get() ); + + // but re-add their base class(es) + aTypes.addType( cppu::UnoType::get() ); + + Reference< XTypeProvider > xProv; + if ( query_aggregation( m_xAggregate, xProv )) + aTypes.addTypes( xProv->getTypes() ); + + aTypes.removeType( cppu::UnoType::get() ); + aTypes.removeType( cppu::UnoType::get() ); + aTypes.removeType( cppu::UnoType::get() ); + + return aTypes.getTypes(); +} + + +Any SAL_CALL OGridColumn::queryAggregation( const Type& _rType ) +{ + Any aReturn; + // some functionality at our aggregate cannot be reasonably fulfilled here. + if ( _rType.equals(cppu::UnoType::get()) + || _rType.equals(cppu::UnoType::get()) + || _rType.equals(cppu::UnoType::get()) + || _rType.equals(cppu::UnoType::get()) + || comphelper::isAssignableFrom(cppu::UnoType::get(),_rType) + ) + return aReturn; + + aReturn = OGridColumn_BASE::queryAggregation(_rType); + if (!aReturn.hasValue()) + { + aReturn = OPropertySetAggregationHelper::queryInterface(_rType); + if (!aReturn.hasValue() && m_xAggregate.is()) + aReturn = m_xAggregate->queryAggregation(_rType); + } + + return aReturn; +} + + +OGridColumn::OGridColumn( const Reference& _rContext, const OUString& _sModelName ) + :OGridColumn_BASE(m_aMutex) + ,OPropertySetAggregationHelper(OGridColumn_BASE::rBHelper) + ,m_aHidden( Any( false ) ) + ,m_aModelName(_sModelName) +{ + + // Create the UnoControlModel + if ( m_aModelName.isEmpty() ) // is there a to-be-aggregated model? + return; + + osl_atomic_increment( &m_refCount ); + + { + m_xAggregate.set( _rContext->getServiceManager()->createInstanceWithContext( m_aModelName, _rContext ), UNO_QUERY ); + setAggregation( m_xAggregate ); + } + + if ( m_xAggregate.is() ) + { // don't omit those brackets - they ensure that the following temporary is properly deleted + m_xAggregate->setDelegator( static_cast< ::cppu::OWeakObject* >( this ) ); + } + + // Set refcount back to zero + osl_atomic_decrement( &m_refCount ); +} + + +OGridColumn::OGridColumn( const OGridColumn* _pOriginal ) + :OGridColumn_BASE( m_aMutex ) + ,OPropertySetAggregationHelper( OGridColumn_BASE::rBHelper ) +{ + + m_aWidth = _pOriginal->m_aWidth; + m_aAlign = _pOriginal->m_aAlign; + m_aHidden = _pOriginal->m_aHidden; + m_aModelName = _pOriginal->m_aModelName; + m_aLabel = _pOriginal->m_aLabel; + + osl_atomic_increment( &m_refCount ); + { + { + m_xAggregate = createAggregateClone( _pOriginal ); + setAggregation( m_xAggregate ); + } + + if ( m_xAggregate.is() ) + { // don't omit this brackets - they ensure that the following temporary is properly deleted + m_xAggregate->setDelegator( static_cast< ::cppu::OWeakObject* >( this ) ); + } + } + osl_atomic_decrement( &m_refCount ); +} + + +OGridColumn::~OGridColumn() +{ + if (!OGridColumn_BASE::rBHelper.bDisposed) + { + acquire(); + dispose(); + } + + // Free the aggregate + if (m_xAggregate.is()) + { + css::uno::Reference xIface; + m_xAggregate->setDelegator(xIface); + } + +} + +// XEventListener + +void SAL_CALL OGridColumn::disposing(const EventObject& _rSource) +{ + OPropertySetAggregationHelper::disposing(_rSource); + + Reference xEvtLstner; + if (query_aggregation(m_xAggregate, xEvtLstner)) + xEvtLstner->disposing(_rSource); +} + +// OGridColumn_BASE + +void OGridColumn::disposing() +{ + OGridColumn_BASE::disposing(); + OPropertySetAggregationHelper::disposing(); + + Reference xComp; + if (query_aggregation(m_xAggregate, xComp)) + xComp->dispose(); +} + + +void OGridColumn::clearAggregateProperties( Sequence< Property >& _rProps, bool bAllowDropDown ) +{ + // some properties are not to be exposed to the outer world + static const o3tl::sorted_vector< OUString > aForbiddenProperties { + PROPERTY_ALIGN, + PROPERTY_AUTOCOMPLETE, + PROPERTY_BACKGROUNDCOLOR, + PROPERTY_BORDER, + PROPERTY_BORDERCOLOR, + PROPERTY_ECHO_CHAR, + PROPERTY_FILLCOLOR, + PROPERTY_FONT, + PROPERTY_FONT_NAME, + PROPERTY_FONT_STYLENAME, + PROPERTY_FONT_FAMILY, + PROPERTY_FONT_CHARSET, + PROPERTY_FONT_HEIGHT, + PROPERTY_FONT_WEIGHT, + PROPERTY_FONT_SLANT, + PROPERTY_FONT_UNDERLINE, + PROPERTY_FONT_STRIKEOUT, + PROPERTY_FONT_WORDLINEMODE, + PROPERTY_TEXTLINECOLOR, + PROPERTY_FONTEMPHASISMARK, + PROPERTY_FONTRELIEF, + PROPERTY_HARDLINEBREAKS, + PROPERTY_HSCROLL, + PROPERTY_LABEL, + PROPERTY_LINECOLOR, + PROPERTY_MULTISELECTION, + PROPERTY_PRINTABLE, + PROPERTY_TABINDEX, + PROPERTY_TABSTOP, + PROPERTY_TEXTCOLOR, + PROPERTY_VSCROLL, + PROPERTY_CONTROLLABEL, + PROPERTY_RICH_TEXT, + PROPERTY_VERTICAL_ALIGN, + PROPERTY_IMAGE_URL, + PROPERTY_IMAGE_POSITION, + PROPERTY_ENABLEVISIBLE + }; + + Sequence< Property > aNewProps( _rProps.getLength() ); + Property* pNewProps = aNewProps.getArray(); + + const Property* pProps = _rProps.getConstArray(); + const Property* pPropsEnd = pProps + _rProps.getLength(); + for ( ; pProps != pPropsEnd; ++pProps ) + { + if ( aForbiddenProperties.find( pProps->Name ) == aForbiddenProperties.end() + && (bAllowDropDown || pProps->Name != PROPERTY_DROPDOWN)) + *pNewProps++ = *pProps; + } + + aNewProps.realloc( pNewProps - aNewProps.getArray() ); + _rProps = aNewProps; +} + + +void OGridColumn::setOwnProperties(Sequence& aDescriptor) +{ + aDescriptor.realloc(5); + Property* pProperties = aDescriptor.getArray(); + *pProperties++ = css::beans::Property(PROPERTY_LABEL, PROPERTY_ID_LABEL, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND); + *pProperties++ = css::beans::Property(PROPERTY_WIDTH, PROPERTY_ID_WIDTH, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEVOID | css::beans::PropertyAttribute::MAYBEDEFAULT); + *pProperties++ = css::beans::Property(PROPERTY_ALIGN, PROPERTY_ID_ALIGN, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEVOID | css::beans::PropertyAttribute::MAYBEDEFAULT); + *pProperties++ = css::beans::Property(PROPERTY_HIDDEN, PROPERTY_ID_HIDDEN, cppu::UnoType::get(), + css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEDEFAULT); + *pProperties++ = css::beans::Property(PROPERTY_COLUMNSERVICENAME, PROPERTY_ID_COLUMNSERVICENAME, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY); +} + +// Reference + +void OGridColumn::getFastPropertyValue(Any& rValue, sal_Int32 nHandle ) const +{ + switch (nHandle) + { + case PROPERTY_ID_COLUMNSERVICENAME: + rValue <<= m_aModelName; + break; + case PROPERTY_ID_LABEL: + rValue <<= m_aLabel; + break; + case PROPERTY_ID_WIDTH: + rValue = m_aWidth; + break; + case PROPERTY_ID_ALIGN: + rValue = m_aAlign; + break; + case PROPERTY_ID_HIDDEN: + rValue = m_aHidden; + break; + default: + OPropertySetAggregationHelper::getFastPropertyValue(rValue, nHandle); + } +} + + +sal_Bool OGridColumn::convertFastPropertyValue( Any& rConvertedValue, Any& rOldValue, + sal_Int32 nHandle, const Any& rValue ) +{ + bool bModified(false); + switch (nHandle) + { + case PROPERTY_ID_LABEL: + bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_aLabel); + break; + case PROPERTY_ID_WIDTH: + bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, m_aWidth, cppu::UnoType::get()); + break; + case PROPERTY_ID_ALIGN: + bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aAlign, cppu::UnoType::get()); + // strange enough, css.awt.TextAlign is a 32-bit integer, while the Align property (both here for grid controls + // and for ordinary toolkit controls) is a 16-bit integer. So, allow for 32 bit, but normalize it to 16 bit + if ( bModified ) + { + sal_Int32 nAlign( 0 ); + if ( rConvertedValue >>= nAlign ) + rConvertedValue <<= static_cast(nAlign); + } + break; + case PROPERTY_ID_HIDDEN: + bModified = tryPropertyValue(rConvertedValue, rOldValue, rValue, getBOOL(m_aHidden)); + break; + } + return bModified; +} + + +void OGridColumn::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) +{ + switch (nHandle) + { + case PROPERTY_ID_LABEL: + DBG_ASSERT(rValue.getValueType().getTypeClass() == TypeClass_STRING, "invalid type" ); + rValue >>= m_aLabel; + break; + case PROPERTY_ID_WIDTH: + m_aWidth = rValue; + break; + case PROPERTY_ID_ALIGN: + m_aAlign = rValue; + break; + case PROPERTY_ID_HIDDEN: + m_aHidden = rValue; + break; + } +} + + +// XPropertyState + +Any OGridColumn::getPropertyDefaultByHandle( sal_Int32 nHandle ) const +{ + switch (nHandle) + { + case PROPERTY_ID_WIDTH: + case PROPERTY_ID_ALIGN: + return Any(); + case PROPERTY_ID_HIDDEN: + return Any(false); + default: + return OPropertySetAggregationHelper::getPropertyDefaultByHandle(nHandle); + } +} + +// XCloneable + +Reference< XCloneable > SAL_CALL OGridColumn::createClone( ) +{ + return createCloneColumn(); +} + +// XPersistObject + +void OGridColumn::write(const Reference& _rxOutStream) +{ + // 1. Write the UnoControl + Reference xMark(_rxOutStream, UNO_QUERY); + sal_Int32 nMark = xMark->createMark(); + + sal_Int32 nLen = 0; + _rxOutStream->writeLong(nLen); + + Reference xPersist; + if (query_aggregation(m_xAggregate, xPersist)) + xPersist->write(_rxOutStream); + + // Calculate the length + nLen = xMark->offsetToMark(nMark) - 4; + xMark->jumpToMark(nMark); + _rxOutStream->writeLong(nLen); + xMark->jumpToFurthest(); + xMark->deleteMark(nMark); + + // 2. Write a version number + _rxOutStream->writeShort(0x0002); + + sal_uInt16 nAnyMask = 0; + if (m_aWidth.getValueType().getTypeClass() == TypeClass_LONG) + nAnyMask |= WIDTH; + + if (m_aAlign.getValueTypeClass() == TypeClass_SHORT) + nAnyMask |= ALIGN; + + nAnyMask |= COMPATIBLE_HIDDEN; + + _rxOutStream->writeShort(nAnyMask); + + if (nAnyMask & WIDTH) + _rxOutStream->writeLong(getINT32(m_aWidth)); + if (nAnyMask & ALIGN) + _rxOutStream->writeShort(getINT16(m_aAlign)); + + // Name + _rxOutStream << m_aLabel; + + // the new place for the hidden flag : after m_aLabel, so older office version read the correct label, too + if (nAnyMask & COMPATIBLE_HIDDEN) + _rxOutStream->writeBoolean(getBOOL(m_aHidden)); +} + + +void OGridColumn::read(const Reference& _rxInStream) +{ + // 1. Read the UnoControl + sal_Int32 nLen = _rxInStream->readLong(); + if (nLen) + { + Reference xMark(_rxInStream, UNO_QUERY); + sal_Int32 nMark = xMark->createMark(); + Reference xPersist; + if (query_aggregation(m_xAggregate, xPersist)) + xPersist->read(_rxInStream); + + xMark->jumpToMark(nMark); + _rxInStream->skipBytes(nLen); + xMark->deleteMark(nMark); + } + + // 2. Write a version number + _rxInStream->readShort(); // version; + sal_uInt16 nAnyMask = _rxInStream->readShort(); + + if (nAnyMask & WIDTH) + { + sal_Int32 nValue = _rxInStream->readLong(); + m_aWidth <<= nValue; + } + + if (nAnyMask & ALIGN) + { + sal_Int16 nValue = _rxInStream->readShort(); + m_aAlign <<= nValue; + } + if (nAnyMask & OLD_HIDDEN) + { + bool bValue = _rxInStream->readBoolean(); + m_aHidden <<= bValue; + } + + // Name + _rxInStream >> m_aLabel; + + if (nAnyMask & COMPATIBLE_HIDDEN) + { + bool bValue = _rxInStream->readBoolean(); + m_aHidden <<= bValue; + } +} + +TextFieldColumn::TextFieldColumn(const css::uno::Reference& _rContext) + :OGridColumn(_rContext, FRM_SUN_COMPONENT_TEXTFIELD) +{ +} +TextFieldColumn::TextFieldColumn(const TextFieldColumn* _pCloneFrom) + :OGridColumn( _pCloneFrom ) +{ +} +css::uno::Reference< css::beans::XPropertySetInfo> TextFieldColumn::getPropertySetInfo() +{ + css::uno::Reference< css::beans::XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} +::cppu::IPropertyArrayHelper& TextFieldColumn::getInfoHelper() +{ + return *getArrayHelper(); +} +void TextFieldColumn::fillProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps, + css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps + ) const +{ + if (m_xAggregateSet.is()) + { + _rAggregateProps = m_xAggregateSet->getPropertySetInfo()->getProperties(); + clearAggregateProperties(_rAggregateProps, false); + setOwnProperties(_rProps); + } +} +rtl::Reference TextFieldColumn::createCloneColumn() const +{ + return new TextFieldColumn(this); +} + +PatternFieldColumn::PatternFieldColumn(const css::uno::Reference& _rContext) + :OGridColumn(_rContext, FRM_SUN_COMPONENT_PATTERNFIELD) +{ +} +PatternFieldColumn::PatternFieldColumn(const PatternFieldColumn* _pCloneFrom) + :OGridColumn( _pCloneFrom ) +{ +} +css::uno::Reference< css::beans::XPropertySetInfo> PatternFieldColumn::getPropertySetInfo() +{ + css::uno::Reference< css::beans::XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} +::cppu::IPropertyArrayHelper& PatternFieldColumn::getInfoHelper() +{ + return *getArrayHelper(); +} +void PatternFieldColumn::fillProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps, + css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps + ) const +{ + if (m_xAggregateSet.is()) + { + _rAggregateProps = m_xAggregateSet->getPropertySetInfo()->getProperties(); + clearAggregateProperties(_rAggregateProps, false); + setOwnProperties(_rProps); + } +} +rtl::Reference PatternFieldColumn::createCloneColumn() const +{ + return new PatternFieldColumn(this); +} + +DateFieldColumn::DateFieldColumn(const css::uno::Reference& _rContext) + :OGridColumn(_rContext, FRM_SUN_COMPONENT_DATEFIELD) +{ +} +DateFieldColumn::DateFieldColumn(const DateFieldColumn* _pCloneFrom) + :OGridColumn( _pCloneFrom ) +{ +} +css::uno::Reference< css::beans::XPropertySetInfo> DateFieldColumn::getPropertySetInfo() +{ + css::uno::Reference< css::beans::XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} +::cppu::IPropertyArrayHelper& DateFieldColumn::getInfoHelper() +{ + return *getArrayHelper(); +} +void DateFieldColumn::fillProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps, + css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps + ) const +{ + if (m_xAggregateSet.is()) + { + _rAggregateProps = m_xAggregateSet->getPropertySetInfo()->getProperties(); + clearAggregateProperties(_rAggregateProps, true); + setOwnProperties(_rProps); + } +} +rtl::Reference DateFieldColumn::createCloneColumn() const +{ + return new DateFieldColumn(this); +} + +TimeFieldColumn::TimeFieldColumn(const css::uno::Reference& _rContext) + :OGridColumn(_rContext, FRM_SUN_COMPONENT_TIMEFIELD) +{ +} +TimeFieldColumn::TimeFieldColumn(const TimeFieldColumn* _pCloneFrom) + :OGridColumn( _pCloneFrom ) +{ +} +css::uno::Reference< css::beans::XPropertySetInfo> TimeFieldColumn::getPropertySetInfo() +{ + css::uno::Reference< css::beans::XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} +::cppu::IPropertyArrayHelper& TimeFieldColumn::getInfoHelper() +{ + return *getArrayHelper(); +} +void TimeFieldColumn::fillProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps, + css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps + ) const +{ + if (m_xAggregateSet.is()) + { + _rAggregateProps = m_xAggregateSet->getPropertySetInfo()->getProperties(); + clearAggregateProperties(_rAggregateProps, false); + setOwnProperties(_rProps); + } +} +rtl::Reference TimeFieldColumn::createCloneColumn() const +{ + return new TimeFieldColumn(this); +} + +NumericFieldColumn::NumericFieldColumn(const css::uno::Reference& _rContext) + :OGridColumn(_rContext, FRM_SUN_COMPONENT_NUMERICFIELD) +{ +} +NumericFieldColumn::NumericFieldColumn(const NumericFieldColumn* _pCloneFrom) + :OGridColumn( _pCloneFrom ) +{ +} +css::uno::Reference< css::beans::XPropertySetInfo> NumericFieldColumn::getPropertySetInfo() +{ + css::uno::Reference< css::beans::XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} +::cppu::IPropertyArrayHelper& NumericFieldColumn::getInfoHelper() +{ + return *getArrayHelper(); +} +void NumericFieldColumn::fillProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps, + css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps + ) const +{ + if (m_xAggregateSet.is()) + { + _rAggregateProps = m_xAggregateSet->getPropertySetInfo()->getProperties(); + clearAggregateProperties(_rAggregateProps, false); + setOwnProperties(_rProps); + } +} +rtl::Reference NumericFieldColumn::createCloneColumn() const +{ + return new NumericFieldColumn(this); +} + +CurrencyFieldColumn::CurrencyFieldColumn(const css::uno::Reference& _rContext) + :OGridColumn(_rContext, FRM_SUN_COMPONENT_CURRENCYFIELD) +{ +} +CurrencyFieldColumn::CurrencyFieldColumn(const CurrencyFieldColumn* _pCloneFrom) + :OGridColumn( _pCloneFrom ) +{ +} +css::uno::Reference< css::beans::XPropertySetInfo> CurrencyFieldColumn::getPropertySetInfo() +{ + css::uno::Reference< css::beans::XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} +::cppu::IPropertyArrayHelper& CurrencyFieldColumn::getInfoHelper() +{ + return *getArrayHelper(); +} +void CurrencyFieldColumn::fillProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps, + css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps + ) const +{ + if (m_xAggregateSet.is()) + { + _rAggregateProps = m_xAggregateSet->getPropertySetInfo()->getProperties(); + clearAggregateProperties(_rAggregateProps, false); + setOwnProperties(_rProps); + } +} +rtl::Reference CurrencyFieldColumn::createCloneColumn() const +{ + return new CurrencyFieldColumn(this); +} + +CheckBoxColumn::CheckBoxColumn(const css::uno::Reference& _rContext) + :OGridColumn(_rContext, FRM_SUN_COMPONENT_CHECKBOX) +{ +} +CheckBoxColumn::CheckBoxColumn(const CheckBoxColumn* _pCloneFrom) + :OGridColumn( _pCloneFrom ) +{ +} +css::uno::Reference< css::beans::XPropertySetInfo> CheckBoxColumn::getPropertySetInfo() +{ + css::uno::Reference< css::beans::XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} +::cppu::IPropertyArrayHelper& CheckBoxColumn::getInfoHelper() +{ + return *getArrayHelper(); +} +void CheckBoxColumn::fillProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps, + css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps + ) const +{ + if (m_xAggregateSet.is()) + { + _rAggregateProps = m_xAggregateSet->getPropertySetInfo()->getProperties(); + clearAggregateProperties(_rAggregateProps, false); + setOwnProperties(_rProps); + } +} +rtl::Reference CheckBoxColumn::createCloneColumn() const +{ + return new CheckBoxColumn(this); +} + +ComboBoxColumn::ComboBoxColumn(const css::uno::Reference& _rContext) + :OGridColumn(_rContext, FRM_SUN_COMPONENT_COMBOBOX) +{ +} +ComboBoxColumn::ComboBoxColumn(const ComboBoxColumn* _pCloneFrom) + :OGridColumn( _pCloneFrom ) +{ +} +css::uno::Reference< css::beans::XPropertySetInfo> ComboBoxColumn::getPropertySetInfo() +{ + css::uno::Reference< css::beans::XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} +::cppu::IPropertyArrayHelper& ComboBoxColumn::getInfoHelper() +{ + return *getArrayHelper(); +} +void ComboBoxColumn::fillProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps, + css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps + ) const +{ + if (m_xAggregateSet.is()) + { + _rAggregateProps = m_xAggregateSet->getPropertySetInfo()->getProperties(); + clearAggregateProperties(_rAggregateProps, false); + setOwnProperties(_rProps); + } +} +rtl::Reference ComboBoxColumn::createCloneColumn() const +{ + return new ComboBoxColumn(this); +} + +ListBoxColumn::ListBoxColumn(const css::uno::Reference& _rContext) + :OGridColumn(_rContext, FRM_SUN_COMPONENT_LISTBOX) +{ +} +ListBoxColumn::ListBoxColumn(const ListBoxColumn* _pCloneFrom) + :OGridColumn( _pCloneFrom ) +{ +} +css::uno::Reference< css::beans::XPropertySetInfo> ListBoxColumn::getPropertySetInfo() +{ + css::uno::Reference< css::beans::XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} +::cppu::IPropertyArrayHelper& ListBoxColumn::getInfoHelper() +{ + return *getArrayHelper(); +} +void ListBoxColumn::fillProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps, + css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps + ) const +{ + if (m_xAggregateSet.is()) + { + _rAggregateProps = m_xAggregateSet->getPropertySetInfo()->getProperties(); + clearAggregateProperties(_rAggregateProps, false); + setOwnProperties(_rProps); + } +} +rtl::Reference ListBoxColumn::createCloneColumn() const +{ + return new ListBoxColumn(this); +} + +FormattedFieldColumn::FormattedFieldColumn(const css::uno::Reference& _rContext) + :OGridColumn(_rContext, FRM_SUN_COMPONENT_FORMATTEDFIELD) +{ +} +FormattedFieldColumn::FormattedFieldColumn(const FormattedFieldColumn* _pCloneFrom) + :OGridColumn( _pCloneFrom ) +{ +} +css::uno::Reference< css::beans::XPropertySetInfo> FormattedFieldColumn::getPropertySetInfo() +{ + css::uno::Reference< css::beans::XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} +::cppu::IPropertyArrayHelper& FormattedFieldColumn::getInfoHelper() +{ + return *getArrayHelper(); +} +void FormattedFieldColumn::fillProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps, + css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps + ) const +{ + if (m_xAggregateSet.is()) + { + _rAggregateProps = m_xAggregateSet->getPropertySetInfo()->getProperties(); + clearAggregateProperties(_rAggregateProps, false); + setOwnProperties(_rProps); + } +} +rtl::Reference FormattedFieldColumn::createCloneColumn() const +{ + return new FormattedFieldColumn(this); +} + +} // namespace frm + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/forms/source/component/Columns.hxx b/forms/source/component/Columns.hxx new file mode 100644 index 000000000..fd2caa3b9 --- /dev/null +++ b/forms/source/component/Columns.hxx @@ -0,0 +1,322 @@ +/* -*- 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 . + */ + +#pragma once + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace comphelper; + + +namespace frm +{ + +typedef ::cppu::WeakAggComponentImplHelper2 < css::lang::XUnoTunnel + , css::util::XCloneable > OGridColumn_BASE; +class OGridColumn :public ::cppu::BaseMutex + ,public OGridColumn_BASE + ,public OPropertySetAggregationHelper + ,public OCloneableAggregation +{ +// [properties] + css::uno::Any m_aWidth; // column width + css::uno::Any m_aAlign; // column alignment + css::uno::Any m_aHidden; // column hidden? +// [properties] + + OUString m_aModelName; + +// [properties] + OUString m_aLabel; // Column name +// [properties] + +public: + OGridColumn(const css::uno::Reference& _rContext, const OUString& _sModelName); + explicit OGridColumn(const OGridColumn* _pOriginal ); + virtual ~OGridColumn() override; + + // UNO binding + DECLARE_UNO3_AGG_DEFAULTS(OGridControlModel, OGridColumn_BASE) + virtual css::uno::Any SAL_CALL queryAggregation( const css::uno::Type& _rType ) override; + + static const css::uno::Sequence& getUnoTunnelId(); + // XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence& _rIdentifier) override; + + // XTypeProvider + virtual css::uno::Sequence SAL_CALL getImplementationId() override; + virtual css::uno::Sequence< css::uno::Type> SAL_CALL getTypes() override; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // XEventListener + virtual void SAL_CALL disposing(const css::lang::EventObject& _rSource) override; + + // XPersistObject + void write(const css::uno::Reference< css::io::XObjectOutputStream>& _rxOutStream); + void read(const css::uno::Reference< css::io::XObjectInputStream>& _rxInStream); + + // XPropertySet + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override = 0; + virtual void SAL_CALL getFastPropertyValue(css::uno::Any& rValue, sal_Int32 nHandle ) const override; + virtual sal_Bool SAL_CALL convertFastPropertyValue(css::uno::Any& rConvertedValue, css::uno::Any& rOldValue, + sal_Int32 nHandle, const css::uno::Any& rValue ) override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const css::uno::Any& rValue) override; + + using OPropertySetAggregationHelper::getFastPropertyValue; + + // css::beans::XPropertyState + virtual css::uno::Any getPropertyDefaultByHandle( sal_Int32 nHandle ) const override; + + // XCloneable + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone( ) override; + + const OUString& getModelName() const { return m_aModelName; } + +protected: + static void clearAggregateProperties(css::uno::Sequence< css::beans::Property>& seqProps, bool bAllowDropDown); + static void setOwnProperties(css::uno::Sequence< css::beans::Property>& seqProps); + + virtual rtl::Reference createCloneColumn() const = 0; +}; + +// column type ids +#define TYPE_CHECKBOX 0 +#define TYPE_COMBOBOX 1 +#define TYPE_CURRENCYFIELD 2 +#define TYPE_DATEFIELD 3 +#define TYPE_FORMATTEDFIELD 4 +#define TYPE_LISTBOX 5 +#define TYPE_NUMERICFIELD 6 +#define TYPE_PATTERNFIELD 7 +#define TYPE_TEXTFIELD 8 +#define TYPE_TIMEFIELD 9 + +// List of all known columns +const css::uno::Sequence& getColumnTypes(); +sal_Int32 getColumnTypeByModelName(const OUString& aModelName); + +// Columns +class TextFieldColumn + :public OGridColumn + ,public OAggregationArrayUsageHelper< TextFieldColumn > +{ +public: + explicit TextFieldColumn(const css::uno::Reference& _rContext ); + explicit TextFieldColumn(const TextFieldColumn* _pCloneFrom); + + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + virtual void fillProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps, + css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps + ) const override; + + virtual rtl::Reference createCloneColumn() const override; +}; + +class PatternFieldColumn + :public OGridColumn + ,public OAggregationArrayUsageHelper< PatternFieldColumn > +{ +public: + explicit PatternFieldColumn(const css::uno::Reference& _rContext ); + explicit PatternFieldColumn(const PatternFieldColumn* _pCloneFrom); + + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + virtual void fillProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps, + css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps + ) const override; + + virtual rtl::Reference createCloneColumn() const override; +}; + +class DateFieldColumn + :public OGridColumn + ,public OAggregationArrayUsageHelper< DateFieldColumn > +{ +public: + explicit DateFieldColumn(const css::uno::Reference& _rContext ); + explicit DateFieldColumn(const DateFieldColumn* _pCloneFrom); + + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + virtual void fillProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps, + css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps + ) const override; + + virtual rtl::Reference createCloneColumn() const override; +}; + +class TimeFieldColumn + :public OGridColumn + ,public OAggregationArrayUsageHelper< TimeFieldColumn > +{ +public: + explicit TimeFieldColumn(const css::uno::Reference& _rContext ); + explicit TimeFieldColumn(const TimeFieldColumn* _pCloneFrom); + + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + virtual void fillProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps, + css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps + ) const override; + + virtual rtl::Reference createCloneColumn() const override; +}; + +class NumericFieldColumn + :public OGridColumn + ,public OAggregationArrayUsageHelper< NumericFieldColumn > +{ +public: + explicit NumericFieldColumn(const css::uno::Reference& _rContext ); + explicit NumericFieldColumn(const NumericFieldColumn* _pCloneFrom); + + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + virtual void fillProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps, + css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps + ) const override; + + virtual rtl::Reference createCloneColumn() const override; +}; + +class CurrencyFieldColumn + :public OGridColumn + ,public OAggregationArrayUsageHelper< CurrencyFieldColumn > +{ +public: + explicit CurrencyFieldColumn(const css::uno::Reference& _rContext ); + explicit CurrencyFieldColumn(const CurrencyFieldColumn* _pCloneFrom); + + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + virtual void fillProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps, + css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps + ) const override; + + virtual rtl::Reference createCloneColumn() const override; +}; + +class CheckBoxColumn + :public OGridColumn + ,public OAggregationArrayUsageHelper< CheckBoxColumn > +{ +public: + explicit CheckBoxColumn(const css::uno::Reference& _rContext ); + explicit CheckBoxColumn(const CheckBoxColumn* _pCloneFrom); + + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + virtual void fillProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps, + css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps + ) const override; + + virtual rtl::Reference createCloneColumn() const override; +}; + +class ComboBoxColumn + :public OGridColumn + ,public OAggregationArrayUsageHelper< ComboBoxColumn > +{ +public: + explicit ComboBoxColumn(const css::uno::Reference& _rContext ); + explicit ComboBoxColumn(const ComboBoxColumn* _pCloneFrom); + + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + virtual void fillProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps, + css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps + ) const override; + + virtual rtl::Reference createCloneColumn() const override; +}; + +class ListBoxColumn + :public OGridColumn + ,public OAggregationArrayUsageHelper< ListBoxColumn > +{ +public: + explicit ListBoxColumn(const css::uno::Reference& _rContext ); + explicit ListBoxColumn(const ListBoxColumn* _pCloneFrom); + + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + virtual void fillProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps, + css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps + ) const override; + + virtual rtl::Reference createCloneColumn() const override; +}; + +class FormattedFieldColumn + :public OGridColumn + ,public OAggregationArrayUsageHelper< FormattedFieldColumn > +{ +public: + explicit FormattedFieldColumn(const css::uno::Reference& _rContext ); + explicit FormattedFieldColumn(const FormattedFieldColumn* _pCloneFrom); + + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + virtual void fillProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps, + css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps + ) const override; + + virtual rtl::Reference createCloneColumn() const override; +}; + +} // namespace frm + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/forms/source/component/ComboBox.cxx b/forms/source/component/ComboBox.cxx new file mode 100644 index 000000000..d38c16abc --- /dev/null +++ b/forms/source/component/ComboBox.cxx @@ -0,0 +1,888 @@ +/* -*- 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 "ComboBox.hxx" +#include +#include + +#include +#include +#include "BaseListBox.hxx" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +using namespace dbtools; + + +namespace frm +{ +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::form::binding; + + +Sequence OComboBoxModel::_getTypes() +{ + return ::comphelper::concatSequences( + OBoundControlModel::_getTypes(), + OEntryListHelper::getTypes(), + OErrorBroadcaster::getTypes() + ); +} + +// XServiceInfo + +css::uno::Sequence SAL_CALL OComboBoxModel::getSupportedServiceNames() +{ + css::uno::Sequence aSupported = OBoundControlModel::getSupportedServiceNames(); + + sal_Int32 nOldLen = aSupported.getLength(); + aSupported.realloc( nOldLen + 9 ); + OUString* pStoreTo = aSupported.getArray() + nOldLen; + + *pStoreTo++ = BINDABLE_CONTROL_MODEL; + *pStoreTo++ = DATA_AWARE_CONTROL_MODEL; + *pStoreTo++ = VALIDATABLE_CONTROL_MODEL; + + *pStoreTo++ = BINDABLE_DATA_AWARE_CONTROL_MODEL; + *pStoreTo++ = VALIDATABLE_BINDABLE_CONTROL_MODEL; + + *pStoreTo++ = FRM_SUN_COMPONENT_COMBOBOX; + *pStoreTo++ = FRM_SUN_COMPONENT_DATABASE_COMBOBOX; + *pStoreTo++ = BINDABLE_DATABASE_COMBO_BOX; + + *pStoreTo++ = FRM_COMPONENT_COMBOBOX; + + return aSupported; +} + + +Any SAL_CALL OComboBoxModel::queryAggregation(const Type& _rType) +{ + Any aReturn = OBoundControlModel::queryAggregation( _rType ); + if ( !aReturn.hasValue() ) + aReturn = OEntryListHelper::queryInterface( _rType ); + if ( !aReturn.hasValue() ) + aReturn = OErrorBroadcaster::queryInterface( _rType ); + return aReturn; +} + + +OComboBoxModel::OComboBoxModel(const Reference& _rxFactory) + :OBoundControlModel( _rxFactory, VCL_CONTROLMODEL_COMBOBOX, FRM_SUN_CONTROL_COMBOBOX, true, true, true ) + // use the old control name for compatibility reasons + ,OEntryListHelper( static_cast(*this) ) + ,OErrorBroadcaster( OComponentHelper::rBHelper ) + ,m_eListSourceType(ListSourceType_TABLE) + ,m_bEmptyIsNull(true) +{ + m_nClassId = FormComponentType::COMBOBOX; + initValueProperty( PROPERTY_TEXT, PROPERTY_ID_TEXT ); +} + + +OComboBoxModel::OComboBoxModel( const OComboBoxModel* _pOriginal, const Reference& _rxFactory ) + :OBoundControlModel( _pOriginal, _rxFactory ) + ,OEntryListHelper( *_pOriginal, static_cast(*this) ) + ,OErrorBroadcaster( OComponentHelper::rBHelper ) + ,m_aListSource( _pOriginal->m_aListSource ) + ,m_aDefaultText( _pOriginal->m_aDefaultText ) + ,m_eListSourceType( _pOriginal->m_eListSourceType ) + ,m_bEmptyIsNull( _pOriginal->m_bEmptyIsNull ) +{ +} + + +OComboBoxModel::~OComboBoxModel() +{ + if (!OComponentHelper::rBHelper.bDisposed) + { + acquire(); + dispose(); + } + +} + +// XCloneable + +css::uno::Reference< css::util::XCloneable > SAL_CALL OComboBoxModel::createClone() +{ + rtl::Reference pClone = new OComboBoxModel(this, getContext()); + pClone->clonedFrom(this); + return pClone; +} + + +void OComboBoxModel::disposing() +{ + OBoundControlModel::disposing(); + OEntryListHelper::disposing(); + OErrorBroadcaster::disposing(); +} + + +void OComboBoxModel::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const +{ + switch (_nHandle) + { + case PROPERTY_ID_LISTSOURCETYPE: + _rValue <<= m_eListSourceType; + break; + + case PROPERTY_ID_LISTSOURCE: + _rValue <<= m_aListSource; + break; + + case PROPERTY_ID_EMPTY_IS_NULL: + _rValue <<= m_bEmptyIsNull; + break; + + case PROPERTY_ID_DEFAULT_TEXT: + _rValue <<= m_aDefaultText; + break; + + case PROPERTY_ID_STRINGITEMLIST: + _rValue <<= comphelper::containerToSequence(getStringItemList()); + break; + + case PROPERTY_ID_TYPEDITEMLIST: + _rValue <<= getTypedItemList(); + break; + + default: + OBoundControlModel::getFastPropertyValue(_rValue, _nHandle); + } +} + + +void OComboBoxModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue) +{ + switch (_nHandle) + { + case PROPERTY_ID_LISTSOURCETYPE : + DBG_ASSERT(_rValue.getValueType().equals(::cppu::UnoType::get()), + "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" ); + _rValue >>= m_eListSourceType; + break; + + case PROPERTY_ID_LISTSOURCE : + DBG_ASSERT(_rValue.getValueType().getTypeClass() == TypeClass_STRING, + "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" ); + _rValue >>= m_aListSource; + // The ListSource has changed -> reload + if (ListSourceType_VALUELIST != m_eListSourceType) + { + if ( m_xCursor.is() && !hasField() && !hasExternalListSource() ) + // combo box is already connected to a database, and no external list source + // data source changed -> refresh + loadData( false ); + } + break; + + case PROPERTY_ID_EMPTY_IS_NULL : + DBG_ASSERT(_rValue.getValueType().getTypeClass() == TypeClass_BOOLEAN, + "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" ); + _rValue >>= m_bEmptyIsNull; + break; + + case PROPERTY_ID_DEFAULT_TEXT : + DBG_ASSERT(_rValue.getValueType().getTypeClass() == TypeClass_STRING, + "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" ); + _rValue >>= m_aDefaultText; + resetNoBroadcast(); + break; + + case PROPERTY_ID_STRINGITEMLIST: + { + ControlModelLock aLock( *this ); + setNewStringItemList( _rValue, aLock ); + // FIXME: this is bogus. setNewStringItemList expects a guard which has the *only* + // lock to the mutex, but setFastPropertyValue_NoBroadcast is already called with + // a lock - so we effectively has two locks here, of which setNewStringItemList can + // only control one. + } + break; + + case PROPERTY_ID_TYPEDITEMLIST: + { + ControlModelLock aLock( *this ); + setNewTypedItemList( _rValue, aLock ); + // Same FIXME as above. + } + break; + + default: + OBoundControlModel::setFastPropertyValue_NoBroadcast(_nHandle, _rValue); + } +} + +sal_Bool OComboBoxModel::convertFastPropertyValue( + Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue) +{ + bool bModified(false); + switch (_nHandle) + { + case PROPERTY_ID_LISTSOURCETYPE : + bModified = tryPropertyValueEnum(_rConvertedValue, _rOldValue, _rValue, m_eListSourceType); + break; + + case PROPERTY_ID_LISTSOURCE : + bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aListSource); + break; + + case PROPERTY_ID_EMPTY_IS_NULL : + bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_bEmptyIsNull); + break; + + case PROPERTY_ID_DEFAULT_TEXT : + bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aDefaultText); + break; + + case PROPERTY_ID_STRINGITEMLIST: + bModified = convertNewListSourceProperty( _rConvertedValue, _rOldValue, _rValue ); + break; + + case PROPERTY_ID_TYPEDITEMLIST : + if (hasExternalListSource()) + throw IllegalArgumentException(); + bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, getTypedItemList()); + break; + + default: + bModified = OBoundControlModel::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue); + break; + } + return bModified; +} + +void OComboBoxModel::describeFixedProperties( Sequence< Property >& _rProps ) const +{ + OBoundControlModel::describeFixedProperties( _rProps ); + sal_Int32 nOldCount = _rProps.getLength(); + _rProps.realloc( nOldCount + 7); + css::beans::Property* pProperties = _rProps.getArray() + nOldCount; + *pProperties++ = css::beans::Property(PROPERTY_TABINDEX, PROPERTY_ID_TABINDEX, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND); + *pProperties++ = css::beans::Property(PROPERTY_LISTSOURCETYPE, PROPERTY_ID_LISTSOURCETYPE, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND); + *pProperties++ = css::beans::Property(PROPERTY_LISTSOURCE, PROPERTY_ID_LISTSOURCE, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND); + *pProperties++ = css::beans::Property(PROPERTY_EMPTY_IS_NULL, PROPERTY_ID_EMPTY_IS_NULL, cppu::UnoType::get(), + css::beans::PropertyAttribute::BOUND); + *pProperties++ = css::beans::Property(PROPERTY_DEFAULT_TEXT, PROPERTY_ID_DEFAULT_TEXT, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND); + *pProperties++ = css::beans::Property(PROPERTY_STRINGITEMLIST, PROPERTY_ID_STRINGITEMLIST, cppu::UnoType>::get(), css::beans::PropertyAttribute::BOUND); + *pProperties++ = css::beans::Property(PROPERTY_TYPEDITEMLIST, PROPERTY_ID_TYPEDITEMLIST, cppu::UnoType>::get(), css::beans::PropertyAttribute::OPTIONAL); + DBG_ASSERT( pProperties == _rProps.getArray() + _rProps.getLength(), "<...>::describeFixedProperties/getInfoHelper: forgot to adjust the count ?"); +} + + +void OComboBoxModel::describeAggregateProperties( Sequence< Property >& _rAggregateProps ) const +{ + OBoundControlModel::describeAggregateProperties( _rAggregateProps ); + + // superseded properties: + RemoveProperty( _rAggregateProps, PROPERTY_STRINGITEMLIST ); + RemoveProperty( _rAggregateProps, PROPERTY_TYPEDITEMLIST ); +} + + +OUString SAL_CALL OComboBoxModel::getServiceName() +{ + return FRM_COMPONENT_COMBOBOX; // old (non-sun) name for compatibility ! +} + + +void SAL_CALL OComboBoxModel::write(const Reference& _rxOutStream) +{ + OBoundControlModel::write(_rxOutStream); + + // Version + // Version 0x0002: EmptyIsNull + // Version 0x0003: ListSource->Seq + // Version 0x0004: DefaultText + // Version 0x0005: HelpText + _rxOutStream->writeShort(0x0006); + + // Mask for Any + sal_uInt16 nAnyMask = 0; + if (m_aBoundColumn.getValueType().getTypeClass() == TypeClass_SHORT) + nAnyMask |= BOUNDCOLUMN; + _rxOutStream << nAnyMask; + + css::uno::Sequence aListSourceSeq(&m_aListSource, 1); + _rxOutStream << aListSourceSeq; + _rxOutStream << static_cast(m_eListSourceType); + + if ((nAnyMask & BOUNDCOLUMN) == BOUNDCOLUMN) + { + sal_Int16 nBoundColumn = 0; + m_aBoundColumn >>= nBoundColumn; + _rxOutStream << nBoundColumn; + } + + _rxOutStream << m_bEmptyIsNull; + _rxOutStream << m_aDefaultText; + writeHelpTextCompatibly(_rxOutStream); + + // from version 0x0006 : common properties + writeCommonProperties(_rxOutStream); +} + + +void SAL_CALL OComboBoxModel::read(const Reference& _rxInStream) +{ + OBoundControlModel::read(_rxInStream); + ControlModelLock aLock( *this ); + + // since we are "overwriting" the StringItemList of our aggregate (means we have + // an own place to store the value, instead of relying on our aggregate storing it), + // we need to respect what the aggregate just read for the StringItemList property. + try + { + if ( m_xAggregateSet.is() ) + setNewStringItemList( m_xAggregateSet->getPropertyValue( PROPERTY_STRINGITEMLIST ), aLock ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "forms.component", "OComboBoxModel::read: caught an exception while examining the aggregate's string item list!" ); + } + + // Version + sal_uInt16 nVersion = _rxInStream->readShort(); + DBG_ASSERT(nVersion > 0, "OComboBoxModel::read : version 0 ? this should never have been written !"); + + if (nVersion > 0x0006) + { + OSL_FAIL("OComboBoxModel::read : invalid (means unknown) version !"); + m_aListSource.clear(); + m_aBoundColumn <<= sal_Int16(0); + m_aDefaultText.clear(); + m_eListSourceType = ListSourceType_TABLE; + m_bEmptyIsNull = true; + defaultCommonProperties(); + return; + } + + // Mask for Any + sal_uInt16 nAnyMask; + _rxInStream >> nAnyMask; + + // ListSource + if (nVersion < 0x0003) + { + _rxInStream >> m_aListSource; + } + else // nVersion == 4 + { + m_aListSource.clear(); + css::uno::Sequence aListSource; + _rxInStream >> aListSource; + for (const OUString& rToken : std::as_const(aListSource)) + m_aListSource += rToken; + } + + sal_Int16 nListSourceType; + _rxInStream >> nListSourceType; + m_eListSourceType = static_cast(nListSourceType); + + if ((nAnyMask & BOUNDCOLUMN) == BOUNDCOLUMN) + { + sal_Int16 nValue; + _rxInStream >> nValue; + m_aBoundColumn <<= nValue; + } + + if (nVersion > 0x0001) + { + bool bNull; + _rxInStream >> bNull; + m_bEmptyIsNull = bNull; + } + + if (nVersion > 0x0003) // nVersion == 4 + _rxInStream >> m_aDefaultText; + + // StringList must be emptied if a ListSource is set. + // This can be the case if we save in alive mode. + if ( !m_aListSource.isEmpty() + && !hasExternalListSource() + ) + { + setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, Any( css::uno::Sequence() ) ); + setFastPropertyValue( PROPERTY_ID_TYPEDITEMLIST, Any( css::uno::Sequence() ) ); + } + + if (nVersion > 0x0004) + readHelpTextCompatibly(_rxInStream); + + if (nVersion > 0x0005) + readCommonProperties(_rxInStream); + + // After reading in, display the default values + if ( !getControlSource().isEmpty() ) + { + // (not if we don't have a control source - the "State" property acts like it is persistent, then + resetNoBroadcast(); + } +} + + +void OComboBoxModel::loadData( bool _bForce ) +{ + DBG_ASSERT(m_eListSourceType != ListSourceType_VALUELIST, "OComboBoxModel::loadData : do not call for a value list !"); + DBG_ASSERT( !hasExternalListSource(), "OComboBoxModel::loadData: cannot load from DB when I have an external list source!" ); + + if ( hasExternalListSource() ) + return; + + // Get Connection + if (!m_xCursor.is()) + return; + Reference xConnection = getConnection(m_xCursor); + if (!xConnection.is()) + return; + + Reference xServiceInfo(xConnection, UNO_QUERY); + if (!xServiceInfo.is() || !xServiceInfo->supportsService(SRV_SDB_CONNECTION)) + { + OSL_FAIL("OComboBoxModel::loadData : invalid connection !"); + return; + } + + if (m_aListSource.isEmpty() || m_eListSourceType == ListSourceType_VALUELIST) + return; + + ::utl::SharedUNOComponent< XResultSet > xListCursor; + try + { + m_aListRowSet.setConnection( xConnection ); + + bool bExecuteRowSet( false ); + switch (m_eListSourceType) + { + case ListSourceType_TABLEFIELDS: + // don't work with a statement here, the fields will be collected below + break; + case ListSourceType_TABLE: + { + // does the bound field belong to the table ? + // if we use an alias for the bound field, we won't find it + // in that case we use the first field of the table + + Reference xFieldsByName = getTableFields(xConnection, m_aListSource); + + OUString aFieldName; + if ( xFieldsByName.is() && xFieldsByName->hasByName( getControlSource() ) ) + { + aFieldName = getControlSource(); + } + else + { + // otherwise look for the alias + Reference xFormProp(m_xCursor,UNO_QUERY); + Reference< XColumnsSupplier > xSupplyFields; + xFormProp->getPropertyValue("SingleSelectQueryComposer") >>= xSupplyFields; + + // search the field + DBG_ASSERT(xSupplyFields.is(), "OComboBoxModel::loadData : invalid query composer !"); + + Reference< XNameAccess > xFieldNames = xSupplyFields->getColumns(); + if ( xFieldNames->hasByName( getControlSource() ) ) + { + Reference< XPropertySet > xComposerFieldAsSet; + xFieldNames->getByName( getControlSource() ) >>= xComposerFieldAsSet; + if (hasProperty(PROPERTY_FIELDSOURCE, xComposerFieldAsSet)) + xComposerFieldAsSet->getPropertyValue(PROPERTY_FIELDSOURCE) >>= aFieldName; + } + } + + if (aFieldName.isEmpty()) + break; + + Reference xMeta = xConnection->getMetaData(); + OSL_ENSURE(xMeta.is(),"No database meta data!"); + if ( xMeta.is() ) + { + OUString aQuote = xMeta->getIdentifierQuoteString(); + + OUString sCatalog, sSchema, sTable; + qualifiedNameComponents( xMeta, m_aListSource, sCatalog, sSchema, sTable, EComposeRule::InDataManipulation ); + + OUString aStatement = + "SELECT DISTINCT " + + quoteName( aQuote, aFieldName ) + + " FROM " + + composeTableNameForSelect( xConnection, sCatalog, sSchema, sTable ); + + m_aListRowSet.setEscapeProcessing( false ); + m_aListRowSet.setCommand( aStatement ); + bExecuteRowSet = true; + } + } break; + case ListSourceType_QUERY: + { + m_aListRowSet.setCommandFromQuery( m_aListSource ); + bExecuteRowSet = true; + } + break; + + default: + { + m_aListRowSet.setEscapeProcessing( ListSourceType_SQLPASSTHROUGH != m_eListSourceType ); + m_aListRowSet.setCommand( m_aListSource ); + bExecuteRowSet = true; + } + } + + if ( bExecuteRowSet ) + { + if ( !_bForce && !m_aListRowSet.isDirty() ) + { + // if none of the settings of the row set changed, compared to the last + // invocation of loadData, then don't re-fill the list. Instead, assume + // the list entries are the same. + return; + } + xListCursor.reset( m_aListRowSet.execute() ); + } + } + catch(const SQLException& eSQL) + { + onError(eSQL, ResourceManager::loadString(RID_BASELISTBOX_ERROR_FILLLIST)); + return; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("forms.component"); + return; + } + + ::std::vector< OUString > aStringList; + aStringList.reserve(16); + try + { + OSL_ENSURE( xListCursor.is() || ( ListSourceType_TABLEFIELDS == m_eListSourceType ), + "OComboBoxModel::loadData: logic error!" ); + if ( !xListCursor.is() && ( ListSourceType_TABLEFIELDS != m_eListSourceType ) ) + return; + + switch (m_eListSourceType) + { + case ListSourceType_SQL: + case ListSourceType_SQLPASSTHROUGH: + case ListSourceType_TABLE: + case ListSourceType_QUERY: + { + // The XDatabaseVariant of the first column + Reference xSupplyCols(xListCursor, UNO_QUERY); + DBG_ASSERT(xSupplyCols.is(), "OComboBoxModel::loadData : cursor supports the row set service but is no column supplier?!"); + Reference xColumns; + if (xSupplyCols.is()) + { + xColumns.set(xSupplyCols->getColumns(), UNO_QUERY); + DBG_ASSERT(xColumns.is(), "OComboBoxModel::loadData : no columns supplied by the row set !"); + } + Reference< XPropertySet > xDataField; + if ( xColumns.is() ) + xColumns->getByIndex(0) >>= xDataField; + if ( !xDataField.is() ) + return; + + ::dbtools::FormattedColumnValue aValueFormatter( getContext(), m_xCursor, xDataField ); + + // Fill Lists + sal_Int16 i = 0; + // At the moment by definition the list cursor is positioned _before_ the first row + while (xListCursor->next() && (i++ xFieldNames = getTableFields(xConnection, m_aListSource); + if (xFieldNames.is()) + { + const Sequence aFieldNames = xFieldNames->getElementNames(); + aStringList.insert(aStringList.end(), aFieldNames.begin(), aFieldNames.end()); + } + } + break; + default: + OSL_FAIL( "OComboBoxModel::loadData: unreachable!" ); + break; + } + } + catch(const SQLException& eSQL) + { + onError(eSQL, ResourceManager::loadString(RID_BASELISTBOX_ERROR_FILLLIST)); + return; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("forms.component"); + return; + } + + // Set String-Sequence at ListBox + setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, Any( comphelper::containerToSequence(aStringList) ) ); + // Reset TypedItemList, no matching data. + setFastPropertyValue( PROPERTY_ID_TYPEDITEMLIST, Any( css::uno::Sequence() ) ); +} + + +void OComboBoxModel::onConnectedDbColumn( const Reference< XInterface >& _rxForm ) +{ + Reference xField = getField(); + if ( xField.is() ) + m_pValueFormatter.reset( new ::dbtools::FormattedColumnValue( getContext(), Reference< XRowSet >( _rxForm, UNO_QUERY ), xField ) ); + getPropertyValue( PROPERTY_STRINGITEMLIST ) >>= m_aDesignModeStringItems; + + // Only load data if a ListSource was supplied + if ( !m_aListSource.isEmpty() && m_xCursor.is() && !hasExternalListSource() ) + loadData( false ); +} + + +void OComboBoxModel::onDisconnectedDbColumn() +{ + m_pValueFormatter.reset(); + + // reset the string item list + if ( !hasExternalListSource() ) + setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, Any( m_aDesignModeStringItems ) ); + + m_aListRowSet.dispose(); +} + + +void SAL_CALL OComboBoxModel::reloaded( const EventObject& aEvent ) +{ + OBoundControlModel::reloaded(aEvent); + + // reload data if we have a list source + if ( !m_aListSource.isEmpty() && m_xCursor.is() && !hasExternalListSource() ) + loadData( false ); +} + + +void OComboBoxModel::resetNoBroadcast() +{ + OBoundControlModel::resetNoBroadcast(); + m_aLastKnownValue.clear(); +} + + +bool OComboBoxModel::commitControlValueToDbColumn( bool _bPostReset ) +{ + Any aNewValue( m_xAggregateFastSet->getFastPropertyValue( getValuePropertyAggHandle() ) ); + + OUString sNewValue; + aNewValue >>= sNewValue; + + bool bModified = ( aNewValue != m_aLastKnownValue ); + if ( bModified ) + { + if ( !aNewValue.hasValue() + || ( sNewValue.isEmpty() // an empty string + && m_bEmptyIsNull // which should be interpreted as NULL + ) + ) + { + m_xColumnUpdate->updateNull(); + } + else + { + try + { + OSL_PRECOND(m_pValueFormatter, + "OComboBoxModel::commitControlValueToDbColumn: no value formatter!"); + if (m_pValueFormatter) + { + if ( !m_pValueFormatter->setFormattedValue( sNewValue ) ) + return false; + } + else + m_xColumnUpdate->updateString( sNewValue ); + } + catch ( const Exception& ) + { + return false; + } + } + + m_aLastKnownValue = aNewValue; + } + + // add the new value to the list + bool bAddToList = bModified && !_bPostReset; + // (only if this is not the "commit" triggered by a "reset") + + if ( !bAddToList ) + return true; + + css::uno::Sequence aStringItemList; + if ( !(getPropertyValue( PROPERTY_STRINGITEMLIST ) >>= aStringItemList) ) + return true; + + bool bFound = false; + for (const OUString& rStringItem : std::as_const(aStringItemList)) + { + if ( (bFound = rStringItem == sNewValue) ) + break; + } + + // not found -> add + if (!bFound) + { + sal_Int32 nOldLen = aStringItemList.getLength(); + aStringItemList.realloc( nOldLen + 1 ); + aStringItemList.getArray()[ nOldLen ] = sNewValue; + + setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, Any( aStringItemList ) ); + setFastPropertyValue( PROPERTY_ID_TYPEDITEMLIST, Any( css::uno::Sequence() ) ); + } + + return true; +} + +// XPropertiesChangeListener + +Any OComboBoxModel::translateDbColumnToControlValue() +{ + OSL_PRECOND(m_pValueFormatter, + "OComboBoxModel::translateDbColumnToControlValue: no value formatter!"); + if (m_pValueFormatter) + { + OUString sValue( m_pValueFormatter->getFormattedValue() ); + if ( sValue.isEmpty() + && m_pValueFormatter->getColumn().is() + && m_pValueFormatter->getColumn()->wasNull() + ) + { + m_aLastKnownValue.clear(); + } + else + { + + m_aLastKnownValue <<= sValue; + } + } + else + m_aLastKnownValue.clear(); + + return m_aLastKnownValue.hasValue() ? m_aLastKnownValue : Any( OUString() ); + // (m_aLastKnownValue is allowed to be VOID, the control value isn't) +} + + +Any OComboBoxModel::getDefaultForReset() const +{ + return Any( m_aDefaultText ); +} + + +void OComboBoxModel::stringItemListChanged( ControlModelLock& /*_rInstanceLock*/ ) +{ + if ( m_xAggregateSet.is() ) + { + m_xAggregateSet->setPropertyValue( PROPERTY_STRINGITEMLIST, Any( comphelper::containerToSequence(getStringItemList()) ) ); + m_xAggregateSet->setPropertyValue( PROPERTY_TYPEDITEMLIST, Any( getTypedItemList()) ) ; + } +} + + +void OComboBoxModel::refreshInternalEntryList() +{ + DBG_ASSERT( !hasExternalListSource(), "OComboBoxModel::refreshInternalEntryList: invalid call!" ); + + if ( !hasExternalListSource( ) + && ( m_eListSourceType != ListSourceType_VALUELIST ) + && ( m_xCursor.is() ) + ) + { + loadData( true ); + } +} + + +void SAL_CALL OComboBoxModel::disposing( const EventObject& _rSource ) +{ + if ( !OEntryListHelper::handleDisposing( _rSource ) ) + OBoundControlModel::disposing( _rSource ); +} + + +//= OComboBoxControl + +OComboBoxControl::OComboBoxControl(const Reference& _rxContext) + :OBoundControl(_rxContext, VCL_CONTROL_COMBOBOX) +{ +} + + +css::uno::Sequence SAL_CALL OComboBoxControl::getSupportedServiceNames() +{ + css::uno::Sequence aSupported = OBoundControl::getSupportedServiceNames(); + aSupported.realloc(aSupported.getLength() + 2); + + OUString* pArray = aSupported.getArray(); + pArray[aSupported.getLength()-2] = FRM_SUN_CONTROL_COMBOBOX; + pArray[aSupported.getLength()-1] = STARDIV_ONE_FORM_CONTROL_COMBOBOX; + return aSupported; +} + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_form_OComboBoxModel_get_implementation(css::uno::XComponentContext* component, + css::uno::Sequence const &) +{ + return cppu::acquire(new frm::OComboBoxModel(component)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_form_OComboBoxControl_get_implementation(css::uno::XComponentContext* component, + css::uno::Sequence const &) +{ + return cppu::acquire(new frm::OComboBoxControl(component)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/forms/source/component/ComboBox.hxx b/forms/source/component/ComboBox.hxx new file mode 100644 index 000000000..ed2360144 --- /dev/null +++ b/forms/source/component/ComboBox.hxx @@ -0,0 +1,145 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include "errorbroadcaster.hxx" +#include "entrylisthelper.hxx" +#include "cachedrowset.hxx" + +#include + +#include + + +namespace frm +{ + +class OComboBoxModel final + :public OBoundControlModel + ,public OEntryListHelper + ,public OErrorBroadcaster +{ + CachedRowSet m_aListRowSet; // the row set to fill the list + css::uno::Any m_aBoundColumn; // obsolete + OUString m_aListSource; + OUString m_aDefaultText; // DefaultText + css::uno::Any m_aLastKnownValue; + + css::uno::Sequence m_aDesignModeStringItems; + + css::form::ListSourceType m_eListSourceType; // ListSource's type + bool m_bEmptyIsNull; // Empty string is interpreted as NULL + + ::std::unique_ptr< ::dbtools::FormattedColumnValue > m_pValueFormatter; + + virtual css::uno::Sequence< css::uno::Type> _getTypes() override; + +public: + OComboBoxModel( + const css::uno::Reference< css::uno::XComponentContext>& _rxFactory + ); + OComboBoxModel( + const OComboBoxModel* _pOriginal, + const css::uno::Reference< css::uno::XComponentContext>& _rxFactory + ); + virtual ~OComboBoxModel() override; + + virtual void SAL_CALL disposing() override; + + // OPropertySetHelper + virtual void SAL_CALL getFastPropertyValue(css::uno::Any& rValue, sal_Int32 nHandle) const override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const css::uno::Any& rValue ) override; + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any& _rConvertedValue, css::uno::Any& _rOldValue, sal_Int32 _nHandle, const css::uno::Any& _rValue ) override; + + // XLoadListener + virtual void SAL_CALL reloaded( const css::lang::EventObject& aEvent ) override; + + // XServiceInfo + OUString SAL_CALL getImplementationName() override + { return "com.sun.star.form.OComboBoxModel"; } + + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // UNO + DECLARE_UNO3_AGG_DEFAULTS(OComboBoxModel, OBoundControlModel) + virtual css::uno::Any SAL_CALL queryAggregation( const css::uno::Type& _rType ) override; + + // XPersistObject + virtual OUString SAL_CALL getServiceName() override; + virtual void SAL_CALL + write(const css::uno::Reference< css::io::XObjectOutputStream>& _rxOutStream) override; + virtual void SAL_CALL + read(const css::uno::Reference< css::io::XObjectInputStream>& _rxInStream) override; + + // OControlModel's property handling + virtual void describeFixedProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps + ) const override; + virtual void describeAggregateProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps + ) const override; + + // XEventListener + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + + // prevent method hiding + using OBoundControlModel::getFastPropertyValue; + +private: + // OBoundControlModel overridables + virtual css::uno::Any translateDbColumnToControlValue( ) override; + virtual bool commitControlValueToDbColumn( bool _bPostReset ) override; + + virtual void onConnectedDbColumn( const css::uno::Reference< css::uno::XInterface >& _rxForm ) override; + virtual void onDisconnectedDbColumn() override; + + virtual css::uno::Any getDefaultForReset() const override; + + virtual void resetNoBroadcast() override; + + // OEntryListHelper overridables + virtual void stringItemListChanged( ControlModelLock& _rInstanceLock ) override; + virtual void refreshInternalEntryList() override; + + void loadData( bool _bForce ); + + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone( ) override; +}; + +class OComboBoxControl : public OBoundControl +{ +public: + explicit OComboBoxControl(const css::uno::Reference< css::uno::XComponentContext>& _rxContext); + + // XServiceInfo + OUString SAL_CALL getImplementationName() override + { return "com.sun.star.form.OComboBoxControl"; } + + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; +}; + + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/forms/source/component/Currency.cxx b/forms/source/component/Currency.cxx new file mode 100644 index 000000000..2e4839dd8 --- /dev/null +++ b/forms/source/component/Currency.cxx @@ -0,0 +1,253 @@ +/* -*- 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 "Currency.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace frm +{ + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; + +OCurrencyControl::OCurrencyControl(const Reference& _rxFactory) + :OBoundControl(_rxFactory, VCL_CONTROL_CURRENCYFIELD) +{ +} + +css::uno::Sequence SAL_CALL OCurrencyControl::getSupportedServiceNames() +{ + css::uno::Sequence aSupported = OBoundControl::getSupportedServiceNames(); + aSupported.realloc(aSupported.getLength() + 2); + + OUString*pArray = aSupported.getArray(); + pArray[aSupported.getLength()-2] = FRM_SUN_CONTROL_CURRENCYFIELD; + pArray[aSupported.getLength()-1] = STARDIV_ONE_FORM_CONTROL_CURRENCYFIELD; + return aSupported; +} + + +// OCurrencyModel + +void OCurrencyModel::implConstruct() +{ + if (!m_xAggregateSet.is()) + return; + + try + { + // get the system international information + const SvtSysLocale aSysLocale; + const LocaleDataWrapper& aLocaleInfo = aSysLocale.GetLocaleData(); + + OUString sCurrencySymbol; + bool bPrependCurrencySymbol = false; + switch ( aLocaleInfo.getCurrPositiveFormat() ) + { + case 0: // $1 + sCurrencySymbol = aLocaleInfo.getCurrSymbol(); + bPrependCurrencySymbol = true; + break; + case 1: // 1$ + sCurrencySymbol = aLocaleInfo.getCurrSymbol(); + bPrependCurrencySymbol = false; + break; + case 2: // $ 1 + sCurrencySymbol = aLocaleInfo.getCurrSymbol() + " "; + bPrependCurrencySymbol = true; + break; + case 3: // 1 $ + sCurrencySymbol = " " + aLocaleInfo.getCurrSymbol(); + bPrependCurrencySymbol = false; + break; + } + if (!sCurrencySymbol.isEmpty()) + { + m_xAggregateSet->setPropertyValue(PROPERTY_CURRENCYSYMBOL, Any(sCurrencySymbol)); + m_xAggregateSet->setPropertyValue(PROPERTY_CURRSYM_POSITION, Any(bPrependCurrencySymbol)); + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION( "forms.component", "OCurrencyModel::implConstruct: caught an exception while initializing the aggregate!" ); + } +} + + +OCurrencyModel::OCurrencyModel(const Reference& _rxFactory) + :OEditBaseModel( _rxFactory, VCL_CONTROLMODEL_CURRENCYFIELD, FRM_SUN_CONTROL_CURRENCYFIELD, false, true ) + // use the old control name for compatibility reasons +{ + + m_nClassId = FormComponentType::CURRENCYFIELD; + initValueProperty( PROPERTY_VALUE, PROPERTY_ID_VALUE ); + + implConstruct(); +} + + +OCurrencyModel::OCurrencyModel( const OCurrencyModel* _pOriginal, const Reference& _rxFactory ) + :OEditBaseModel( _pOriginal, _rxFactory ) +{ + implConstruct(); +} + + +OCurrencyModel::~OCurrencyModel() +{ +} + +// XCloneable + +css::uno::Reference< css::util::XCloneable > SAL_CALL OCurrencyModel::createClone() +{ + rtl::Reference pClone = new OCurrencyModel(this, getContext()); + pClone->clonedFrom(this); + return pClone; +} + + +// XServiceInfo + +css::uno::Sequence SAL_CALL OCurrencyModel::getSupportedServiceNames() +{ + css::uno::Sequence aSupported = OBoundControlModel::getSupportedServiceNames(); + + sal_Int32 nOldLen = aSupported.getLength(); + aSupported.realloc( nOldLen + 5 ); + OUString* pStoreTo = aSupported.getArray() + nOldLen; + + *pStoreTo++ = DATA_AWARE_CONTROL_MODEL; + *pStoreTo++ = VALIDATABLE_CONTROL_MODEL; + + *pStoreTo++ = FRM_SUN_COMPONENT_CURRENCYFIELD; + *pStoreTo++ = FRM_SUN_COMPONENT_DATABASE_CURRENCYFIELD; + + *pStoreTo++ = FRM_COMPONENT_CURRENCYFIELD; + + return aSupported; +} + + +void OCurrencyModel::describeFixedProperties( Sequence< Property >& _rProps ) const +{ + OEditBaseModel::describeFixedProperties( _rProps ); + sal_Int32 nOldCount = _rProps.getLength(); + _rProps.realloc( nOldCount + 2); + css::beans::Property* pProperties = _rProps.getArray() + nOldCount; + // Set Value to transient + // ModifyPropertyAttributes(_rAggregateProps, PROPERTY_VALUE, PropertyAttribute::TRANSIENT, 0); + + *pProperties++ = css::beans::Property(PROPERTY_DEFAULT_VALUE, PROPERTY_ID_DEFAULT_VALUE, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEDEFAULT | css::beans::PropertyAttribute::MAYBEVOID); + *pProperties++ = css::beans::Property(PROPERTY_TABINDEX, PROPERTY_ID_TABINDEX, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND); + DBG_ASSERT( pProperties == _rProps.getArray() + _rProps.getLength(), "<...>::describeFixedProperties/getInfoHelper: forgot to adjust the count ?"); +} + + +OUString SAL_CALL OCurrencyModel::getServiceName() +{ + return FRM_COMPONENT_CURRENCYFIELD; // old (non-sun) name for compatibility ! +} + + +bool OCurrencyModel::commitControlValueToDbColumn( bool /*_bPostReset*/ ) +{ + Any aControlValue( m_xAggregateFastSet->getFastPropertyValue( getValuePropertyAggHandle() ) ); + if ( aControlValue != m_aSaveValue ) + { + if ( aControlValue.getValueType().getTypeClass() == TypeClass_VOID ) + m_xColumnUpdate->updateNull(); + else + { + try + { + m_xColumnUpdate->updateDouble( getDouble( aControlValue ) ); + } + catch(const Exception&) + { + return false; + } + } + m_aSaveValue = aControlValue; + } + return true; +} + + +Any OCurrencyModel::translateDbColumnToControlValue() +{ + m_aSaveValue <<= m_xColumn->getDouble(); + if ( m_xColumn->wasNull() ) + m_aSaveValue.clear(); + return m_aSaveValue; +} + +// XReset + +Any OCurrencyModel::getDefaultForReset() const +{ + Any aValue; + if ( m_aDefault.getValueType().getTypeClass() == TypeClass_DOUBLE ) + aValue = m_aDefault; + + return aValue; +} + + +void OCurrencyModel::resetNoBroadcast() +{ + OEditBaseModel::resetNoBroadcast(); + m_aSaveValue.clear(); +} + + +} // namespace frm + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_form_OCurrencyModel_get_implementation(css::uno::XComponentContext* component, + css::uno::Sequence const &) +{ + return cppu::acquire(new frm::OCurrencyModel(component)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_form_OCurrencyControl_get_implementation(css::uno::XComponentContext* component, + css::uno::Sequence const &) +{ + return cppu::acquire(new frm::OCurrencyControl(component)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/forms/source/component/Currency.hxx b/forms/source/component/Currency.hxx new file mode 100644 index 000000000..f77f711f0 --- /dev/null +++ b/forms/source/component/Currency.hxx @@ -0,0 +1,85 @@ +/* -*- 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 . + */ + +#pragma once + +#include "EditBase.hxx" + + +namespace frm +{ + +class OCurrencyModel final + :public OEditBaseModel +{ + css::uno::Any m_aSaveValue; + +public: + OCurrencyModel( + const css::uno::Reference< css::uno::XComponentContext>& _rxFactory + ); + OCurrencyModel( + const OCurrencyModel* _pOriginal, + const css::uno::Reference< css::uno::XComponentContext>& _rxFactory + ); + virtual ~OCurrencyModel() override; + + // css::lang::XServiceInfo + OUString SAL_CALL getImplementationName() override + { return "com.sun.star.form.OCurrencyModel"; } + + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // css::io::XPersistObject + virtual OUString SAL_CALL getServiceName() override; + + // OControlModel's property handling + virtual void describeFixedProperties( + css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps + ) const override; + +private: + // OBoundControlModel overridables + virtual css::uno::Any translateDbColumnToControlValue( ) override; + virtual bool commitControlValueToDbColumn( bool _bPostReset ) override; + + virtual css::uno::Any getDefaultForReset() const override; + + virtual void resetNoBroadcast() override; + + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone( ) override; + + void implConstruct(); +}; + +class OCurrencyControl: public OBoundControl +{ +public: + explicit OCurrencyControl(const css::uno::Reference< css::uno::XComponentContext>& _rxContext); + // css::lang::XServiceInfo + OUString SAL_CALL getImplementationName() override + { return "com.sun.star.form.OCurrencyControl"; } + + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; +}; + + +} // namespace frm + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/forms/source/component/DatabaseForm.cxx b/forms/source/component/DatabaseForm.cxx new file mode 100644 index 000000000..cfb22d927 --- /dev/null +++ b/forms/source/component/DatabaseForm.cxx @@ -0,0 +1,4044 @@ +/* -*- 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 + +#include + +#include +#include "DatabaseForm.hxx" +#include "EventThread.hxx" +#include +#include +#include "GroupManager.hxx" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::dbtools; +using namespace ::comphelper; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; + + +namespace frm +{ + +namespace { + +class DocumentModifyGuard +{ +public: + explicit DocumentModifyGuard( const Reference< XInterface >& _rxFormComponent ) + :m_xDocumentModify( getXModel( _rxFormComponent ), UNO_QUERY ) + { + impl_changeModifiableFlag_nothrow( false ); + } + ~DocumentModifyGuard() + { + impl_changeModifiableFlag_nothrow( true ); + } + +private: + void impl_changeModifiableFlag_nothrow( const bool _enable ) + { + try + { + if ( m_xDocumentModify.is() ) + _enable ? m_xDocumentModify->enableSetModified() : m_xDocumentModify->disableSetModified(); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("forms.component"); + } + } + +private: + Reference< XModifiable2 > m_xDocumentModify; +}; + +} + +// submitting and resetting html-forms asynchronously +class OFormSubmitResetThread: public OComponentEventThread +{ +protected: + + // process an event. while processing the mutex isn't locked, and pCompImpl + // is made sure to remain valid + virtual void processEvent( ::cppu::OComponentHelper* _pCompImpl, + const EventObject* _pEvt, + const Reference& _rControl, + bool _bSubmit) override; + +public: + + explicit OFormSubmitResetThread(ODatabaseForm* pControl) : OComponentEventThread(pControl) { } +}; + + +void OFormSubmitResetThread::processEvent( + ::cppu::OComponentHelper* pCompImpl, + const EventObject *_pEvt, + const Reference& _rControl, + bool _bSubmit) +{ + if (_bSubmit) + static_cast(pCompImpl)->submit_impl(_rControl, *static_cast(_pEvt)); + else + static_cast(pCompImpl)->reset_impl(true); +} + + +//= ODatabaseForm + +Sequence SAL_CALL ODatabaseForm::getImplementationId() +{ + return css::uno::Sequence(); +} + + +Sequence SAL_CALL ODatabaseForm::getTypes() +{ + // ask the aggregate + Sequence aAggregateTypes; + Reference xAggregateTypes; + if (query_aggregation(m_xAggregate, xAggregateTypes)) + aAggregateTypes = xAggregateTypes->getTypes(); + + Sequence< Type > aRet = concatSequences( + aAggregateTypes, ODatabaseForm_BASE1::getTypes(), OFormComponents::getTypes() + ); + aRet = concatSequences( aRet, ODatabaseForm_BASE2::getTypes(), ODatabaseForm_BASE3::getTypes() ); + return concatSequences( aRet, OPropertySetAggregationHelper::getTypes() ); +} + + +Any SAL_CALL ODatabaseForm::queryAggregation(const Type& _rType) +{ + Any aReturn = ODatabaseForm_BASE1::queryInterface(_rType); + // our own interfaces + if (!aReturn.hasValue()) + { + aReturn = ODatabaseForm_BASE2::queryInterface(_rType); + // property set related interfaces + if (!aReturn.hasValue()) + { + aReturn = OPropertySetAggregationHelper::queryInterface(_rType); + + // form component collection related interfaces + if (!aReturn.hasValue()) + { + aReturn = OFormComponents::queryAggregation(_rType); + + // interfaces already present in the aggregate which we want to reroute + // only available if we could create the aggregate + if (!aReturn.hasValue() && m_xAggregateAsRowSet.is()) + aReturn = ODatabaseForm_BASE3::queryInterface(_rType); + + // aggregate interfaces + // (ask the aggregated object _after_ the OComponentHelper (base of OFormComponents), + // so calls to the XComponent interface reach us and not the aggregation) + if (!aReturn.hasValue() && m_xAggregate.is()) + aReturn = m_xAggregate->queryAggregation(_rType); + } + } + } + + return aReturn; +} + + +ODatabaseForm::ODatabaseForm(const Reference& _rxContext) + :OFormComponents(_rxContext) + ,OPropertySetAggregationHelper(OComponentHelper::rBHelper) + ,OPropertyChangeListener(m_aMutex) + ,m_aLoadListeners(m_aMutex) + ,m_aRowSetApproveListeners(m_aMutex) + ,m_aSubmitListeners(m_aMutex) + ,m_aErrorListeners(m_aMutex) + ,m_aResetListeners(m_aMutex) + ,m_aPropertyBagHelper( *this ) + ,m_aParameterManager( m_aMutex, _rxContext ) + ,m_aFilterManager() + ,m_nResetsPending(0) + ,m_nPrivileges(0) + ,m_bInsertOnly( false ) + ,m_eSubmitMethod(FormSubmitMethod_GET) + ,m_eSubmitEncoding(FormSubmitEncoding_URL) + ,m_eNavigation(NavigationBarMode_CURRENT) + ,m_bAllowInsert(true) + ,m_bAllowUpdate(true) + ,m_bAllowDelete(true) + ,m_bLoaded(false) + ,m_bSubForm(false) + ,m_bForwardingConnection(false) + ,m_bSharingConnection( false ) +{ + impl_construct(); +} + + +ODatabaseForm::ODatabaseForm( const ODatabaseForm& _cloneSource ) + :OFormComponents( _cloneSource ) + ,OPropertySetAggregationHelper( OComponentHelper::rBHelper ) + ,OPropertyChangeListener( m_aMutex ) + ,ODatabaseForm_BASE1() + ,ODatabaseForm_BASE2() + ,ODatabaseForm_BASE3() + ,IPropertyBagHelperContext() + ,m_aLoadListeners( m_aMutex ) + ,m_aRowSetApproveListeners( m_aMutex ) + ,m_aSubmitListeners( m_aMutex ) + ,m_aErrorListeners( m_aMutex ) + ,m_aResetListeners( m_aMutex ) + ,m_aPropertyBagHelper( *this ) + ,m_aParameterManager( m_aMutex, _cloneSource.m_xContext ) + ,m_aFilterManager() + ,m_nResetsPending( 0 ) + ,m_nPrivileges( 0 ) + ,m_bInsertOnly( _cloneSource.m_bInsertOnly ) + ,m_aControlBorderColorFocus( _cloneSource.m_aControlBorderColorFocus ) + ,m_aControlBorderColorMouse( _cloneSource.m_aControlBorderColorMouse ) + ,m_aControlBorderColorInvalid( _cloneSource.m_aControlBorderColorInvalid ) + ,m_aDynamicControlBorder( _cloneSource.m_aDynamicControlBorder ) + ,m_sName( _cloneSource.m_sName ) + ,m_aTargetURL( _cloneSource.m_aTargetURL ) + ,m_aTargetFrame( _cloneSource.m_aTargetFrame ) + ,m_eSubmitMethod( _cloneSource.m_eSubmitMethod ) + ,m_eSubmitEncoding( _cloneSource.m_eSubmitEncoding ) + ,m_eNavigation( _cloneSource.m_eNavigation ) + ,m_bAllowInsert( _cloneSource.m_bAllowInsert ) + ,m_bAllowUpdate( _cloneSource.m_bAllowUpdate ) + ,m_bAllowDelete( _cloneSource.m_bAllowDelete ) + ,m_bLoaded( false ) + ,m_bSubForm( false ) + ,m_bForwardingConnection( false ) + ,m_bSharingConnection( false ) +{ + + impl_construct(); + + osl_atomic_increment( &m_refCount ); + { + // our aggregated rowset itself is not cloneable, so simply copy the properties + ::comphelper::copyProperties( _cloneSource.m_xAggregateSet, m_xAggregateSet ); + + // also care for the dynamic properties: If the clone source has properties which we do not have, + // then add them + try + { + Reference< XPropertySet > xSourceProps( const_cast< ODatabaseForm& >( _cloneSource ).queryAggregation( + cppu::UnoType::get() ), UNO_QUERY_THROW ); + Reference< XPropertySetInfo > xSourcePSI( xSourceProps->getPropertySetInfo(), UNO_SET_THROW ); + Reference< XPropertyState > xSourcePropState( xSourceProps, UNO_QUERY ); + + Reference< XPropertySetInfo > xDestPSI( getPropertySetInfo(), UNO_SET_THROW ); + + const Sequence< Property > aSourceProperties( xSourcePSI->getProperties() ); + for ( auto const & sourceProperty : aSourceProperties ) + { + if ( xDestPSI->hasPropertyByName( sourceProperty.Name ) ) + continue; + + // the initial value passed to XPropertyContainer is also used as default, usually. So, try + // to retrieve the default of the source property + Any aInitialValue; + if ( xSourcePropState.is() ) + { + aInitialValue = xSourcePropState->getPropertyDefault( sourceProperty.Name ); + } + else + { + aInitialValue = xSourceProps->getPropertyValue( sourceProperty.Name ); + } + addProperty( sourceProperty.Name, sourceProperty.Attributes, aInitialValue ); + setPropertyValue( sourceProperty.Name, xSourceProps->getPropertyValue( sourceProperty.Name ) ); + } + } + catch(const RuntimeException&) + { + throw; + } + catch(const Exception&) + { + css::uno::Any a(cppu::getCaughtException()); + throw WrappedTargetRuntimeException( + "Could not clone the given database form.", + *const_cast< ODatabaseForm* >( &_cloneSource ), + a + ); + } + } + osl_atomic_decrement( &m_refCount ); +} + +void ODatabaseForm::impl_construct() +{ + // aggregate a row set + osl_atomic_increment(&m_refCount); + { + m_xAggregate.set( m_xContext->getServiceManager()->createInstanceWithContext(SRV_SDB_ROWSET, m_xContext), UNO_QUERY_THROW ); + m_xAggregateAsRowSet.set( m_xAggregate, UNO_QUERY_THROW ); + setAggregation( m_xAggregate ); + } + + // listen for the properties, important for Parameters + if ( m_xAggregateSet.is() ) + { + m_xAggregatePropertyMultiplexer = new OPropertyChangeMultiplexer(this, m_xAggregateSet, false); + m_xAggregatePropertyMultiplexer->addProperty(PROPERTY_COMMAND); + m_xAggregatePropertyMultiplexer->addProperty(PROPERTY_ACTIVE_CONNECTION); + } + + { + Reference< XWarningsSupplier > xRowSetWarnings( m_xAggregate, UNO_QUERY ); + m_aWarnings.setExternalWarnings( xRowSetWarnings ); + } + + if ( m_xAggregate.is() ) + { + m_xAggregate->setDelegator( static_cast< XWeak* >( this ) ); + } + + { + m_aFilterManager.initialize( m_xAggregateSet ); + m_aParameterManager.initialize( this, m_xAggregate ); + + declareForwardedProperty( PROPERTY_ID_ACTIVE_CONNECTION ); + } + osl_atomic_decrement( &m_refCount ); + + m_pGroupManager = new OGroupManager( this ); +} + + +ODatabaseForm::~ODatabaseForm() +{ + m_pGroupManager.clear(); + + if (m_xAggregate.is()) + m_xAggregate->setDelegator( nullptr ); + + m_aWarnings.setExternalWarnings( nullptr ); + + if (m_xAggregatePropertyMultiplexer.is()) + { + m_xAggregatePropertyMultiplexer->dispose(); + m_xAggregatePropertyMultiplexer.clear(); + } +} + + +// html tools + +OUString ODatabaseForm::GetDataEncoded(bool _bURLEncoded,const Reference& SubmitButton, const css::awt::MouseEvent& MouseEvt) +{ + // Fill List of successful Controls + HtmlSuccessfulObjList aSuccObjList; + FillSuccessfulList( aSuccObjList, SubmitButton, MouseEvt ); + + + // Aggregate the list to OUString + OUStringBuffer aResult; + OUString aName; + OUString aValue; + + for ( HtmlSuccessfulObjList::iterator pSuccObj = aSuccObjList.begin(); + pSuccObj < aSuccObjList.end(); + ++pSuccObj + ) + { + aName = pSuccObj->aName; + aValue = pSuccObj->aValue; + if( pSuccObj->nRepresentation == SUCCESSFUL_REPRESENT_FILE && !aValue.isEmpty() ) + { + // For File URLs we transfer the file name and not a URL, because Netscape does it like that + INetURLObject aURL; + aURL.SetSmartProtocol(INetProtocol::File); + aURL.SetSmartURL(aValue); + if( INetProtocol::File == aURL.GetProtocol() ) + aValue = INetURLObject::decode(aURL.PathToFileName(), INetURLObject::DecodeMechanism::Unambiguous); + } + Encode( aName ); + Encode( aValue ); + + aResult.append(aName); + aResult.append('='); + aResult.append(aValue); + + if (pSuccObj < aSuccObjList.end() - 1) + { + if ( _bURLEncoded ) + aResult.append('&'); + else + aResult.append("\r\n"); + } + } + + + aSuccObjList.clear(); + + return aResult.makeStringAndClear(); +} + + +// html tools + +Sequence ODatabaseForm::GetDataMultiPartEncoded(const Reference& SubmitButton, const css::awt::MouseEvent& MouseEvt, OUString& rContentType) +{ + + // Create Parent + INetMIMEMessage aParent; + aParent.EnableAttachMultipartFormDataChild(); + + + // Fill List of successful Controls + HtmlSuccessfulObjList aSuccObjList; + FillSuccessfulList( aSuccObjList, SubmitButton, MouseEvt ); + + + // Aggregate List to OUString + for (auto const& succObj : aSuccObjList) + { + if( succObj.nRepresentation == SUCCESSFUL_REPRESENT_TEXT ) + InsertTextPart( aParent, succObj.aName, succObj.aValue ); + else if( succObj.nRepresentation == SUCCESSFUL_REPRESENT_FILE ) + InsertFilePart( aParent, succObj.aName, succObj.aValue ); + } + + + // Delete List + aSuccObjList.clear(); + + // Create MessageStream for parent + INetMIMEMessageStream aMessStream(&aParent, true); + + // Copy MessageStream to SvStream + SvMemoryStream aMemStream; + std::unique_ptr pBuf(new char[1025]); + int nRead; + while( (nRead = aMessStream.Read(pBuf.get(), 1024)) > 0 ) + { + aMemStream.WriteBytes(pBuf.get(), nRead); + } + pBuf.reset(); + + aMemStream.FlushBuffer(); + aMemStream.Seek( 0 ); + void const * pData = aMemStream.GetData(); + sal_Int32 nLen = aMemStream.TellEnd(); + + rContentType = aParent.GetContentType(); + return Sequence(static_cast(pData), nLen); +} + + +namespace +{ + void appendDigits( sal_Int32 _nNumber, sal_Int8 nDigits, OUStringBuffer& _rOut ) + { + sal_Int32 nCurLen = _rOut.getLength(); + _rOut.append( _nNumber ); + while ( _rOut.getLength() - nCurLen < nDigits ) + _rOut.insert( nCurLen, '0' ); + } +} + + +void ODatabaseForm::AppendComponent(HtmlSuccessfulObjList& rList, const Reference& xComponentSet, std::u16string_view rNamePrefix, + const Reference& rxSubmitButton, const css::awt::MouseEvent& MouseEvt) +{ + if (!xComponentSet.is()) + return; + + // TODO: Catch nested Forms; or would we need to submit them? + if (!hasProperty(PROPERTY_CLASSID, xComponentSet)) + return; + + // Get names + if (!hasProperty(PROPERTY_NAME, xComponentSet)) + return; + + sal_Int16 nClassId = 0; + xComponentSet->getPropertyValue(PROPERTY_CLASSID) >>= nClassId; + OUString aName; + xComponentSet->getPropertyValue( PROPERTY_NAME ) >>= aName; + if( aName.isEmpty() && nClassId != FormComponentType::IMAGEBUTTON) + return; + else // Extend name with the prefix + aName = rNamePrefix + aName; + + switch( nClassId ) + { + // Buttons + case FormComponentType::COMMANDBUTTON: + { + // We only evaluate the pressed Submit button + // If one is passed at all + if( rxSubmitButton.is() ) + { + Reference xSubmitButtonComponent(rxSubmitButton->getModel(), UNO_QUERY); + if (xSubmitButtonComponent == xComponentSet && hasProperty(PROPERTY_LABEL, xComponentSet)) + { + // =