diff options
Diffstat (limited to '')
-rw-r--r-- | forms/source/misc/InterfaceContainer.cxx | 1313 | ||||
-rw-r--r-- | forms/source/misc/componenttools.cxx | 105 | ||||
-rw-r--r-- | forms/source/misc/limitedformats.cxx | 381 | ||||
-rw-r--r-- | forms/source/misc/listenercontainers.cxx | 58 | ||||
-rw-r--r-- | forms/source/misc/property.cxx | 223 |
5 files changed, 2080 insertions, 0 deletions
diff --git a/forms/source/misc/InterfaceContainer.cxx b/forms/source/misc/InterfaceContainer.cxx new file mode 100644 index 000000000..41dbd7f3c --- /dev/null +++ b/forms/source/misc/InterfaceContainer.cxx @@ -0,0 +1,1313 @@ +/* -*- 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 <strings.hrc> +#include <frm_resource.hxx> +#include <frm_strings.hxx> +#include <InterfaceContainer.hxx> +#include <componenttools.hxx> +#include <services.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/io/WrongFormatException.hpp> +#include <com/sun/star/io/XMarkableStream.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/ServiceNotRegisteredException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/util/XCloneable.hpp> +#include <com/sun/star/form/XForm.hpp> + +#include <comphelper/enumhelper.hxx> +#include <comphelper/eventattachermgr.hxx> +#include <comphelper/property.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/types.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <sal/log.hxx> + +#include <algorithm> +#include <memory> + + +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/document/XCodeNameQuery.hpp> +#include <ooo/vba/XVBAToOOEventDescGen.hpp> + +namespace frm +{ + + +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::script; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::util; + +namespace +{ + + void lcl_throwIllegalArgumentException() + { + throw IllegalArgumentException(); + } +} + +static bool +lcl_hasVbaEvents( const Sequence< ScriptEventDescriptor >& sEvents ) +{ + for ( auto const& rDesc : sEvents ) + { + if ( rDesc.ScriptType == "VBAInterop" ) + return true; + } + return false; +} + +static Sequence< ScriptEventDescriptor > +lcl_stripVbaEvents( const Sequence< ScriptEventDescriptor >& sEvents ) +{ + Sequence< ScriptEventDescriptor > sStripped( sEvents.getLength() ); + ScriptEventDescriptor* pStripped = sStripped.getArray(); + + sal_Int32 nCopied = 0; + for ( auto const& rDesc : sEvents ) + { + if ( rDesc.ScriptType != "VBAInterop" ) + { + pStripped[ nCopied++ ] = rDesc; + } + } + sStripped.realloc( nCopied ); + return sStripped; +} + +void OInterfaceContainer::impl_addVbEvents_nolck_nothrow( const sal_Int32 i_nIndex ) +{ + // we are dealing with form controls + try + { + do + { + Reference< XModel > xDoc( getXModel( static_cast< XContainer *> ( this ) ) ); + if ( !xDoc.is() ) + break; + + Reference< XMultiServiceFactory > xDocFac( xDoc, UNO_QUERY_THROW ); + Reference< XCodeNameQuery > xNameQuery( xDocFac->createInstance("ooo.vba.VBACodeNameProvider"), UNO_QUERY ); + if ( !xNameQuery.is() ) + break; + + ::osl::MutexGuard aGuard( m_rMutex ); + bool hasVBABindings = lcl_hasVbaEvents( m_xEventAttacher->getScriptEvents( i_nIndex ) ); + if ( hasVBABindings ) + break; + + Reference< XInterface > xElement( getByIndex( i_nIndex ) , UNO_QUERY_THROW ); + Reference< XForm > xElementAsForm( xElement, UNO_QUERY ); + if ( xElementAsForm.is() ) + break; + + // Try getting the code name from the container first (faster), + // then from the element if that fails (slower). + Reference<XInterface> xThis = static_cast<XContainer*>(this); + OUString sCodeName = xNameQuery->getCodeNameForContainer(xThis); + if (sCodeName.isEmpty()) + sCodeName = xNameQuery->getCodeNameForObject(xElement); + + Reference< XPropertySet > xProps( xElement, UNO_QUERY_THROW ); + OUString sServiceName; + xProps->getPropertyValue("DefaultControl") >>= sServiceName; + + Reference< ooo::vba::XVBAToOOEventDescGen > xDescSupplier( m_xContext->getServiceManager()->createInstanceWithContext("ooo.vba.VBAToOOEventDesc", m_xContext), UNO_QUERY_THROW ); + Sequence< ScriptEventDescriptor > vbaEvents = xDescSupplier->getEventDescriptions( sServiceName , sCodeName ); + + // register the vba script events + m_xEventAttacher->registerScriptEvents( i_nIndex, vbaEvents ); + } + while ( false ); + } + catch ( const ServiceNotRegisteredException& ) + { + // silence this, not all document types support the ooo.vba.VBACodeNameProvider service + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("forms.misc"); + } + +} + +ElementDescription::ElementDescription( ) +{ +} + + +OInterfaceContainer::OInterfaceContainer( + const Reference<XComponentContext>& _rxContext, + ::osl::Mutex& _rMutex, + const Type& _rElementType) + :OInterfaceContainer_BASE() + ,m_rMutex(_rMutex) + ,m_aContainerListeners(_rMutex) + ,m_aElementType(_rElementType) + ,m_xContext(_rxContext) +{ + impl_createEventAttacher_nothrow(); +} + + +OInterfaceContainer::OInterfaceContainer( ::osl::Mutex& _rMutex, const OInterfaceContainer& _cloneSource ) + :OInterfaceContainer_BASE() + ,m_rMutex( _rMutex ) + ,m_aContainerListeners( _rMutex ) + ,m_aElementType( _cloneSource.m_aElementType ) + ,m_xContext( _cloneSource.m_xContext ) +{ + impl_createEventAttacher_nothrow(); +} + +void OInterfaceContainer::clonedFrom(const OInterfaceContainer& _cloneSource) +{ + try + { + const Reference< XIndexAccess > xSourceHierarchy( const_cast< OInterfaceContainer* >( &_cloneSource ) ); + const sal_Int32 nCount = xSourceHierarchy->getCount(); + for ( sal_Int32 i=0; i<nCount; ++i ) + { + Reference< XCloneable > xCloneable( xSourceHierarchy->getByIndex( i ), UNO_QUERY_THROW ); + Reference< XInterface > xClone( xCloneable->createClone() ); + insertByIndex( i, makeAny( xClone ) ); + } + } + catch (const RuntimeException&) + { + throw; + } + catch (const Exception&) + { + throw WrappedTargetRuntimeException( + "Could not clone the given interface hierarchy.", + static_cast< XIndexContainer* >( const_cast< OInterfaceContainer* >( &_cloneSource ) ), + ::cppu::getCaughtException() + ); + } +} + +void OInterfaceContainer::impl_createEventAttacher_nothrow() +{ + try + { + m_xEventAttacher.set( ::comphelper::createEventAttacherManager( m_xContext ), UNO_SET_THROW ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("forms.misc"); + } +} + + +OInterfaceContainer::~OInterfaceContainer() +{ +} + + +void OInterfaceContainer::disposing() +{ + // dispose all elements + for (sal_Int32 i = m_aItems.size(); i > 0; --i) + { + Reference<XPropertySet> xSet(m_aItems[i - 1], UNO_QUERY); + if (xSet.is()) + xSet->removePropertyChangeListener(PROPERTY_NAME, this); + + // revoke event knittings + if ( m_xEventAttacher.is() ) + { + m_xEventAttacher->detach( i - 1, Reference<XInterface>(xSet, UNO_QUERY) ); + m_xEventAttacher->removeEntry( i - 1 ); + } + + Reference<XComponent> xComponent(xSet, UNO_QUERY); + if (xComponent.is()) + xComponent->dispose(); + } + m_aMap.clear(); + m_aItems.clear(); + + css::lang::EventObject aEvt(static_cast<XContainer*>(this)); + m_aContainerListeners.disposeAndClear(aEvt); +} + +// XPersistObject + +namespace +{ + + void lcl_saveEvents( ::std::vector< Sequence< ScriptEventDescriptor > >& _rSave, + const Reference< XEventAttacherManager >& _rxManager, const sal_Int32 _nItemCount ) + { + OSL_ENSURE( _rxManager.is(), "lcl_saveEvents: invalid event attacher manager!" ); + if ( !_rxManager.is() ) + return; + + // reserve the space needed + _rSave.reserve( _nItemCount ); + + // copy the events + for (sal_Int32 i=0; i<_nItemCount; ++i) + _rSave.push_back(_rxManager->getScriptEvents( i )); + } + + + void lcl_restoreEvents( const ::std::vector< Sequence< ScriptEventDescriptor > >& _rSave, + const Reference< XEventAttacherManager >& _rxManager ) + { + OSL_ENSURE( _rxManager.is(), "lcl_restoreEvents: invalid event attacher manager!" ); + if ( !_rxManager.is() ) + return; + + sal_Int32 i=0; + for (auto const& elem : _rSave) + { + _rxManager->revokeScriptEvents( i ); + _rxManager->registerScriptEvents(i, elem); + ++i; + } + } +} + + +void SAL_CALL OInterfaceContainer::writeEvents(const Reference<XObjectOutputStream>& _rxOutStream) +{ + // We're writing a document in SO 5.2 format (or even from earlier versions) + // -> convert the events from the new runtime format to the format of the 5.2 files + // but before, remember the current script events set for our children + ::std::vector< Sequence< ScriptEventDescriptor > > aSave; + if ( m_xEventAttacher.is() ) + lcl_saveEvents( aSave, m_xEventAttacher, m_aItems.size() ); + + transformEvents(); + + try + { + Reference<XMarkableStream> xMark(_rxOutStream, UNO_QUERY); + sal_Int32 nMark = xMark->createMark(); + + sal_Int32 nObjLen = 0; + _rxOutStream->writeLong(nObjLen); + + Reference<XPersistObject> xScripts(m_xEventAttacher, UNO_QUERY); + if (xScripts.is()) + xScripts->write(_rxOutStream); + + // Determine length + nObjLen = xMark->offsetToMark(nMark) - 4; + xMark->jumpToMark(nMark); + _rxOutStream->writeLong(nObjLen); + xMark->jumpToFurthest(); + xMark->deleteMark(nMark); + } + catch( const Exception& ) + { + // restore the events + if ( m_xEventAttacher.is() ) + lcl_restoreEvents( aSave, m_xEventAttacher ); + throw; + } + + // restore the events + if ( m_xEventAttacher.is() ) + lcl_restoreEvents( aSave, m_xEventAttacher ); +} + +namespace { + +struct TransformEventTo52Format +{ + void operator()( ScriptEventDescriptor& _rDescriptor ) + { + if ( _rDescriptor.ScriptType != "StarBasic" ) + return; + + // it's a starbasic macro + sal_Int32 nPrefixLength = _rDescriptor.ScriptCode.indexOf( ':' ); + if ( 0 <= nPrefixLength ) + { // the macro name does not already contain a : +#ifdef DBG_UTIL + const OUString sPrefix = _rDescriptor.ScriptCode.copy( 0, nPrefixLength ); + DBG_ASSERT( sPrefix == "document" + || sPrefix == "application", + "TransformEventTo52Format: invalid (unknown) prefix!" ); +#endif + // cut the prefix + _rDescriptor.ScriptCode = _rDescriptor.ScriptCode.copy( nPrefixLength + 1 ); + } + } +}; + +} + +void OInterfaceContainer::transformEvents() +{ + OSL_ENSURE( m_xEventAttacher.is(), "OInterfaceContainer::transformEvents: no event attacher manager!" ); + if ( !m_xEventAttacher.is() ) + return; + + try + { + // loop through all our children + sal_Int32 nItems = m_aItems.size(); + Sequence< ScriptEventDescriptor > aChildEvents; + + for (sal_Int32 i=0; i<nItems; ++i) + { + // get the script events for this object + aChildEvents = m_xEventAttacher->getScriptEvents( i ); + + if ( aChildEvents.hasElements() ) + { + // do the transformation + ::std::for_each( aChildEvents.begin(), aChildEvents.end(), TransformEventTo52Format() ); + + // revoke the script events + m_xEventAttacher->revokeScriptEvents( i ); + // and re-register them + m_xEventAttacher->registerScriptEvents( i, aChildEvents ); + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("forms.misc"); + } +} + + +void SAL_CALL OInterfaceContainer::readEvents(const Reference<XObjectInputStream>& _rxInStream) +{ + ::osl::MutexGuard aGuard( m_rMutex ); + + // Read scripting info + Reference<XMarkableStream> xMark(_rxInStream, UNO_QUERY); + sal_Int32 nObjLen = _rxInStream->readLong(); + if (nObjLen) + { + sal_Int32 nMark = xMark->createMark(); + Reference<XPersistObject> xObj(m_xEventAttacher, UNO_QUERY); + if (xObj.is()) + xObj->read(_rxInStream); + xMark->jumpToMark(nMark); + _rxInStream->skipBytes(nObjLen); + xMark->deleteMark(nMark); + } + + // Read Attachment + if ( m_xEventAttacher.is() ) + { + sal_Int32 i=0; + for (auto const& item : m_aItems) + { + Reference< XInterface > xAsIFace( item, UNO_QUERY ); // important to normalize this... + Reference< XPropertySet > xAsSet( xAsIFace, UNO_QUERY ); + m_xEventAttacher->attach( i++, xAsIFace, makeAny( xAsSet ) ); + } + } +} + + +void SAL_CALL OInterfaceContainer::write( const Reference< XObjectOutputStream >& _rxOutStream ) +{ + ::osl::MutexGuard aGuard( m_rMutex ); + sal_Int32 nLen = m_aItems.size(); + + // Write length + _rxOutStream->writeLong(nLen); + + if (!nLen) + return; + + // 1. Version + _rxOutStream->writeShort(0x0001); + + // 2. Objects + for (sal_Int32 i = 0; i < nLen; i++) + { + Reference<XPersistObject> xObj(m_aItems[i], UNO_QUERY); + if (xObj.is()) + _rxOutStream->writeObject(xObj); + else + { + // Error + } + } + + // 3. Scripts + writeEvents(_rxOutStream); +} + + +namespace +{ + Reference< XPersistObject > lcl_createPlaceHolder( const Reference< XComponentContext >& _rxORB ) + { + Reference< XPersistObject > xObject( _rxORB->getServiceManager()->createInstanceWithContext(FRM_COMPONENT_HIDDENCONTROL, _rxORB), UNO_QUERY ); + DBG_ASSERT( xObject.is(), "lcl_createPlaceHolder: could not create a substitute for the unknown object!" ); + if ( xObject.is() ) + { + // set some properties describing what we did + Reference< XPropertySet > xObjProps( xObject, UNO_QUERY ); + if ( xObject.is() ) + { + try + { + xObjProps->setPropertyValue( PROPERTY_NAME, makeAny( FRM_RES_STRING( RID_STR_CONTROL_SUBSTITUTED_NAME ) ) ); + xObjProps->setPropertyValue( PROPERTY_TAG, makeAny( FRM_RES_STRING( RID_STR_CONTROL_SUBSTITUTED_EPXPLAIN ) ) ); + } + catch(const Exception&) + { + } + } + } + return xObject; + } +} + + +void SAL_CALL OInterfaceContainer::read( const Reference< XObjectInputStream >& _rxInStream ) +{ + ::osl::MutexGuard aGuard( m_rMutex ); + + // after ::read the object is expected to be in the state it was when ::write was called, so we have + // to empty ourself here + while (getCount()) + removeByIndex(0); + + // Only writes depending on the length + sal_Int32 nLen = _rxInStream->readLong(); + + if (nLen) + { + // 1. Version + _rxInStream->readShort(); + + // 2. Objects + for (sal_Int32 i = 0; i < nLen; i++) + { + Reference<XPersistObject> xObj; + try + { + xObj = _rxInStream->readObject(); + } + catch(const WrongFormatException&) + { + // the object could not be read + // create an object (so the readEvents below will assign the events to the right controls) + xObj = lcl_createPlaceHolder( m_xContext ); + if ( !xObj.is() ) + // couldn't handle it + throw; + } + catch(const Exception&) + { + // Clear the map + while (!m_aItems.empty()) + removeElementsNoEvents(); + + // Rethrow the exception + throw; + } + + if ( xObj.is() ) + { + Reference< XPropertySet > xElement( xObj, UNO_QUERY ); + try + { + implInsert( + m_aItems.size(), // position + xElement, // element to insert + false, // no event attacher manager handling + nullptr, // not yet approved - let implInsert do it + true // fire the event + ); + } + catch( const Exception& ) + { + SAL_WARN("forms.misc", "OInterfaceContainerHelper2::read: reading succeeded, but not inserting!" ); + // create a placeholder + xElement.set(lcl_createPlaceHolder( m_xContext ), css::uno::UNO_QUERY); + if ( !xElement.is() ) + // couldn't handle it + throw; + // insert the placeholder + implInsert( m_aItems.size(), xElement, false, nullptr, true ); + } + } + } + + readEvents(_rxInStream); + } + else + { + try + { + m_xEventAttacher = ::comphelper::createEventAttacherManager( m_xContext ); + OSL_ENSURE( m_xEventAttacher.is(), "OInterfaceContainer::read: could not create an event attacher manager!" ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("forms.misc"); + } + } +} + +// XContainer + +void SAL_CALL OInterfaceContainer::addContainerListener(const Reference<XContainerListener>& _rxListener) +{ + m_aContainerListeners.addInterface(_rxListener); +} + + +void SAL_CALL OInterfaceContainer::removeContainerListener(const Reference<XContainerListener>& _rxListener) +{ + m_aContainerListeners.removeInterface(_rxListener); +} + +// XEventListener + +void SAL_CALL OInterfaceContainer::disposing(const css::lang::EventObject& _rSource) +{ + ::osl::MutexGuard aGuard( m_rMutex ); + + Reference< XInterface > xSource( _rSource.Source, UNO_QUERY ); + // normalized source + + OInterfaceArray::iterator j; + for ( j = m_aItems.begin(); j != m_aItems.end(); ++j ) + { + DBG_ASSERT( j->get() == Reference< XInterface >( *j, UNO_QUERY ).get(), + "OInterfaceContainer::disposing: vector element not normalized!" ); + + if ( xSource.get() == j->get() ) + // found the element + break; + } + + if ( m_aItems.end() == j ) + return; + + m_aItems.erase(j); + + // look up in, and erase from, m_aMap, too + OInterfaceMap::iterator i = m_aMap.begin(); + while ( i != m_aMap.end() ) + { + DBG_ASSERT( i->second.get() == Reference< XInterface >( i->second, UNO_QUERY ).get(), + "OInterfaceContainer::disposing: map element not normalized!" ); + + if ( i->second.get() == xSource.get() ) + { + // found it + m_aMap.erase(i); + break; + } + + ++i; + + DBG_ASSERT( i != m_aMap.end(), "OInterfaceContainer::disposing: inconsistency: the element was in m_aItems, but not in m_aMap!" ); + } +} + +// XPropertyChangeListener + +void OInterfaceContainer::propertyChange(const PropertyChangeEvent& evt) { + if (evt.PropertyName != PROPERTY_NAME) + return; + + ::osl::MutexGuard aGuard( m_rMutex ); + auto range = m_aMap.equal_range(::comphelper::getString(evt.OldValue)); + for (auto it = range.first; it != range.second; ++it) + if (it->second == evt.Source) + { + css::uno::Reference<css::uno::XInterface> xCorrectType(it->second); + m_aMap.erase(it); + m_aMap.insert(::std::pair<const OUString, css::uno::Reference<css::uno::XInterface> >(::comphelper::getString(evt.NewValue),xCorrectType)); + break; + } +} + +// XElementAccess + +sal_Bool SAL_CALL OInterfaceContainer::hasElements() +{ + return !m_aMap.empty(); +} + + +Type SAL_CALL OInterfaceContainer::getElementType() +{ + return m_aElementType; +} + +// XEnumerationAccess + +Reference<XEnumeration> SAL_CALL OInterfaceContainer::createEnumeration() +{ + ::osl::MutexGuard aGuard( m_rMutex ); + return new ::comphelper::OEnumerationByIndex(static_cast<XIndexAccess*>(this)); +} + +// XNameAccess + +Any SAL_CALL OInterfaceContainer::getByName( const OUString& _rName ) +{ + ::std::pair <OInterfaceMap::iterator, + OInterfaceMap::iterator> aPair = m_aMap.equal_range(_rName); + + if (aPair.first == aPair.second) + throw NoSuchElementException(); + + return (*aPair.first).second->queryInterface( m_aElementType ); +} + + +css::uno::Sequence<OUString> SAL_CALL OInterfaceContainer::getElementNames() +{ + return comphelper::mapKeysToSequence(m_aMap); +} + + +sal_Bool SAL_CALL OInterfaceContainer::hasByName( const OUString& _rName ) +{ + ::std::pair <OInterfaceMap::iterator, + OInterfaceMap::iterator> aPair = m_aMap.equal_range(_rName); + return aPair.first != aPair.second; +} + +// XIndexAccess + +sal_Int32 OInterfaceContainer::getCount() +{ + return m_aItems.size(); +} + + +Any OInterfaceContainer::getByIndex(sal_Int32 _nIndex) +{ + if (_nIndex < 0 || (_nIndex >= static_cast<sal_Int32>(m_aItems.size()))) + throw IndexOutOfBoundsException(); + + return m_aItems[_nIndex]->queryInterface( m_aElementType ); +} + + +void OInterfaceContainer::approveNewElement( const Reference< XPropertySet >& _rxObject, ElementDescription* _pElement ) +{ + // it has to be non-NULL + if ( !_rxObject.is() ) + throw IllegalArgumentException(FRM_RES_STRING(RID_STR_NEED_NON_NULL_OBJECT), static_cast<XContainer*>(this), 1); + + // it has to support our element type interface + Any aCorrectType = _rxObject->queryInterface( m_aElementType ); + if ( !aCorrectType.hasValue() ) + lcl_throwIllegalArgumentException(); + + // it has to have a "Name" property + if ( !hasProperty( PROPERTY_NAME, _rxObject ) ) + lcl_throwIllegalArgumentException(); + + // it has to be a child, and it must not have a parent already + Reference< XChild > xChild( _rxObject, UNO_QUERY ); + if ( !xChild.is() || xChild->getParent().is() ) + { + lcl_throwIllegalArgumentException(); + } + + // passed all tests. cache the information we have so far + DBG_ASSERT( _pElement, "OInterfaceContainer::approveNewElement: invalid event descriptor!" ); + if ( _pElement ) + { + _pElement->xPropertySet = _rxObject; + _pElement->xChild = xChild; + _pElement->aElementTypeInterface = aCorrectType; + _pElement->xInterface = Reference< XInterface >( _rxObject, UNO_QUERY ); // normalized XInterface + } +} + + +void OInterfaceContainer::implInsert(sal_Int32 _nIndex, const Reference< XPropertySet >& _rxElement, + bool _bEvents, ElementDescription* _pApprovalResult, bool _bFire ) +{ + const bool bHandleEvents = _bEvents && m_xEventAttacher.is(); + + // SYNCHRONIZED -----> + ::osl::ClearableMutexGuard aGuard( m_rMutex ); + + std::unique_ptr< ElementDescription > aAutoDeleteMetaData; + ElementDescription* pElementMetaData = _pApprovalResult; + if ( !pElementMetaData ) + { // not yet approved by the caller -> do ourself + pElementMetaData = createElementMetaData(); + DBG_ASSERT( pElementMetaData, "OInterfaceContainer::implInsert: createElementMetaData returned nonsense!" ); + + // ensure that the meta data structure will be deleted later on + aAutoDeleteMetaData.reset( pElementMetaData ); + + // will throw an exception if necessary + approveNewElement( _rxElement, pElementMetaData ); + } + + + // approveNewElement (no matter if called here or outside) has ensure that all relevant interfaces + // exist + + // set the name, and add as change listener for the name + OUString sName; + _rxElement->getPropertyValue(PROPERTY_NAME) >>= sName; + _rxElement->addPropertyChangeListener(PROPERTY_NAME, this); + + // insert the object into our internal structures + if (_nIndex > static_cast<sal_Int32>(m_aItems.size())) // Calculate the actual index + { + _nIndex = m_aItems.size(); + m_aItems.push_back( pElementMetaData->xInterface ); + } + else + m_aItems.insert( m_aItems.begin() + _nIndex, pElementMetaData->xInterface ); + + m_aMap.insert( ::std::pair< const OUString, css::uno::Reference<css::uno::XInterface> >( sName, pElementMetaData->xInterface ) ); + + // announce ourself as parent to the new element + pElementMetaData->xChild->setParent(static_cast<XContainer*>(this)); + + // handle the events + if ( bHandleEvents ) + { + m_xEventAttacher->insertEntry(_nIndex); + m_xEventAttacher->attach( _nIndex, pElementMetaData->xInterface, makeAny( _rxElement ) ); + } + + // notify derived classes + implInserted( pElementMetaData ); + + aGuard.clear(); + // <----- SYNCHRONIZED + + // insert faked VBA events? + bool bHandleVbaEvents = false; + try + { + _rxElement->getPropertyValue("GenerateVbaEvents") >>= bHandleVbaEvents; + } + catch( const Exception& ) + { + } + if ( bHandleVbaEvents ) + { + Reference< XEventAttacherManager > xMgr ( pElementMetaData->xInterface, UNO_QUERY ); + OInterfaceContainer* pIfcMgr = xMgr.is() ? dynamic_cast<OInterfaceContainer*>(xMgr.get()) : nullptr; + if (pIfcMgr) + { + sal_Int32 nLen = pIfcMgr->getCount(); + for (sal_Int32 i = 0; i < nLen; ++i) + { + // add fake events to the control at index i + pIfcMgr->impl_addVbEvents_nolck_nothrow( i ); + } + } + else + { + // add fake events to the control at index i + impl_addVbEvents_nolck_nothrow( _nIndex ); + } + } + + // fire the notification about the change + if ( _bFire ) + { + // notify listeners + ContainerEvent aEvt; + aEvt.Source = static_cast<XContainer*>(this); + aEvt.Accessor <<= _nIndex; + aEvt.Element = pElementMetaData->aElementTypeInterface; + + m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvt ); + } +} + + +void OInterfaceContainer::removeElementsNoEvents() +{ + OInterfaceArray::iterator i = m_aItems.begin(); + css::uno::Reference<css::uno::XInterface> xElement(*i); + + OInterfaceMap::iterator j = std::find_if(m_aMap.begin(), m_aMap.end(), + [&xElement](const OInterfaceMap::value_type& rEntry) { return rEntry.second == xElement; }); + + m_aItems.erase(i); + m_aMap.erase(j); + + Reference<XPropertySet> xSet(xElement, UNO_QUERY); + if (xSet.is()) + xSet->removePropertyChangeListener(PROPERTY_NAME, this); + + Reference<XChild> xChild(xElement, UNO_QUERY); + if (xChild.is()) + xChild->setParent(css::uno::Reference<css::uno::XInterface> ()); +} + + +void OInterfaceContainer::implInserted( const ElementDescription* /*_pElement*/ ) +{ + // not interested in +} + + +void OInterfaceContainer::implRemoved( const css::uno::Reference<css::uno::XInterface>& /*_rxObject*/ ) +{ + // not interested in +} + + +void OInterfaceContainer::impl_replacedElement( const ContainerEvent& _rEvent, ::osl::ClearableMutexGuard& _rInstanceLock ) +{ + _rInstanceLock.clear(); + m_aContainerListeners.notifyEach( &XContainerListener::elementReplaced, _rEvent ); +} + +// XIndexContainer + +void SAL_CALL OInterfaceContainer::insertByIndex( sal_Int32 _nIndex, const Any& _rElement ) +{ + Reference< XPropertySet > xElement; + _rElement >>= xElement; + implInsert( _nIndex, xElement, true /* event handling */ , nullptr /* not yet approved */ , true /* notification */ ); +} + + +void OInterfaceContainer::implReplaceByIndex( const sal_Int32 _nIndex, const Any& _rNewElement, ::osl::ClearableMutexGuard& _rClearBeforeNotify ) +{ + OSL_PRECOND( ( _nIndex >= 0 ) && ( _nIndex < static_cast<sal_Int32>(m_aItems.size()) ), "OInterfaceContainer::implReplaceByIndex: precondition not met (index)!" ); + + // approve the new object + std::unique_ptr< ElementDescription > aElementMetaData( createElementMetaData() ); + DBG_ASSERT(aElementMetaData, + "OInterfaceContainer::implReplaceByIndex: createElementMetaData returned nonsense!"); + { + Reference< XPropertySet > xElementProps; + _rNewElement >>= xElementProps; + approveNewElement( xElementProps, aElementMetaData.get() ); + } + + // get the old element + css::uno::Reference<css::uno::XInterface> xOldElement( m_aItems[ _nIndex ] ); + DBG_ASSERT( xOldElement.get() == Reference< XInterface >( xOldElement, UNO_QUERY ).get(), + "OInterfaceContainer::implReplaceByIndex: elements should be held normalized!" ); + + // locate the old element in the map + OInterfaceMap::iterator j = std::find_if(m_aMap.begin(), m_aMap.end(), + [&xOldElement](const OInterfaceMap::value_type& rEntry) { return rEntry.second.get() == xOldElement.get(); }); + + // remove event knittings + if ( m_xEventAttacher.is() ) + { + css::uno::Reference<css::uno::XInterface> xNormalized( xOldElement, UNO_QUERY ); + m_xEventAttacher->detach( _nIndex, xNormalized ); + m_xEventAttacher->removeEntry( _nIndex ); + } + + // don't listen for property changes anymore + Reference<XPropertySet> xSet( xOldElement, UNO_QUERY ); + if (xSet.is()) + xSet->removePropertyChangeListener(PROPERTY_NAME, this); + + // give the old element a new (void) parent + Reference<XChild> xChild(xOldElement, UNO_QUERY); + if (xChild.is()) + xChild->setParent(css::uno::Reference<css::uno::XInterface> ()); + + // remove the old one + m_aMap.erase(j); + + // examine the new element + OUString sName; + DBG_ASSERT(aElementMetaData->xPropertySet.is(), + "OInterfaceContainer::implReplaceByIndex: what did approveNewElement do?"); + + aElementMetaData->xPropertySet->getPropertyValue(PROPERTY_NAME) >>= sName; + aElementMetaData->xPropertySet->addPropertyChangeListener(PROPERTY_NAME, this); + + // insert the new one + m_aMap.insert(::std::pair<const OUString, css::uno::Reference<css::uno::XInterface>>( + sName, aElementMetaData->xInterface)); + m_aItems[_nIndex] = aElementMetaData->xInterface; + + aElementMetaData->xChild->setParent(static_cast<XContainer*>(this)); + + if ( m_xEventAttacher.is() ) + { + m_xEventAttacher->insertEntry( _nIndex ); + m_xEventAttacher->attach(_nIndex, aElementMetaData->xInterface, + makeAny(aElementMetaData->xPropertySet)); + } + + ContainerEvent aReplaceEvent; + aReplaceEvent.Source = static_cast< XContainer* >( this ); + aReplaceEvent.Accessor <<= _nIndex; + aReplaceEvent.Element = aElementMetaData->xInterface->queryInterface(m_aElementType); + aReplaceEvent.ReplacedElement = xOldElement->queryInterface( m_aElementType ); + + impl_replacedElement( aReplaceEvent, _rClearBeforeNotify ); +} + + +void OInterfaceContainer::implCheckIndex( const sal_Int32 _nIndex ) +{ + if (_nIndex < 0 || _nIndex >= static_cast<sal_Int32>(m_aItems.size())) + throw IndexOutOfBoundsException(); +} + + +void SAL_CALL OInterfaceContainer::replaceByIndex(sal_Int32 _nIndex, const Any& Element) +{ + ::osl::ClearableMutexGuard aGuard( m_rMutex ); + // check the index + implCheckIndex( _nIndex ); + // do the replace + implReplaceByIndex( _nIndex, Element, aGuard ); +} + + +void OInterfaceContainer::implRemoveByIndex( const sal_Int32 _nIndex, ::osl::ClearableMutexGuard& _rClearBeforeNotify ) +{ + OSL_PRECOND( ( _nIndex >= 0 ) && ( _nIndex < static_cast<sal_Int32>(m_aItems.size()) ), "OInterfaceContainer::implRemoveByIndex: precondition not met (index)!" ); + + OInterfaceArray::iterator i = m_aItems.begin() + _nIndex; + css::uno::Reference<css::uno::XInterface> xElement(*i); + + OInterfaceMap::iterator j = std::find_if(m_aMap.begin(), m_aMap.end(), + [&xElement](const OInterfaceMap::value_type& rEntry) { return rEntry.second == xElement; }); + + m_aItems.erase(i); + m_aMap.erase(j); + + // remove event knittings + if ( m_xEventAttacher.is() ) + { + css::uno::Reference<css::uno::XInterface> xNormalized( xElement, UNO_QUERY ); + m_xEventAttacher->detach( _nIndex, xNormalized ); + m_xEventAttacher->removeEntry( _nIndex ); + } + + Reference<XPropertySet> xSet(xElement, UNO_QUERY); + if (xSet.is()) + xSet->removePropertyChangeListener(PROPERTY_NAME, this); + + Reference<XChild> xChild(xElement, UNO_QUERY); + if (xChild.is()) + xChild->setParent(css::uno::Reference<css::uno::XInterface> ()); + + // notify derived classes + implRemoved(xElement); + + // notify listeners + ContainerEvent aEvt; + aEvt.Source = static_cast<XContainer*>(this); + aEvt.Element = xElement->queryInterface( m_aElementType ); + aEvt.Accessor <<= _nIndex; + + _rClearBeforeNotify.clear(); + m_aContainerListeners.notifyEach( &XContainerListener::elementRemoved, aEvt ); +} + + +void SAL_CALL OInterfaceContainer::removeByIndex(sal_Int32 _nIndex) +{ + ::osl::ClearableMutexGuard aGuard( m_rMutex ); + // check the index + implCheckIndex( _nIndex ); + // do the removal + implRemoveByIndex( _nIndex, aGuard ); +} + + +ElementDescription* OInterfaceContainer::createElementMetaData( ) +{ + return new ElementDescription; +} + + +void SAL_CALL OInterfaceContainer::insertByName(const OUString& _rName, const Any& _rElement) +{ + Reference< XPropertySet > xElementProps; + + std::unique_ptr< ElementDescription > aElementMetaData( createElementMetaData() ); + DBG_ASSERT(aElementMetaData, + "OInterfaceContainer::insertByName: createElementMetaData returned nonsense!"); + + // ensure the correct name of the element + try + { + _rElement >>= xElementProps; + approveNewElement( xElementProps, aElementMetaData.get() ); + + xElementProps->setPropertyValue( PROPERTY_NAME, makeAny( _rName ) ); + } + catch( const IllegalArgumentException& ) + { + throw; // allowed to leave + } + catch( const ElementExistException& ) + { + throw; // allowed to leave + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("forms.misc", "OInterfaceContainer::insertByName" ); + } + implInsert( m_aItems.size(), xElementProps, true, aElementMetaData.get(), true ); +} + + +void SAL_CALL OInterfaceContainer::replaceByName(const OUString& Name, const Any& Element) +{ + ::osl::ClearableMutexGuard aGuard( m_rMutex ); + ::std::pair <OInterfaceMap::iterator, + OInterfaceMap::iterator> aPair = m_aMap.equal_range(Name); + if (aPair.first == aPair.second) + throw NoSuchElementException(); + + if (Element.getValueType().getTypeClass() != TypeClass_INTERFACE) + lcl_throwIllegalArgumentException(); + + Reference<XPropertySet> xSet; + Element >>= xSet; + if (xSet.is()) + { + if (!hasProperty(PROPERTY_NAME, xSet)) + lcl_throwIllegalArgumentException(); + + xSet->setPropertyValue(PROPERTY_NAME, makeAny(Name)); + } + + // determine the element pos + sal_Int32 nPos = ::std::find(m_aItems.begin(), m_aItems.end(), (*aPair.first).second) - m_aItems.begin(); + + implReplaceByIndex( nPos, Element, aGuard ); +} + + +void SAL_CALL OInterfaceContainer::removeByName(const OUString& Name) +{ + ::osl::MutexGuard aGuard( m_rMutex ); + ::std::pair <OInterfaceMap::iterator, + OInterfaceMap::iterator> aPair = m_aMap.equal_range(Name); + if (aPair.first == aPair.second) + throw NoSuchElementException(); + + sal_Int32 nPos = ::std::find(m_aItems.begin(), m_aItems.end(), (*aPair.first).second) - m_aItems.begin(); + removeByIndex(nPos); +} + + +// XEventAttacherManager + +void SAL_CALL OInterfaceContainer::registerScriptEvent( sal_Int32 nIndex, const ScriptEventDescriptor& aScriptEvent ) +{ + ::osl::ClearableMutexGuard aGuard( m_rMutex ); + if ( m_xEventAttacher.is() ) + { + m_xEventAttacher->registerScriptEvent( nIndex, aScriptEvent ); + aGuard.clear(); + impl_addVbEvents_nolck_nothrow( nIndex ); // add fake vba events + } +} + + +void SAL_CALL OInterfaceContainer::registerScriptEvents( sal_Int32 nIndex, const Sequence< ScriptEventDescriptor >& aScriptEvents ) +{ + ::osl::ClearableMutexGuard aGuard( m_rMutex ); + if ( m_xEventAttacher.is() ) + { + m_xEventAttacher->registerScriptEvents( nIndex, aScriptEvents ); + aGuard.clear(); + impl_addVbEvents_nolck_nothrow( nIndex ); // add fake vba events + } +} + + +void SAL_CALL OInterfaceContainer::revokeScriptEvent( sal_Int32 nIndex, const OUString& aListenerType, const OUString& aEventMethod, const OUString& aRemoveListenerParam ) +{ + if ( m_xEventAttacher.is() ) + m_xEventAttacher->revokeScriptEvent( nIndex, aListenerType, aEventMethod, aRemoveListenerParam ); +} + + +void SAL_CALL OInterfaceContainer::revokeScriptEvents( sal_Int32 nIndex ) +{ + if ( m_xEventAttacher.is() ) + m_xEventAttacher->revokeScriptEvents( nIndex ); +} + + +void SAL_CALL OInterfaceContainer::insertEntry( sal_Int32 nIndex ) +{ + if ( m_xEventAttacher.is() ) + m_xEventAttacher->insertEntry( nIndex ); +} + + +void SAL_CALL OInterfaceContainer::removeEntry( sal_Int32 nIndex ) +{ + if ( m_xEventAttacher.is() ) + m_xEventAttacher->removeEntry( nIndex ); +} + + +Sequence< ScriptEventDescriptor > SAL_CALL OInterfaceContainer::getScriptEvents( sal_Int32 nIndex ) +{ + Sequence< ScriptEventDescriptor > aReturn; + if ( m_xEventAttacher.is() ) + { + aReturn = m_xEventAttacher->getScriptEvents( nIndex ); + if ( lcl_hasVbaEvents( aReturn ) ) + { + aReturn = lcl_stripVbaEvents( aReturn ); + } + } + return aReturn; +} + + +void SAL_CALL OInterfaceContainer::attach( sal_Int32 nIndex, const Reference< XInterface >& xObject, const Any& aHelper ) +{ + if ( m_xEventAttacher.is() ) + m_xEventAttacher->attach( nIndex, xObject, aHelper ); +} + + +void SAL_CALL OInterfaceContainer::detach( sal_Int32 nIndex, const Reference< XInterface >& xObject ) +{ + if ( m_xEventAttacher.is() ) + m_xEventAttacher->detach( nIndex, xObject ); +} + + +void SAL_CALL OInterfaceContainer::addScriptListener( const Reference< XScriptListener >& xListener ) +{ + if ( m_xEventAttacher.is() ) + m_xEventAttacher->addScriptListener( xListener ); +} + + +void SAL_CALL OInterfaceContainer::removeScriptListener( const Reference< XScriptListener >& xListener ) +{ + if ( m_xEventAttacher.is() ) + m_xEventAttacher->removeScriptListener( xListener ); +} + + +//= OFormComponents + + +Any SAL_CALL OFormComponents::queryAggregation(const Type& _rType) +{ + Any aReturn = OFormComponents_BASE::queryInterface(_rType); + if (!aReturn.hasValue()) + { + aReturn = OInterfaceContainer::queryInterface(_rType); + + if (!aReturn.hasValue()) + aReturn = ::cppu::OComponentHelper::queryAggregation(_rType); + } + + return aReturn; +} + + +Sequence<Type> SAL_CALL OFormComponents::getTypes() +{ + return ::comphelper::concatSequences(OInterfaceContainer::getTypes(), ::cppu::OComponentHelper::getTypes(), OFormComponents_BASE::getTypes()); +} + + +OFormComponents::OFormComponents(const Reference<XComponentContext>& _rxFactory) + : ::cppu::OComponentHelper( m_aMutex ) + ,OInterfaceContainer( _rxFactory, m_aMutex, cppu::UnoType<XFormComponent>::get() ) + ,OFormComponents_BASE() +{ +} + + +OFormComponents::OFormComponents( const OFormComponents& _cloneSource ) + : ::cppu::OComponentHelper( m_aMutex ) + ,OInterfaceContainer( m_aMutex, _cloneSource ) + ,OFormComponents_BASE() +{ +} + + +OFormComponents::~OFormComponents() +{ + if (! ::cppu::OComponentHelper::rBHelper.bDisposed) + { + acquire(); + dispose(); + } +} + +// OComponentHelper + +void OFormComponents::disposing() +{ + OInterfaceContainer::disposing(); + ::cppu::OComponentHelper::disposing(); + m_xParent = nullptr; +} + +//XChild + +void OFormComponents::setParent(const css::uno::Reference<css::uno::XInterface>& Parent) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + m_xParent = Parent; +} + + +css::uno::Reference<css::uno::XInterface> OFormComponents::getParent() +{ + return m_xParent; +} + + +} // namespace frm + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/forms/source/misc/componenttools.cxx b/forms/source/misc/componenttools.cxx new file mode 100644 index 000000000..41a062188 --- /dev/null +++ b/forms/source/misc/componenttools.cxx @@ -0,0 +1,105 @@ +/* -*- 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 <componenttools.hxx> + +#include <com/sun/star/container/XChild.hpp> +#include <comphelper/sequence.hxx> + +#include <algorithm> +#include <iterator> + + +namespace frm +{ + + + using ::com::sun::star::frame::XModel; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::container::XChild; + + TypeBag::TypeBag( const TypeSequence& _rTypes1 ) + { + addTypes( _rTypes1 ); + } + + + TypeBag::TypeBag( const TypeSequence& _rTypes1, const TypeSequence& _rTypes2 ) + { + addTypes( _rTypes1 ); + addTypes( _rTypes2 ); + } + + + TypeBag::TypeBag( const TypeSequence& _rTypes1, const TypeSequence& _rTypes2, const TypeSequence& _rTypes3 ) + { + addTypes( _rTypes1 ); + addTypes( _rTypes2 ); + addTypes( _rTypes3 ); + } + + + void TypeBag::addTypes( const TypeSequence& _rTypes ) + { + ::std::copy( + _rTypes.begin(), + _rTypes.end(), + ::std::insert_iterator< TypeSet >( m_aTypes, m_aTypes.begin() ) + ); + } + + + void TypeBag::addType( const css::uno::Type& i_rType ) + { + m_aTypes.insert( i_rType ); + } + + + void TypeBag::removeType( const css::uno::Type& i_rType ) + { + m_aTypes.erase( i_rType ); + } + + + TypeBag::TypeSequence TypeBag::getTypes() const + { + return comphelper::containerToSequence(m_aTypes); + } + + + Reference< XModel > getXModel( const Reference< XInterface >& _rxComponent ) + { + Reference< XInterface > xParent = _rxComponent; + Reference< XModel > xModel( xParent, UNO_QUERY ); + while ( xParent.is() && !xModel.is() ) + { + Reference< XChild > xChild( xParent, UNO_QUERY ); + xParent.set( xChild.is() ? xChild->getParent() : Reference< XInterface >(), UNO_QUERY ); + xModel.set( xParent, UNO_QUERY ); + } + return xModel; + } + + +} // namespace frm + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/forms/source/misc/limitedformats.cxx b/forms/source/misc/limitedformats.cxx new file mode 100644 index 000000000..f49b8617f --- /dev/null +++ b/forms/source/misc/limitedformats.cxx @@ -0,0 +1,381 @@ +/* -*- 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 <limitedformats.hxx> +#include <osl/diagnose.h> +#include <comphelper/types.hxx> +#include <comphelper/extract.hxx> +#include <com/sun/star/form/FormComponentType.hpp> +#include <com/sun/star/util/NumberFormatsSupplier.hpp> + + +namespace frm +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::form; + using namespace ::com::sun::star::beans; + + sal_Int32 OLimitedFormats::s_nInstanceCount(0); + ::osl::Mutex OLimitedFormats::s_aMutex; + Reference< XNumberFormatsSupplier > OLimitedFormats::s_xStandardFormats; + + + //= + + namespace { + + enum LocaleType + { + ltEnglishUS, + ltGerman, + ltSystem + }; + + } + + static const Locale& getLocale(LocaleType _eType) + { + static const Locale s_aEnglishUS( "en", "us", OUString() ); + static const Locale s_aGerman( "de", "DE", OUString() ); + static const Locale s_aSystem( "", "", "" ); + + switch (_eType) + { + case ltEnglishUS: + return s_aEnglishUS; + + case ltGerman: + return s_aGerman; + + case ltSystem: + return s_aSystem; + } + + OSL_FAIL("getLocale: invalid enum value!"); + return s_aSystem; + } + + namespace { + + struct FormatEntry + { + const char* pDescription; + sal_Int32 nKey; + LocaleType eLocale; + }; + + } + + static FormatEntry* lcl_getFormatTable(sal_Int16 nTableId) + { + switch (nTableId) + { + case FormComponentType::TIMEFIELD: + { + static FormatEntry s_aFormats[] = { + { "HH:MM", -1, ltEnglishUS }, + { "HH:MM:SS", -1, ltEnglishUS }, + { "HH:MM AM/PM", -1, ltEnglishUS }, + { "HH:MM:SS AM/PM", -1, ltEnglishUS }, + { nullptr, -1, ltSystem } + }; + return s_aFormats; + } + case FormComponentType::DATEFIELD: + { + static FormatEntry s_aFormats[] = { + { "T-M-JJ", -1, ltGerman }, + { "TT-MM-JJ", -1, ltGerman }, + { "TT-MM-JJJJ", -1, ltGerman }, + { "NNNNT. MMMM JJJJ", -1, ltGerman }, + + { "DD/MM/YY", -1, ltEnglishUS }, + { "MM/DD/YY", -1, ltEnglishUS }, + { "YY/MM/DD", -1, ltEnglishUS }, + { "DD/MM/YYYY", -1, ltEnglishUS }, + { "MM/DD/YYYY", -1, ltEnglishUS }, + { "YYYY/MM/DD", -1, ltEnglishUS }, + + { "JJ-MM-TT", -1, ltGerman }, + { "JJJJ-MM-TT", -1, ltGerman }, + + { nullptr, -1, ltSystem } + }; + return s_aFormats; + } + } + + OSL_FAIL("lcl_getFormatTable: invalid id!"); + return nullptr; + } + + OLimitedFormats::OLimitedFormats(const Reference< XComponentContext >& _rxContext, const sal_Int16 _nClassId) + :m_nFormatEnumPropertyHandle(-1) + ,m_nTableId(_nClassId) + { + OSL_ENSURE(_rxContext.is(), "OLimitedFormats::OLimitedFormats: invalid service factory!"); + acquireSupplier(_rxContext); + ensureTableInitialized(m_nTableId); + } + + + OLimitedFormats::~OLimitedFormats() + { + releaseSupplier(); + } + + + void OLimitedFormats::ensureTableInitialized(const sal_Int16 _nTableId) + { + FormatEntry* pFormatTable = lcl_getFormatTable(_nTableId); + if (-1 != pFormatTable->nKey) + return; + + ::osl::MutexGuard aGuard(s_aMutex); + if (-1 != pFormatTable->nKey) + return; + + // initialize the keys + Reference<XNumberFormats> xStandardFormats; + if (s_xStandardFormats.is()) + xStandardFormats = s_xStandardFormats->getNumberFormats(); + OSL_ENSURE(xStandardFormats.is(), "OLimitedFormats::ensureTableInitialized: don't have a formats supplier!"); + + if (!xStandardFormats.is()) + return; + + // loop through the table + FormatEntry* pLoopFormats = pFormatTable; + while (pLoopFormats->pDescription) + { + // get the key for the description + pLoopFormats->nKey = xStandardFormats->queryKey( + OUString::createFromAscii(pLoopFormats->pDescription), + getLocale(pLoopFormats->eLocale), + false + ); + + if (-1 == pLoopFormats->nKey) + { + pLoopFormats->nKey = xStandardFormats->addNew( + OUString::createFromAscii(pLoopFormats->pDescription), + getLocale(pLoopFormats->eLocale) + ); +#ifdef DBG_UTIL + try + { + xStandardFormats->getByKey(pLoopFormats->nKey); + } + catch(const Exception&) + { + OSL_FAIL("OLimitedFormats::ensureTableInitialized: adding the key to the formats collection failed!"); + } +#endif + } + + // next + ++pLoopFormats; + } + } + + + void OLimitedFormats::clearTable(const sal_Int16 _nTableId) + { + ::osl::MutexGuard aGuard(s_aMutex); + FormatEntry* pFormats = lcl_getFormatTable(_nTableId); + FormatEntry* pResetLoop = pFormats; + while (pResetLoop->pDescription) + { + pResetLoop->nKey = -1; + ++pResetLoop; + } + } + + + void OLimitedFormats::setAggregateSet(const Reference< XFastPropertySet >& _rxAggregate, sal_Int32 _nOriginalPropertyHandle) + { + // changes (NULL -> not NULL) and (not NULL -> NULL) are allowed + OSL_ENSURE(!m_xAggregate.is() || !_rxAggregate.is(), "OLimitedFormats::setAggregateSet: already have an aggregate!"); + OSL_ENSURE(_rxAggregate.is() || m_xAggregate.is(), "OLimitedFormats::setAggregateSet: invalid new aggregate!"); + + m_xAggregate = _rxAggregate; + m_nFormatEnumPropertyHandle = _nOriginalPropertyHandle; +#ifdef DBG_UTIL + if (m_xAggregate.is()) + { + try + { + m_xAggregate->getFastPropertyValue(m_nFormatEnumPropertyHandle); + } + catch(const Exception&) + { + OSL_FAIL("OLimitedFormats::setAggregateSet: invalid handle!"); + } + } +#endif + } + + + void OLimitedFormats::getFormatKeyPropertyValue( Any& _rValue ) const + { + _rValue.clear(); + + OSL_ENSURE(m_xAggregate.is() && (-1 != m_nFormatEnumPropertyHandle), "OLimitedFormats::getFormatKeyPropertyValue: not initialized!"); + if (!m_xAggregate.is()) + return; + + // get the aggregate's enum property value + Any aEnumPropertyValue = m_xAggregate->getFastPropertyValue(m_nFormatEnumPropertyHandle); + sal_Int32 nValue = -1; + ::cppu::enum2int(nValue, aEnumPropertyValue); + + // get the translation table + const FormatEntry* pFormats = lcl_getFormatTable(m_nTableId); + + // seek to the nValue'th entry + sal_Int32 nLookup = 0; + for ( ; + (nullptr != pFormats->pDescription) && (nLookup < nValue); + ++pFormats, ++nLookup + ) + ; + OSL_ENSURE(nullptr != pFormats->pDescription, "OLimitedFormats::getFormatKeyPropertyValue: did not find the value!"); + if (pFormats->pDescription) + _rValue <<= pFormats->nKey; + + // TODO: should use a standard format for the control type we're working for + } + + + bool OLimitedFormats::convertFormatKeyPropertyValue(Any& _rConvertedValue, Any& _rOldValue, const Any& _rNewValue) + { + OSL_ENSURE(m_xAggregate.is() && (-1 != m_nFormatEnumPropertyHandle), "OLimitedFormats::convertFormatKeyPropertyValue: not initialized!"); + + if (m_xAggregate.is()) + { + // the new format key to set + sal_Int32 nNewFormat = 0; + if (!(_rNewValue >>= nNewFormat)) + throw IllegalArgumentException(); + + // get the old (enum) value from the aggregate + Any aEnumPropertyValue = m_xAggregate->getFastPropertyValue(m_nFormatEnumPropertyHandle); + sal_Int32 nOldEnumValue = -1; + ::cppu::enum2int(nOldEnumValue, aEnumPropertyValue); + + // get the translation table + const FormatEntry* pFormats = lcl_getFormatTable(m_nTableId); + + _rOldValue.clear(); + _rConvertedValue.clear(); + + // look for the entry with the given format key + sal_Int32 nTablePosition = 0; + for ( ; + (nullptr != pFormats->pDescription) && (nNewFormat != pFormats->nKey); + ++pFormats, ++nTablePosition + ) + { + if (nTablePosition == nOldEnumValue) + _rOldValue <<= pFormats->nKey; + } + + bool bFoundIt = (nullptr != pFormats->pDescription); + bool bModified = false; + if (bFoundIt) + { + _rConvertedValue <<= static_cast<sal_Int16>(nTablePosition); + bModified = nTablePosition != nOldEnumValue; + } + + if (!_rOldValue.hasValue()) + { // did not reach the end of the table (means we found nNewFormat) + // -> go to the end to ensure that _rOldValue is set + while (pFormats->pDescription) + { + if (nTablePosition == nOldEnumValue) + { + _rOldValue <<= pFormats->nKey; + break; + } + + ++pFormats; + ++nTablePosition; + } + } + + OSL_ENSURE(_rOldValue.hasValue(), "OLimitedFormats::convertFormatKeyPropertyValue: did not find the old enum value in the table!"); + + if (!bFoundIt) + { // somebody gave us a format which we can't translate + throw IllegalArgumentException("This control supports only a very limited number of formats.", nullptr, 2); + } + + return bModified; + } + + return false; + } + + + void OLimitedFormats::setFormatKeyPropertyValue( const Any& _rNewValue ) + { + OSL_ENSURE(m_xAggregate.is() && (-1 != m_nFormatEnumPropertyHandle), "OLimitedFormats::setFormatKeyPropertyValue: not initialized!"); + + if (m_xAggregate.is()) + { // this is to be called after convertFormatKeyPropertyValue, where + // we translated the format key into an enum value. + // So now we can simply forward this enum value to our aggregate + m_xAggregate->setFastPropertyValue(m_nFormatEnumPropertyHandle, _rNewValue); + } + } + + + void OLimitedFormats::acquireSupplier(const Reference< XComponentContext >& _rxContext) + { + ::osl::MutexGuard aGuard(s_aMutex); + if (1 == ++s_nInstanceCount) + { // create the standard formatter + s_xStandardFormats = NumberFormatsSupplier::createWithLocale(_rxContext, getLocale(ltEnglishUS)); + } + } + + + void OLimitedFormats::releaseSupplier() + { + ::osl::MutexGuard aGuard(s_aMutex); + if (0 == --s_nInstanceCount) + { + ::comphelper::disposeComponent(s_xStandardFormats); + s_xStandardFormats = nullptr; + + clearTable(FormComponentType::TIMEFIELD); + clearTable(FormComponentType::DATEFIELD); + } + } + + +} // namespace frm + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/forms/source/misc/listenercontainers.cxx b/forms/source/misc/listenercontainers.cxx new file mode 100644 index 000000000..13adf3e61 --- /dev/null +++ b/forms/source/misc/listenercontainers.cxx @@ -0,0 +1,58 @@ +/* -*- 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 <listenercontainers.hxx> +#include <osl/diagnose.h> + + +namespace frm +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::form; + + + //= ResetListeners + + + bool ResetListeners::implTypedNotify( const Reference< XResetListener >& _rxListener, + const EventObject& _rEvent ) + { + switch ( m_eCurrentNotificationType ) + { + case eApproval: + if ( !_rxListener->approveReset( _rEvent ) ) + return false; + return true; + case eFinal: + _rxListener->resetted( _rEvent ); + break; + default: + OSL_FAIL( "ResetListeners::implNotify: invalid notification type!" ); + } + return true; + } + + +} // namespace frm + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/forms/source/misc/property.cxx b/forms/source/misc/property.cxx new file mode 100644 index 000000000..11c3ad7d2 --- /dev/null +++ b/forms/source/misc/property.cxx @@ -0,0 +1,223 @@ +/* -*- 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 <frm_strings.hxx> +#include <property.hxx> + +namespace frm +{ + +//= PropertyInfoService + +PropertyInfoService::PropertyMap PropertyInfoService::s_AllKnownProperties; + +sal_Int32 PropertyInfoService::getPropertyId(const OUString& _rName) +{ + initialize(); + + sal_Int32 nHandle = -1; + const auto foundProperty = s_AllKnownProperties.find(_rName); + if (foundProperty != s_AllKnownProperties.end()) + nHandle = foundProperty->second; + return nHandle; +} + + +sal_Int32 ConcreteInfoService::getPreferredPropertyId(const OUString& _rName) +{ + return PropertyInfoService::getPropertyId(_rName); +} + + +#define EXPAND_PROP_INIT(varname) \ + { PROPERTY_##varname, PROPERTY_ID_##varname } + +void PropertyInfoService::initialize() +{ + if (!s_AllKnownProperties.empty()) + return; + + s_AllKnownProperties.insert({ + EXPAND_PROP_INIT(NAME), + EXPAND_PROP_INIT(TAG), + EXPAND_PROP_INIT(TABINDEX), + EXPAND_PROP_INIT(CLASSID), + EXPAND_PROP_INIT(ALIGN), + EXPAND_PROP_INIT(FETCHSIZE), + EXPAND_PROP_INIT(VALUE), + EXPAND_PROP_INIT(VALUEMIN), + EXPAND_PROP_INIT(VALUEMAX), + EXPAND_PROP_INIT(VALUESTEP), + EXPAND_PROP_INIT(TEXT), + EXPAND_PROP_INIT(LABEL), + EXPAND_PROP_INIT(NAVIGATION), + EXPAND_PROP_INIT(CYCLE), + EXPAND_PROP_INIT(CONTROLSOURCE), + EXPAND_PROP_INIT(ENABLED), + EXPAND_PROP_INIT(ENABLEVISIBLE), + EXPAND_PROP_INIT(SPIN), + EXPAND_PROP_INIT(READONLY), + EXPAND_PROP_INIT(FILTER), + EXPAND_PROP_INIT(WIDTH), + EXPAND_PROP_INIT(SEARCHABLE), + EXPAND_PROP_INIT(MULTILINE), + EXPAND_PROP_INIT(TARGET_URL), + EXPAND_PROP_INIT(DEFAULTCONTROL), + EXPAND_PROP_INIT(MAXTEXTLEN), + EXPAND_PROP_INIT(SIZE), + EXPAND_PROP_INIT(DATE), + EXPAND_PROP_INIT(TIME), + EXPAND_PROP_INIT(STATE), + EXPAND_PROP_INIT(TRISTATE), + EXPAND_PROP_INIT(HIDDEN_VALUE), + EXPAND_PROP_INIT(TARGET_FRAME), + EXPAND_PROP_INIT(BUTTONTYPE), + EXPAND_PROP_INIT(STRINGITEMLIST), + EXPAND_PROP_INIT(TYPEDITEMLIST), + EXPAND_PROP_INIT(DEFAULT_TEXT), + EXPAND_PROP_INIT(DEFAULT_STATE), + EXPAND_PROP_INIT(DEFAULT_DATE), + EXPAND_PROP_INIT(DEFAULT_TIME), + EXPAND_PROP_INIT(DEFAULT_VALUE), + EXPAND_PROP_INIT(FORMATKEY), + EXPAND_PROP_INIT(FORMATSSUPPLIER), + EXPAND_PROP_INIT(SUBMIT_ACTION), + EXPAND_PROP_INIT(SUBMIT_TARGET), + EXPAND_PROP_INIT(SUBMIT_METHOD), + EXPAND_PROP_INIT(SUBMIT_ENCODING), + EXPAND_PROP_INIT(IMAGE_URL), + EXPAND_PROP_INIT(GRAPHIC), + EXPAND_PROP_INIT(EMPTY_IS_NULL), + EXPAND_PROP_INIT(LISTSOURCETYPE), + EXPAND_PROP_INIT(LISTSOURCE), + EXPAND_PROP_INIT(SELECT_SEQ), + EXPAND_PROP_INIT(VALUE_SEQ), + EXPAND_PROP_INIT(SELECT_VALUE), + EXPAND_PROP_INIT(SELECT_VALUE_SEQ), + EXPAND_PROP_INIT(DEFAULT_SELECT_SEQ), + EXPAND_PROP_INIT(MULTISELECTION), + EXPAND_PROP_INIT(DECIMAL_ACCURACY), + EXPAND_PROP_INIT(EDITMASK), + EXPAND_PROP_INIT(ISREADONLY), + EXPAND_PROP_INIT(FIELDTYPE), + EXPAND_PROP_INIT(DECIMALS), + EXPAND_PROP_INIT(REFVALUE), + EXPAND_PROP_INIT(STRICTFORMAT), + EXPAND_PROP_INIT(DATASOURCE), + EXPAND_PROP_INIT(ALLOWADDITIONS), + EXPAND_PROP_INIT(ALLOWEDITS), + EXPAND_PROP_INIT(ALLOWDELETIONS), + EXPAND_PROP_INIT(MASTERFIELDS), + EXPAND_PROP_INIT(ISPASSTHROUGH), + EXPAND_PROP_INIT(QUERY), + EXPAND_PROP_INIT(LITERALMASK), + EXPAND_PROP_INIT(SHOWTHOUSANDSEP), + EXPAND_PROP_INIT(CURRENCYSYMBOL), + EXPAND_PROP_INIT(DATEFORMAT), + EXPAND_PROP_INIT(DATEMIN), + EXPAND_PROP_INIT(DATEMAX), + EXPAND_PROP_INIT(DATE_SHOW_CENTURY), + EXPAND_PROP_INIT(TIMEFORMAT), + EXPAND_PROP_INIT(TIMEMIN), + EXPAND_PROP_INIT(TIMEMAX), + EXPAND_PROP_INIT(LINECOUNT), + EXPAND_PROP_INIT(BOUNDCOLUMN), + EXPAND_PROP_INIT(HASNAVIGATION), + EXPAND_PROP_INIT(FONT), + EXPAND_PROP_INIT(BACKGROUNDCOLOR), + EXPAND_PROP_INIT(FILLCOLOR), + EXPAND_PROP_INIT(TEXTCOLOR), + EXPAND_PROP_INIT(LINECOLOR), + EXPAND_PROP_INIT(BORDER), + EXPAND_PROP_INIT(DROPDOWN), + EXPAND_PROP_INIT(HSCROLL), + EXPAND_PROP_INIT(VSCROLL), + EXPAND_PROP_INIT(TABSTOP), + EXPAND_PROP_INIT(AUTOCOMPLETE), + EXPAND_PROP_INIT(HARDLINEBREAKS), + EXPAND_PROP_INIT(PRINTABLE), + EXPAND_PROP_INIT(ECHO_CHAR), + EXPAND_PROP_INIT(ROWHEIGHT), + EXPAND_PROP_INIT(HELPTEXT), + EXPAND_PROP_INIT(FONT_NAME), + EXPAND_PROP_INIT(FONT_STYLENAME), + EXPAND_PROP_INIT(FONT_FAMILY), + EXPAND_PROP_INIT(FONT_CHARSET), + EXPAND_PROP_INIT(FONT_HEIGHT), + EXPAND_PROP_INIT(FONT_WEIGHT), + EXPAND_PROP_INIT(FONT_SLANT), + EXPAND_PROP_INIT(FONT_UNDERLINE), + EXPAND_PROP_INIT(FONT_WORDLINEMODE), + EXPAND_PROP_INIT(FONT_STRIKEOUT), + EXPAND_PROP_INIT(TEXTLINECOLOR), + EXPAND_PROP_INIT(FONTEMPHASISMARK), + EXPAND_PROP_INIT(FONTRELIEF), + EXPAND_PROP_INIT(HELPURL), + EXPAND_PROP_INIT(RECORDMARKER), + EXPAND_PROP_INIT(BOUNDFIELD), + EXPAND_PROP_INIT(INPUT_REQUIRED), + EXPAND_PROP_INIT(TREATASNUMERIC), + EXPAND_PROP_INIT(EFFECTIVE_VALUE), + EXPAND_PROP_INIT(EFFECTIVE_DEFAULT), + EXPAND_PROP_INIT(EFFECTIVE_MIN), + EXPAND_PROP_INIT(EFFECTIVE_MAX), + EXPAND_PROP_INIT(HIDDEN), + EXPAND_PROP_INIT(FILTERPROPOSAL), + EXPAND_PROP_INIT(FIELDSOURCE), + EXPAND_PROP_INIT(TABLENAME), + EXPAND_PROP_INIT(CONTROLLABEL), + EXPAND_PROP_INIT(CURRSYM_POSITION), + EXPAND_PROP_INIT(CURSORCOLOR), + EXPAND_PROP_INIT(ALWAYSSHOWCURSOR), + EXPAND_PROP_INIT(DISPLAYSYNCHRON), + EXPAND_PROP_INIT(ISMODIFIED), + EXPAND_PROP_INIT(ISNEW), + EXPAND_PROP_INIT(PRIVILEGES), + EXPAND_PROP_INIT(DETAILFIELDS), + EXPAND_PROP_INIT(COMMAND), + EXPAND_PROP_INIT(COMMANDTYPE), + EXPAND_PROP_INIT(RESULTSET_CONCURRENCY), + EXPAND_PROP_INIT(INSERTONLY), + EXPAND_PROP_INIT(RESULTSET_TYPE), + EXPAND_PROP_INIT(ESCAPE_PROCESSING), + EXPAND_PROP_INIT(APPLYFILTER), + EXPAND_PROP_INIT(ISNULLABLE), + EXPAND_PROP_INIT(ACTIVECOMMAND), + EXPAND_PROP_INIT(ISCURRENCY), + EXPAND_PROP_INIT(URL), + EXPAND_PROP_INIT(TITLE), + EXPAND_PROP_INIT(ACTIVE_CONNECTION), + EXPAND_PROP_INIT(SCALE), + EXPAND_PROP_INIT(SORT), + EXPAND_PROP_INIT(PERSISTENCE_MAXTEXTLENGTH), + EXPAND_PROP_INIT(SCROLL_VALUE), + EXPAND_PROP_INIT(SPIN_VALUE), + EXPAND_PROP_INIT(DEFAULT_SCROLL_VALUE), + EXPAND_PROP_INIT(DEFAULT_SPIN_VALUE), + EXPAND_PROP_INIT( WRITING_MODE ), + EXPAND_PROP_INIT( CONTEXT_WRITING_MODE ), + EXPAND_PROP_INIT( GENERATEVBAEVENTS ) + }); +} + + +} +//... namespace frm ....................................................... + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |