diff options
Diffstat (limited to 'svx/source/form')
59 files changed, 41445 insertions, 0 deletions
diff --git a/svx/source/form/ParseContext.cxx b/svx/source/form/ParseContext.cxx new file mode 100644 index 000000000000..b92f39caa6d1 --- /dev/null +++ b/svx/source/form/ParseContext.cxx @@ -0,0 +1,252 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include <sal/macros.h> +#include "ParseContext.hxx" +#include "stringlistresource.hxx" +#include "fmresids.hrc" + +#include <svx/dialmgr.hxx> + +#include <unotools/syslocale.hxx> +#include <vcl/svapp.hxx> +#include <tools/debug.hxx> +#include <osl/mutex.hxx> + +using namespace svxform; +using namespace ::connectivity; +//========================================================================== +//= OSystemParseContext +//========================================================================== +DBG_NAME(OSystemParseContext) +//----------------------------------------------------------------------------- +OSystemParseContext::OSystemParseContext() : IParseContext() +{ + DBG_CTOR(OSystemParseContext,NULL); + SolarMutexGuard aGuard; + + ::svx::StringListResource aKeywords( SVX_RES( RID_RSC_SQL_INTERNATIONAL ) ); + aKeywords.get( m_aLocalizedKeywords ); +} + +//----------------------------------------------------------------------------- +OSystemParseContext::~OSystemParseContext() +{ + DBG_DTOR(OSystemParseContext,NULL); +} + +//----------------------------------------------------------------------------- +::com::sun::star::lang::Locale OSystemParseContext::getPreferredLocale( ) const +{ + return SvtSysLocale().GetLocaleData().getLocale(); +} + +//----------------------------------------------------------------------------- +::rtl::OUString OSystemParseContext::getErrorMessage(ErrorCode _eCode) const +{ + String aMsg; + SolarMutexGuard aGuard; + switch (_eCode) + { + case ERROR_GENERAL: aMsg = SVX_RES(RID_STR_SVT_SQL_SYNTAX_ERROR); break; + case ERROR_VALUE_NO_LIKE: aMsg = SVX_RES(RID_STR_SVT_SQL_SYNTAX_VALUE_NO_LIKE); break; + case ERROR_FIELD_NO_LIKE: aMsg = SVX_RES(RID_STR_SVT_SQL_SYNTAX_FIELD_NO_LIKE); break; + case ERROR_INVALID_COMPARE: aMsg = SVX_RES(RID_STR_SVT_SQL_SYNTAX_CRIT_NO_COMPARE); break; + case ERROR_INVALID_INT_COMPARE: aMsg = SVX_RES(RID_STR_SVT_SQL_SYNTAX_INT_NO_VALID); break; + case ERROR_INVALID_DATE_COMPARE: aMsg = SVX_RES(RID_STR_SVT_SQL_SYNTAX_ACCESS_DAT_NO_VALID); break; + case ERROR_INVALID_REAL_COMPARE: aMsg = SVX_RES(RID_STR_SVT_SQL_SYNTAX_REAL_NO_VALID); break; + case ERROR_INVALID_TABLE: aMsg = SVX_RES(RID_STR_SVT_SQL_SYNTAX_TABLE); break; + case ERROR_INVALID_TABLE_OR_QUERY: aMsg = SVX_RES(RID_STR_SVT_SQL_SYNTAX_TABLE_OR_QUERY); break; + case ERROR_INVALID_COLUMN: aMsg = SVX_RES(RID_STR_SVT_SQL_SYNTAX_COLUMN); break; + case ERROR_INVALID_TABLE_EXIST: aMsg = SVX_RES(RID_STR_SVT_SQL_SYNTAX_TABLE_EXISTS); break; + case ERROR_INVALID_QUERY_EXIST: aMsg = SVX_RES(RID_STR_SVT_SQL_SYNTAX_QUERY_EXISTS); break; + case ERROR_NONE: break; + } + return aMsg; +} + +//----------------------------------------------------------------------------- +::rtl::OString OSystemParseContext::getIntlKeywordAscii(InternationalKeyCode _eKey) const +{ + size_t nIndex = 0; + switch ( _eKey ) + { + case KEY_LIKE: nIndex = 0; break; + case KEY_NOT: nIndex = 1; break; + case KEY_NULL: nIndex = 2; break; + case KEY_TRUE: nIndex = 3; break; + case KEY_FALSE: nIndex = 4; break; + case KEY_IS: nIndex = 5; break; + case KEY_BETWEEN: nIndex = 6; break; + case KEY_OR: nIndex = 7; break; + case KEY_AND: nIndex = 8; break; + case KEY_AVG: nIndex = 9; break; + case KEY_COUNT: nIndex = 10; break; + case KEY_MAX: nIndex = 11; break; + case KEY_MIN: nIndex = 12; break; + case KEY_SUM: nIndex = 13; break; + case KEY_EVERY: nIndex = 14; break; + case KEY_ANY: nIndex = 15; break; + case KEY_SOME: nIndex = 16; break; + case KEY_STDDEV_POP: nIndex = 17; break; + case KEY_STDDEV_SAMP: nIndex = 18; break; + case KEY_VAR_SAMP: nIndex = 19; break; + case KEY_VAR_POP: nIndex = 20; break; + case KEY_COLLECT: nIndex = 21; break; + case KEY_FUSION: nIndex = 22; break; + case KEY_INTERSECTION: nIndex = 23; break; + case KEY_NONE: + DBG_ERROR( "OSystemParseContext::getIntlKeywordAscii: illegal argument!" ); + break; + } + + OSL_ENSURE( nIndex < m_aLocalizedKeywords.size(), "OSystemParseContext::getIntlKeywordAscii: invalid index!" ); + + ByteString sKeyword; + if ( nIndex < m_aLocalizedKeywords.size() ) + sKeyword = ByteString( m_aLocalizedKeywords[nIndex], RTL_TEXTENCODING_UTF8 ); + return sKeyword; +} + +//----------------------------------------------------------------------------- +static sal_Unicode lcl_getSeparatorChar( const String& _rSeparator, sal_Unicode _nFallback ) +{ + DBG_ASSERT( 0 < _rSeparator.Len(), "::lcl_getSeparatorChar: invalid decimal separator!" ); + + sal_Unicode nReturn( _nFallback ); + if ( _rSeparator.Len() ) + nReturn = static_cast< sal_Char >( _rSeparator.GetBuffer( )[0] ); + return nReturn; +} + +//----------------------------------------------------------------------------- +sal_Unicode OSystemParseContext::getNumDecimalSep( ) const +{ + return lcl_getSeparatorChar( SvtSysLocale().GetLocaleData().getNumDecimalSep(), '.' ); +} + +//----------------------------------------------------------------------------- +sal_Unicode OSystemParseContext::getNumThousandSep( ) const +{ + return lcl_getSeparatorChar( SvtSysLocale().GetLocaleData().getNumThousandSep(), ',' ); +} +// ----------------------------------------------------------------------------- +IParseContext::InternationalKeyCode OSystemParseContext::getIntlKeyCode(const ::rtl::OString& rToken) const +{ + static IParseContext::InternationalKeyCode Intl_TokenID[] = + { + KEY_LIKE, KEY_NOT, KEY_NULL, KEY_TRUE, + KEY_FALSE, KEY_IS, KEY_BETWEEN, KEY_OR, + KEY_AND, KEY_AVG, KEY_COUNT, KEY_MAX, + KEY_MIN, KEY_SUM, KEY_EVERY, + KEY_ANY, KEY_SOME, KEY_STDDEV_POP, + KEY_STDDEV_SAMP, KEY_VAR_SAMP, KEY_VAR_POP, + KEY_COLLECT, KEY_FUSION, KEY_INTERSECTION + }; + + sal_uInt32 nCount = SAL_N_ELEMENTS( Intl_TokenID ); + for (sal_uInt32 i = 0; i < nCount; i++) + { + ::rtl::OString aKey = getIntlKeywordAscii(Intl_TokenID[i]); + if (rToken.equalsIgnoreAsciiCase(aKey)) + return Intl_TokenID[i]; + } + + return KEY_NONE; +} + + +// ============================================================================= +// ============================================================================= +namespace +{ + // ----------------------------------------------------------------------------- + ::osl::Mutex& getSafteyMutex() + { + static ::osl::Mutex s_aSafety; + return s_aSafety; + } + // ----------------------------------------------------------------------------- + oslInterlockedCount& getCounter() + { + static oslInterlockedCount s_nCounter; + return s_nCounter; + } + // ----------------------------------------------------------------------------- + OSystemParseContext* getSharedContext(OSystemParseContext* _pContext = NULL,sal_Bool _bSet = sal_False) + { + static OSystemParseContext* s_pSharedContext = NULL; + if ( _pContext && !s_pSharedContext ) + { + s_pSharedContext = _pContext; + return s_pSharedContext; + } + if ( _bSet ) + { + OSystemParseContext* pReturn = _pContext ? _pContext : s_pSharedContext; + s_pSharedContext = _pContext; + return pReturn; + } + return s_pSharedContext; + } + // ----------------------------------------------------------------------------- +} +// ----------------------------------------------------------------------------- +OParseContextClient::OParseContextClient() +{ + ::osl::MutexGuard aGuard( getSafteyMutex() ); + if ( 1 == osl_incrementInterlockedCount( &getCounter() ) ) + { // first instance + getSharedContext( new OSystemParseContext ); + } +} + +// ----------------------------------------------------------------------------- +OParseContextClient::~OParseContextClient() +{ + { + ::osl::MutexGuard aGuard( getSafteyMutex() ); + if ( 0 == osl_decrementInterlockedCount( &getCounter() ) ) + delete getSharedContext(NULL,sal_True); + } +} +// ----------------------------------------------------------------------------- +const OSystemParseContext* OParseContextClient::getParseContext() const +{ + return getSharedContext(); +} +// ----------------------------------------------------------------------------- + + + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/dataaccessdescriptor.cxx b/svx/source/form/dataaccessdescriptor.cxx new file mode 100644 index 000000000000..575481527996 --- /dev/null +++ b/svx/source/form/dataaccessdescriptor.cxx @@ -0,0 +1,569 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include <svx/dataaccessdescriptor.hxx> +#include <comphelper/stl_types.hxx> +#include <comphelper/propertysetinfo.hxx> +#include <comphelper/genericpropertyset.hxx> +#include <osl/diagnose.h> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/ucb/XContent.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <tools/urlobj.hxx> + +//........................................................................ +namespace svx +{ +//........................................................................ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::ucb; + using namespace ::comphelper; + +#define CONST_CHAR( propname ) propname, sizeof(propname) - 1 + +#ifndef SVX_LIGHT + //==================================================================== + //= ODADescriptorImpl + //==================================================================== + class ODADescriptorImpl + { + protected: + sal_Bool m_bSetOutOfDate : 1; + sal_Bool m_bSequenceOutOfDate : 1; + + public: + typedef ::std::map< DataAccessDescriptorProperty, Any > DescriptorValues; + DescriptorValues m_aValues; + Sequence< PropertyValue > m_aAsSequence; + Reference< XPropertySet > m_xAsSet; + + typedef ::std::map< ::rtl::OUString, PropertyMapEntry* > MapString2PropertyEntry; + + public: + ODADescriptorImpl(); + ODADescriptorImpl(const ODADescriptorImpl& _rSource); + + void invalidateExternRepresentations(); + + void updateSequence(); + void updateSet(); + + /** builds the descriptor from a property value sequence + @return <TRUE/> + if and only if the sequence contained valid properties only + */ + sal_Bool buildFrom( const Sequence< PropertyValue >& _rValues ); + + /** builds the descriptor from a property set + @return <TRUE/> + if and only if the set contained valid properties only + */ + sal_Bool buildFrom( const Reference< XPropertySet >& _rValues ); + + protected: + static PropertyValue buildPropertyValue( const DescriptorValues::const_iterator& _rPos ); + static const MapString2PropertyEntry& getPropertyMap( ); + static PropertyMapEntry* getPropertyMapEntry( const DescriptorValues::const_iterator& _rPos ); + }; + + //-------------------------------------------------------------------- + ODADescriptorImpl::ODADescriptorImpl() + :m_bSetOutOfDate(sal_True) + ,m_bSequenceOutOfDate(sal_True) + { + } + + //-------------------------------------------------------------------- + ODADescriptorImpl::ODADescriptorImpl(const ODADescriptorImpl& _rSource) + :m_bSetOutOfDate( _rSource.m_bSetOutOfDate ) + ,m_bSequenceOutOfDate( _rSource.m_bSequenceOutOfDate ) + ,m_aValues( _rSource.m_aValues ) + { + if (!m_bSetOutOfDate) + m_xAsSet = _rSource.m_xAsSet; + if (!m_bSequenceOutOfDate) + m_aAsSequence = _rSource.m_aAsSequence; + } + + //-------------------------------------------------------------------- + sal_Bool ODADescriptorImpl::buildFrom( const Sequence< PropertyValue >& _rValues ) + { + const MapString2PropertyEntry& rProperties = getPropertyMap(); + + sal_Bool bValidPropsOnly = sal_True; + + // loop through the sequence, and fill our m_aValues + const PropertyValue* pValues = _rValues.getConstArray(); + const PropertyValue* pValuesEnd = pValues + _rValues.getLength(); + for (;pValues != pValuesEnd; ++pValues) + { + MapString2PropertyEntry::const_iterator aPropPos = rProperties.find( pValues->Name ); + if ( aPropPos != rProperties.end() ) + { + DataAccessDescriptorProperty eProperty = (DataAccessDescriptorProperty)aPropPos->second->mnHandle; + m_aValues[eProperty] = pValues->Value; + } + else + // unknown property + bValidPropsOnly = sal_False; + } + + if (bValidPropsOnly) + { + m_aAsSequence = _rValues; + m_bSequenceOutOfDate = sal_False; + } + else + m_bSequenceOutOfDate = sal_True; + + return bValidPropsOnly; + } + + //-------------------------------------------------------------------- + sal_Bool ODADescriptorImpl::buildFrom( const Reference< XPropertySet >& _rxValues ) + { + Reference< XPropertySetInfo > xPropInfo; + if (_rxValues.is()) + xPropInfo = _rxValues->getPropertySetInfo(); + if (!xPropInfo.is()) + { + OSL_ENSURE(sal_False, "ODADescriptorImpl::buildFrom: invalid property set!"); + return sal_False; + } + + // build a PropertyValue sequence with the current values + Sequence< Property > aProperties = xPropInfo->getProperties(); + const Property* pProperty = aProperties.getConstArray(); + const Property* pPropertyEnd = pProperty + aProperties.getLength(); + + Sequence< PropertyValue > aValues(aProperties.getLength()); + PropertyValue* pValues = aValues.getArray(); + + for (;pProperty != pPropertyEnd; ++pProperty, ++pValues) + { + pValues->Name = pProperty->Name; + pValues->Value = _rxValues->getPropertyValue(pProperty->Name); + } + + sal_Bool bValidPropsOnly = buildFrom(aValues); + if (bValidPropsOnly) + { + m_xAsSet = _rxValues; + m_bSetOutOfDate = sal_False; + } + else + m_bSetOutOfDate = sal_True; + + return bValidPropsOnly; + } + + //-------------------------------------------------------------------- + void ODADescriptorImpl::invalidateExternRepresentations() + { + m_bSetOutOfDate = sal_True; + m_bSequenceOutOfDate = sal_True; + } + + //-------------------------------------------------------------------- + const ODADescriptorImpl::MapString2PropertyEntry& ODADescriptorImpl::getPropertyMap( ) + { + // the properties we know + static MapString2PropertyEntry s_aProperties; + if ( s_aProperties.empty() ) + { + static PropertyMapEntry s_aDesriptorProperties[] = + { + { CONST_CHAR("ActiveConnection"), daConnection, &::getCppuType( static_cast< Reference< XConnection >* >(NULL) ), PropertyAttribute::TRANSIENT, 0 }, + { CONST_CHAR("BookmarkSelection"), daBookmarkSelection, &::getBooleanCppuType( ), PropertyAttribute::TRANSIENT, 0 }, + { CONST_CHAR("Column"), daColumnObject, &::getCppuType( static_cast< Reference< XPropertySet >* >(NULL) ), PropertyAttribute::TRANSIENT, 0 }, + { CONST_CHAR("ColumnName"), daColumnName, &::getCppuType( static_cast< ::rtl::OUString* >(NULL) ), PropertyAttribute::TRANSIENT, 0 }, + { CONST_CHAR("Command"), daCommand, &::getCppuType( static_cast< ::rtl::OUString* >(NULL) ), PropertyAttribute::TRANSIENT, 0 }, + { CONST_CHAR("CommandType"), daCommandType, &::getCppuType( static_cast< sal_Int32* >(NULL) ), PropertyAttribute::TRANSIENT, 0 }, + { CONST_CHAR("Component"), daComponent, &::getCppuType( static_cast< Reference< XContent >* >(NULL) ), PropertyAttribute::TRANSIENT, 0 }, + { CONST_CHAR("ConnectionResource"), daConnectionResource, &::getCppuType( static_cast< ::rtl::OUString* >(NULL) ), PropertyAttribute::TRANSIENT, 0 }, + { CONST_CHAR("Cursor"), daCursor, &::getCppuType( static_cast< Reference< XResultSet>* >(NULL) ), PropertyAttribute::TRANSIENT, 0 }, + { CONST_CHAR("DataSourceName"), daDataSource, &::getCppuType( static_cast< ::rtl::OUString* >(NULL) ), PropertyAttribute::TRANSIENT, 0 }, + { CONST_CHAR("DatabaseLocation"), daDatabaseLocation, &::getCppuType( static_cast< ::rtl::OUString* >(NULL) ), PropertyAttribute::TRANSIENT, 0 }, + { CONST_CHAR("EscapeProcessing"), daEscapeProcessing, &::getBooleanCppuType( ), PropertyAttribute::TRANSIENT, 0 }, + { CONST_CHAR("Filter"), daFilter, &::getCppuType( static_cast< ::rtl::OUString* >(NULL) ), PropertyAttribute::TRANSIENT, 0 }, + { CONST_CHAR("Selection"), daSelection, &::getCppuType( static_cast< Sequence< Any >* >(NULL) ), PropertyAttribute::TRANSIENT, 0 }, + { NULL, 0, 0, NULL, 0, 0 } + }; + + PropertyMapEntry* pEntry = s_aDesriptorProperties; + while ( pEntry->mpName ) + { + s_aProperties[ ::rtl::OUString::createFromAscii( pEntry->mpName ) ] = pEntry; + ++pEntry; + } + } + + return s_aProperties; + } + + //-------------------------------------------------------------------- + PropertyMapEntry* ODADescriptorImpl::getPropertyMapEntry( const DescriptorValues::const_iterator& _rPos ) + { + const MapString2PropertyEntry& rProperties = getPropertyMap(); + + sal_Int32 nNeededHandle = (sal_Int32)(_rPos->first); + + for ( MapString2PropertyEntry::const_iterator loop = rProperties.begin(); + loop != rProperties.end(); + ++loop + ) + { + if ( nNeededHandle == loop->second->mnHandle ) + return loop->second; + } + throw RuntimeException(); + } + + //-------------------------------------------------------------------- + PropertyValue ODADescriptorImpl::buildPropertyValue( const DescriptorValues::const_iterator& _rPos ) + { + // the map entry + PropertyMapEntry* pProperty = getPropertyMapEntry( _rPos ); + + // build the property value + PropertyValue aReturn; + aReturn.Name = ::rtl::OUString( pProperty->mpName, pProperty->mnNameLen, RTL_TEXTENCODING_ASCII_US ); + aReturn.Handle = pProperty->mnHandle; + aReturn.Value = _rPos->second; + aReturn.State = PropertyState_DIRECT_VALUE; + + // outta here + return aReturn; + } + + //-------------------------------------------------------------------- + void ODADescriptorImpl::updateSequence() + { + if (!m_bSequenceOutOfDate) + return; + + m_aAsSequence.realloc(m_aValues.size()); + PropertyValue* pValue = m_aAsSequence.getArray(); + + // loop through all our values + for ( DescriptorValues::const_iterator aLoop = m_aValues.begin(); + aLoop != m_aValues.end(); + ++aLoop, ++pValue + ) + { + *pValue = buildPropertyValue(aLoop); + } + + // don't need to rebuild next time + m_bSequenceOutOfDate = sal_False; + } + + //-------------------------------------------------------------------- + void ODADescriptorImpl::updateSet() + { + if (!m_bSetOutOfDate) + return; + + // will be the current values + Sequence< PropertyValue > aValuesToSet(m_aValues.size()); + PropertyValue* pValuesToSet = aValuesToSet.getArray(); + + // build a new property set info + PropertySetInfo* pPropSetInfo = new PropertySetInfo; + + // loop through all our values + for ( DescriptorValues::const_iterator aLoop = m_aValues.begin(); + aLoop != m_aValues.end(); + ++aLoop, ++pValuesToSet + ) + { + PropertyMapEntry* pMapEntry = getPropertyMapEntry( aLoop ); + pPropSetInfo->add( pMapEntry, 1 ); + + *pValuesToSet = buildPropertyValue(aLoop); + } + + // create the generic set + m_xAsSet = GenericPropertySet_CreateInstance( pPropSetInfo ); + + // no we have the set, still need to set the current values + const PropertyValue* pSetValues = aValuesToSet.getConstArray(); + const PropertyValue* pSetValuesEnd = pSetValues + aValuesToSet.getLength(); + for (; pSetValues != pSetValuesEnd; ++pSetValues) + m_xAsSet->setPropertyValue(pSetValues->Name, pSetValues->Value); + + // don't need to rebuild next time + m_bSetOutOfDate = sal_True; + } +#endif + + //==================================================================== + //= ODataAccessDescriptor + //==================================================================== + //-------------------------------------------------------------------- + ODataAccessDescriptor::ODataAccessDescriptor() +#ifndef SVX_LIGHT + :m_pImpl(new ODADescriptorImpl) +#else + :m_pImpl(NULL) +#endif + { + } + + //-------------------------------------------------------------------- + ODataAccessDescriptor::ODataAccessDescriptor( const ODataAccessDescriptor& _rSource ) +#ifndef SVX_LIGHT + :m_pImpl(new ODADescriptorImpl(*_rSource.m_pImpl)) +#else + :m_pImpl(NULL) +#endif + { + } + + //-------------------------------------------------------------------- + const ODataAccessDescriptor& ODataAccessDescriptor::operator=(const ODataAccessDescriptor& _rSource) + { +#ifndef SVX_LIGHT + delete m_pImpl; + m_pImpl = new ODADescriptorImpl(*_rSource.m_pImpl); +#else + OSL_ENSURE(sal_False, "ODataAccessDescriptor::operator=: not available in the SVX_LIGHT version!"); +#endif + return *this; + } + + //-------------------------------------------------------------------- + ODataAccessDescriptor::ODataAccessDescriptor( const Reference< XPropertySet >& _rValues ) +#ifndef SVX_LIGHT + :m_pImpl(new ODADescriptorImpl) +#else + :m_pImpl(NULL) +#endif + { +#ifndef SVX_LIGHT + m_pImpl->buildFrom(_rValues); +#else + OSL_ENSURE(sal_False, "ODataAccessDescriptor::ODataAccessDescriptor: not available in the SVX_LIGHT version!"); +#endif + } + + //-------------------------------------------------------------------- + ODataAccessDescriptor::ODataAccessDescriptor( const Any& _rValues ) +#ifndef SVX_LIGHT + :m_pImpl(new ODADescriptorImpl) +#else + :m_pImpl(NULL) +#endif + { +#ifndef SVX_LIGHT + // check if we know the format in the Any + Sequence< PropertyValue > aValues; + Reference< XPropertySet > xValues; + if ( _rValues >>= aValues ) + m_pImpl->buildFrom( aValues ); + else if ( _rValues >>= xValues ) + m_pImpl->buildFrom( xValues ); +#else + OSL_ENSURE(sal_False, "ODataAccessDescriptor::ODataAccessDescriptor: not available in the SVX_LIGHT version!"); +#endif + } + + //-------------------------------------------------------------------- + ODataAccessDescriptor::ODataAccessDescriptor( const Sequence< PropertyValue >& _rValues ) +#ifndef SVX_LIGHT + :m_pImpl(new ODADescriptorImpl) +#else + :m_pImpl(NULL) +#endif + { +#ifndef SVX_LIGHT + m_pImpl->buildFrom(_rValues); +#else + OSL_ENSURE(sal_False, "ODataAccessDescriptor::ODataAccessDescriptor: not available in the SVX_LIGHT version!"); +#endif + } + + //-------------------------------------------------------------------- + ODataAccessDescriptor::~ODataAccessDescriptor() + { + delete m_pImpl; + } + + //-------------------------------------------------------------------- + void ODataAccessDescriptor::clear() + { +#ifndef SVX_LIGHT + m_pImpl->m_aValues.clear(); +#endif + } + + //-------------------------------------------------------------------- + void ODataAccessDescriptor::erase(DataAccessDescriptorProperty _eWhich) + { +#ifndef SVX_LIGHT + OSL_ENSURE(has(_eWhich), "ODataAccessDescriptor::erase: invalid call!"); + if (has(_eWhich)) + m_pImpl->m_aValues.erase(_eWhich); +#endif + } + + //-------------------------------------------------------------------- + sal_Bool ODataAccessDescriptor::has(DataAccessDescriptorProperty _eWhich) const + { +#ifndef SVX_LIGHT + return m_pImpl->m_aValues.find(_eWhich) != m_pImpl->m_aValues.end(); +#else + return sal_False; +#endif + } + + //-------------------------------------------------------------------- + const Any& ODataAccessDescriptor::operator [] ( DataAccessDescriptorProperty _eWhich ) const + { +#ifndef SVX_LIGHT + if (!has(_eWhich)) + { + OSL_ENSURE(sal_False, "ODataAccessDescriptor::operator[]: invalid acessor!"); + static const Any aDummy; + return aDummy; + } + + return m_pImpl->m_aValues[_eWhich]; +#else + static const Any aDummy; + return aDummy; +#endif + } + + //-------------------------------------------------------------------- + Any& ODataAccessDescriptor::operator[] ( DataAccessDescriptorProperty _eWhich ) + { +#ifndef SVX_LIGHT + m_pImpl->invalidateExternRepresentations(); + return m_pImpl->m_aValues[_eWhich]; +#else + static const Any aDummy; + return aDummy; +#endif + } + + //-------------------------------------------------------------------- + void ODataAccessDescriptor::initializeFrom(const Reference< XPropertySet >& _rxValues, sal_Bool _bClear) + { +#ifndef SVX_LIGHT + if (_bClear) + clear(); + m_pImpl->buildFrom(_rxValues); +#endif + } + + //-------------------------------------------------------------------- + void ODataAccessDescriptor::initializeFrom(const Sequence< PropertyValue >& _rValues, sal_Bool _bClear) + { +#ifndef SVX_LIGHT + if (_bClear) + clear(); + m_pImpl->buildFrom(_rValues); +#endif + } + + //-------------------------------------------------------------------- + Sequence< PropertyValue > ODataAccessDescriptor::createPropertyValueSequence() + { +#ifndef SVX_LIGHT + m_pImpl->updateSequence(); + return m_pImpl->m_aAsSequence; +#else + return Sequence< PropertyValue >(); +#endif + } + //-------------------------------------------------------------------- + Sequence< Any > ODataAccessDescriptor::createAnySequence() + { +#ifndef SVX_LIGHT + m_pImpl->updateSequence(); + Sequence< Any > aRet(m_pImpl->m_aAsSequence.getLength()); + const PropertyValue* pBegin = m_pImpl->m_aAsSequence.getConstArray(); + const PropertyValue* pEnd = pBegin + m_pImpl->m_aAsSequence.getLength(); + for(sal_Int32 i=0;pBegin != pEnd;++pBegin,++i) + aRet[i] <<= *pBegin; + return aRet; +#else + return Sequence< createAnySequence >(); +#endif + } + + //-------------------------------------------------------------------- + Reference< XPropertySet > ODataAccessDescriptor::createPropertySet() + { +#ifndef SVX_LIGHT + m_pImpl->updateSet(); + return m_pImpl->m_xAsSet; +#else + return Reference< XPropertySet >(); +#endif + } + //-------------------------------------------------------------------- + ::rtl::OUString ODataAccessDescriptor::getDataSource() const + { +#ifndef SVX_LIGHT + ::rtl::OUString sDataSourceName; + if ( has(daDataSource) ) + (*this)[daDataSource] >>= sDataSourceName; + else if ( has(daDatabaseLocation) ) + (*this)[daDatabaseLocation] >>= sDataSourceName; + return sDataSourceName; +#else + return ::rtl::OUString(); +#endif + } + //-------------------------------------------------------------------- + void ODataAccessDescriptor::setDataSource(const ::rtl::OUString& _sDataSourceNameOrLocation) + { +#ifndef SVX_LIGHT + if ( _sDataSourceNameOrLocation.getLength() ) + { + INetURLObject aURL(_sDataSourceNameOrLocation); + (*this)[ (( aURL.GetProtocol() == INET_PROT_FILE ) ? daDatabaseLocation : daDataSource)] <<= _sDataSourceNameOrLocation; + } + else + (*this)[ daDataSource ] <<= ::rtl::OUString(); +#endif + } + +//........................................................................ +} // namespace svx +//........................................................................ + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/databaselocationinput.cxx b/svx/source/form/databaselocationinput.cxx new file mode 100644 index 000000000000..bd3d746f48b3 --- /dev/null +++ b/svx/source/form/databaselocationinput.cxx @@ -0,0 +1,317 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include "svx/databaselocationinput.hxx" +#include "svx/dialmgr.hxx" + +#include "fmresids.hrc" + +/** === begin UNO includes === **/ +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +/** === end UNO includes === **/ + +#include <comphelper/componentcontext.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <rtl/ustrbuf.hxx> +#include <sfx2/filedlghelper.hxx> +#include <svtools/urlcontrol.hxx> +#include <svl/filenotation.hxx> +#include <tools/diagnose_ex.h> +#include <unotools/confignode.hxx> +#include <unotools/ucbhelper.hxx> +#include <vcl/button.hxx> +#include <vcl/msgbox.hxx> + +//........................................................................ +namespace svx +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::container::XNameAccess; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::Exception; + /** === end UNO using === **/ + namespace TemplateDescription = ::com::sun::star::ui::dialogs::TemplateDescription; + + //==================================================================== + //= DatabaseLocationInputController_Impl + //==================================================================== + class DatabaseLocationInputController_Impl + { + public: + DatabaseLocationInputController_Impl( + const ::comphelper::ComponentContext& _rContext, + ::svt::OFileURLControl& _rLocationInput, + PushButton& _rBrowseButton + ); + ~DatabaseLocationInputController_Impl(); + + bool prepareCommit(); + void setURL( const String& _rURL ); + String getURL() const; + + private: + void impl_initFilterProperties_nothrow(); + void impl_onBrowseButtonClicked(); + void impl_onLocationModified(); + String impl_getCurrentURL() const; + + DECL_LINK( OnControlAction, VclWindowEvent* ); + + private: + const ::comphelper::ComponentContext m_aContext; + ::svt::OFileURLControl& m_rLocationInput; + PushButton& m_rBrowseButton; + Sequence< ::rtl::OUString > m_aFilterExtensions; + ::rtl::OUString m_sFilterUIName; + bool m_bNeedExistenceCheck; + }; + + //-------------------------------------------------------------------- + DatabaseLocationInputController_Impl::DatabaseLocationInputController_Impl( const ::comphelper::ComponentContext& _rContext, + ::svt::OFileURLControl& _rLocationInput, PushButton& _rBrowseButton ) + :m_aContext( _rContext ) + ,m_rLocationInput( _rLocationInput ) + ,m_rBrowseButton( _rBrowseButton ) + ,m_aFilterExtensions() + ,m_sFilterUIName() + ,m_bNeedExistenceCheck( true ) + { + impl_initFilterProperties_nothrow(); + + // forward the allowed extensions to the input control + ::rtl::OUStringBuffer aExtensionList; + for ( const ::rtl::OUString* pExtension = m_aFilterExtensions.getConstArray(); + pExtension != m_aFilterExtensions.getConstArray() + m_aFilterExtensions.getLength(); + ++pExtension + ) + { + aExtensionList.append( *pExtension ); + aExtensionList.append( (sal_Unicode)';' ); + } + m_rLocationInput.SetFilter( aExtensionList.makeStringAndClear() ); + + m_rBrowseButton.AddEventListener( LINK( this, DatabaseLocationInputController_Impl, OnControlAction ) ); + m_rLocationInput.AddEventListener( LINK( this, DatabaseLocationInputController_Impl, OnControlAction ) ); + } + + //-------------------------------------------------------------------- + DatabaseLocationInputController_Impl::~DatabaseLocationInputController_Impl() + { + m_rBrowseButton.RemoveEventListener( LINK( this, DatabaseLocationInputController_Impl, OnControlAction ) ); + m_rLocationInput.RemoveEventListener( LINK( this, DatabaseLocationInputController_Impl, OnControlAction ) ); + } + + //-------------------------------------------------------------------- + bool DatabaseLocationInputController_Impl::prepareCommit() + { + ::rtl::OUString sURL( impl_getCurrentURL() ); + if ( !sURL.getLength() ) + return false; + + // check if the name exists + if ( m_bNeedExistenceCheck ) + { + if ( ::utl::UCBContentHelper::Exists( sURL ) ) + { + QueryBox aBox( m_rLocationInput.GetSystemWindow(), WB_YES_NO, SVX_RES( RID_STR_ALREADYEXISTOVERWRITE ) ); + if ( aBox.Execute() != RET_YES ) + return false; + } + } + + return true; + } + + //-------------------------------------------------------------------- + void DatabaseLocationInputController_Impl::setURL( const String& _rURL ) + { + ::svt::OFileNotation aTransformer( _rURL ); + m_rLocationInput.SetText( aTransformer.get( ::svt::OFileNotation::N_SYSTEM ) ); + } + + //-------------------------------------------------------------------- + String DatabaseLocationInputController_Impl::getURL() const + { + return impl_getCurrentURL(); + } + + //-------------------------------------------------------------------- + void DatabaseLocationInputController_Impl::impl_initFilterProperties_nothrow() + { + try + { + // get the name of the default filter for database documents + ::utl::OConfigurationTreeRoot aConfig( + ::utl::OConfigurationTreeRoot::createWithServiceFactory( + m_aContext.getLegacyServiceFactory(), + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Setup/Office/Factories/com.sun.star.sdb.OfficeDatabaseDocument" ) ) + ) ); + ::rtl::OUString sDatabaseFilter; + OSL_VERIFY( aConfig.getNodeValue( "ooSetupFactoryActualFilter" ) >>= sDatabaseFilter ); + + // get the type this filter is responsible for + Reference< XNameAccess > xFilterFactory( + m_aContext.createComponent( "com.sun.star.document.FilterFactory" ), + UNO_QUERY_THROW ); + ::comphelper::NamedValueCollection aFilterProperties( xFilterFactory->getByName( sDatabaseFilter ) ); + ::rtl::OUString sDocumentType = aFilterProperties.getOrDefault( "Type", ::rtl::OUString() ); + + // get the extension(s) for this type + Reference< XNameAccess > xTypeDetection( + m_aContext.createComponent( "com.sun.star.document.TypeDetection" ), + UNO_QUERY_THROW ); + + ::comphelper::NamedValueCollection aTypeProperties( xTypeDetection->getByName( sDocumentType ) ); + m_aFilterExtensions = aTypeProperties.getOrDefault( "Extensions", m_aFilterExtensions ); + m_sFilterUIName = aTypeProperties.getOrDefault( "UIName", m_sFilterUIName ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + // ensure we have at least one extension + OSL_ENSURE( m_aFilterExtensions.getLength(), + "DatabaseLocationInputController_Impl::impl_initFilterProperties_nothrow: unable to determine the file extension(s)!" ); + if ( m_aFilterExtensions.getLength() == 0 ) + { + m_aFilterExtensions.realloc(1); + m_aFilterExtensions[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*.odb" ) ); + } + } + + // ----------------------------------------------------------------------------- + IMPL_LINK( DatabaseLocationInputController_Impl, OnControlAction, VclWindowEvent*, _pEvent ) + { + if ( ( _pEvent->GetWindow() == &m_rBrowseButton ) + && ( _pEvent->GetId() == VCLEVENT_BUTTON_CLICK ) + ) + { + impl_onBrowseButtonClicked(); + } + + if ( ( _pEvent->GetWindow() == &m_rLocationInput ) + && ( _pEvent->GetId() == VCLEVENT_EDIT_MODIFY ) + ) + { + impl_onLocationModified(); + } + + return 0L; + } + + // ----------------------------------------------------------------------------- + String DatabaseLocationInputController_Impl::impl_getCurrentURL() const + { + String sCurrentFile( m_rLocationInput.GetText() ); + if ( sCurrentFile.Len() ) + { + ::svt::OFileNotation aCurrentFile( sCurrentFile ); + sCurrentFile = aCurrentFile.get( ::svt::OFileNotation::N_URL ); + } + return sCurrentFile; + } + + // ----------------------------------------------------------------------------- + void DatabaseLocationInputController_Impl::impl_onBrowseButtonClicked() + { + ::sfx2::FileDialogHelper aFileDlg( + TemplateDescription::FILESAVE_AUTOEXTENSION, + WB_STDMODAL | WB_SAVEAS, + m_rLocationInput.GetSystemWindow() + ); + aFileDlg.SetDisplayDirectory( impl_getCurrentURL() ); + + aFileDlg.AddFilter( m_sFilterUIName, ::rtl::OUStringBuffer().appendAscii( "*." ).append( m_aFilterExtensions[0] ).makeStringAndClear() ); + aFileDlg.SetCurrentFilter( m_sFilterUIName ); + + if ( aFileDlg.Execute() == ERRCODE_NONE ) + { + INetURLObject aURL( aFileDlg.GetPath() ); + if( aURL.GetProtocol() != INET_PROT_NOT_VALID ) + { + ::svt::OFileNotation aFileNotation( aURL.GetMainURL( INetURLObject::NO_DECODE ) ); + m_rLocationInput.SetText( aFileNotation.get( ::svt::OFileNotation::N_SYSTEM ) ); + m_rLocationInput.GetModifyHdl().Call( &m_rLocationInput ); + // the dialog already checked for the file's existence, so we don't need to, again + m_bNeedExistenceCheck = false; + } + } + } + + // ----------------------------------------------------------------------------- + void DatabaseLocationInputController_Impl::impl_onLocationModified() + { + m_bNeedExistenceCheck = true; + } + + //==================================================================== + //= DatabaseLocationInputController + //==================================================================== + //-------------------------------------------------------------------- + DatabaseLocationInputController::DatabaseLocationInputController( const ::comphelper::ComponentContext& _rContext, + ::svt::OFileURLControl& _rLocationInput, PushButton& _rBrowseButton ) + :m_pImpl( new DatabaseLocationInputController_Impl( _rContext, _rLocationInput, _rBrowseButton ) ) + { + } + + //-------------------------------------------------------------------- + DatabaseLocationInputController::~DatabaseLocationInputController() + { + } + + //-------------------------------------------------------------------- + bool DatabaseLocationInputController::prepareCommit() + { + return m_pImpl->prepareCommit(); + } + + //-------------------------------------------------------------------- + void DatabaseLocationInputController::setURL( const String& _rURL ) + { + m_pImpl->setURL( _rURL ); + } + + //-------------------------------------------------------------------- + String DatabaseLocationInputController::getURL() const + { + return m_pImpl->getURL(); + } + +//........................................................................ +} // namespace svx +//........................................................................ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/datalistener.cxx b/svx/source/form/datalistener.cxx new file mode 100644 index 000000000000..35f6b32cc1a7 --- /dev/null +++ b/svx/source/form/datalistener.cxx @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include "datalistener.hxx" +#include "datanavi.hxx" + +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::dom::events; + +//............................................................................ +namespace svxform +{ +//............................................................................ + + DataListener::DataListener( DataNavigatorWindow* pNaviWin ) : + + m_pNaviWin( pNaviWin ) + + { + DBG_ASSERT( m_pNaviWin, "DataListener::Ctor(): no navigator win" ); + } + + DataListener::~DataListener() + { + } + + // XContainerListener + void SAL_CALL DataListener::elementInserted( const ContainerEvent& /*Event*/ ) throw (RuntimeException) + { + m_pNaviWin->NotifyChanges(); + } + + void SAL_CALL DataListener::elementRemoved( const ContainerEvent& /*Event*/ ) throw (RuntimeException) + { + m_pNaviWin->NotifyChanges(); + } + + void SAL_CALL DataListener::elementReplaced( const ContainerEvent& /*Event*/ ) throw (RuntimeException) + { + m_pNaviWin->NotifyChanges(); + } + + // XFrameActionListener + void SAL_CALL DataListener::frameAction( const FrameActionEvent& rActionEvt ) throw (RuntimeException) + { + if ( FrameAction_COMPONENT_ATTACHED == rActionEvt.Action || + FrameAction_COMPONENT_REATTACHED == rActionEvt.Action ) + { + m_pNaviWin->NotifyChanges( FrameAction_COMPONENT_REATTACHED == rActionEvt.Action ); + } + } + + // xml::dom::events::XEventListener + void SAL_CALL DataListener::handleEvent( const Reference< XEvent >& /*evt*/ ) throw (RuntimeException) + { + m_pNaviWin->NotifyChanges(); + } + + // lang::XEventListener + void SAL_CALL DataListener::disposing( const EventObject& /*Source*/ ) throw (RuntimeException) + { + DBG_ERRORFILE( "disposing" ); + } + +//............................................................................ +} // namespace svxform +//............................................................................ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/datanavi.cxx b/svx/source/form/datanavi.cxx new file mode 100644 index 000000000000..25c05260338c --- /dev/null +++ b/svx/source/form/datanavi.cxx @@ -0,0 +1,3727 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include <sal/macros.h> +#include "datanavi.hxx" +#include "fmservs.hxx" + +#include "datanavi.hrc" +#include "fmresids.hrc" +#include "fmhelp.hrc" +#include <svx/svxids.hrc> +#include <tools/rcid.h> +#include <tools/diagnose_ex.h> +#include "xmlexchg.hxx" +#include <svx/dialmgr.hxx> +#include <svx/fmshell.hxx> +#include <svtools/miscopt.hxx> +#include <unotools/pathoptions.hxx> +#include <unotools/viewoptions.hxx> +#include <svtools/svtools.hrc> +#include <sfx2/app.hxx> +#include <sfx2/filedlghelper.hxx> +#include <sfx2/objitem.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/dispatch.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/container/XSet.hpp> +#include <com/sun/star/datatransfer/XTransferable.hpp> +#include <com/sun/star/frame/XController.hpp> +#include <com/sun/star/frame/XFramesSupplier.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include "com/sun/star/ui/dialogs/TemplateDescription.hpp" +#include <com/sun/star/xforms/XFormsSupplier.hpp> +#include <com/sun/star/xml/dom/XDocument.hpp> +#include <com/sun/star/xml/dom/DOMException.hpp> +#include <com/sun/star/form/binding/XValueBinding.hpp> +#include <comphelper/processfactory.hxx> +#include <rtl/logfile.hxx> + +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::datatransfer; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::dom::events; +using namespace ::svx; + +namespace css = ::com::sun::star; + +#define CFGNAME_DATANAVIGATOR DEFINE_CONST_UNICODE("DataNavigator") +#define CFGNAME_SHOWDETAILS DEFINE_CONST_UNICODE("ShowDetails") +#define MSG_VARIABLE DEFINE_CONST_UNICODE("%1") +#define MODELNAME DEFINE_CONST_UNICODE("$MODELNAME") +#define INSTANCENAME DEFINE_CONST_UNICODE("$INSTANCENAME") +#define ELEMENTNAME DEFINE_CONST_UNICODE("$ELEMENTNAME") +#define ATTRIBUTENAME DEFINE_CONST_UNICODE("$ATTRIBUTENAME") +#define SUBMISSIONNAME DEFINE_CONST_UNICODE("$SUBMISSIONNAME") +#define BINDINGNAME DEFINE_CONST_UNICODE("$BINDINGNAME") + +//............................................................................ +namespace svxform +{ +//............................................................................ + + // properties of instance + #define PN_INSTANCE_MODEL ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Instance" ) ) + #define PN_INSTANCE_ID ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ID" ) ) + #define PN_INSTANCE_URL ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "URL" ) ) + #define PN_INSTANCE_URLONCE ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "URLOnce" ) ) + + // properties of binding + #define PN_BINDING_ID ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "BindingID" ) ) + #define PN_BINDING_EXPR ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "BindingExpression" ) ) + #define PN_BINDING_MODEL ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Model" ) ) + #define PN_BINDING_NAMESPACES ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ModelNamespaces" ) ) + #define PN_BINDING_MODELID ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ModelID" ) ) + #define PN_READONLY_EXPR ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ReadonlyExpression" ) ) + #define PN_RELEVANT_EXPR ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "RelevantExpression" ) ) + #define PN_REQUIRED_EXPR ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "RequiredExpression" ) ) + #define PN_CONSTRAINT_EXPR ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ConstraintExpression" ) ) + #define PN_CALCULATE_EXPR ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CalculateExpression" ) ) + #define PN_BINDING_TYPE ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Type" ) ) + #define PN_BINDING_READONLY ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ReadOnly" ) ) + #define PN_BINDING_ENABLED ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Enabled" ) ) + + // properties of submission + #define PN_SUBMISSION_ID ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ID" ) ) + #define PN_SUBMISSION_BIND ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Bind" ) ) + #define PN_SUBMISSION_REF ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Ref" ) ) + #define PN_SUBMISSION_ACTION ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Action" ) ) + #define PN_SUBMISSION_METHOD ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Method" ) ) + #define PN_SUBMISSION_MODEL ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Model" ) ) + #define PN_SUBMISSION_REPLACE ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Replace" ) ) + + // submission methods + #define SUBMITMETHOD_POST ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "post" ) ) + #define SUBMITMETHOD_GET ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "get" ) ) + #define SUBMITMETHOD_PUT ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "put" ) ) + + // other const strings + #define TRUE_VALUE ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "true()" ) ) + #define FALSE_VALUE ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "false()" ) ) + #define NEW_ELEMENT ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "newElement" ) ) + #define NEW_ATTRIBUTE ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "newAttribute" ) ) + #define EVENTTYPE_SUBTREE ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DOMSubtreeModified" ) ) + #define EVENTTYPE_CHARDATA ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DOMCharacterDataModified" ) ) + #define EVENTTYPE_ATTR ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DOMAttrModified" ) ) + + #define MIN_PAGE_COUNT 3 // at least one instance, one submission and one binding page + + struct ItemNode + { + Reference< css::xml::dom::XNode > m_xNode; + Reference< XPropertySet > m_xPropSet; + + ItemNode( const Reference< css::xml::dom::XNode >& _rxNode ) : + m_xNode( _rxNode ) {} + ItemNode( const Reference< XPropertySet >& _rxSet ) : + m_xPropSet( _rxSet ) {} + + DataGroupType GetDataGroupType() const; + }; + + //======================================================================== + // class DataTreeListBox + //======================================================================== + DataTreeListBox::DataTreeListBox( XFormsPage* pPage, DataGroupType _eGroup, const ResId& rResId ) : + + SvTreeListBox( pPage, rResId ), + + m_pXFormsPage ( pPage ), + m_eGroup ( _eGroup ) + + { + EnableContextMenuHandling(); + + if ( DGTInstance == m_eGroup ) + SetDragDropMode( SV_DRAGDROP_CTRL_MOVE |SV_DRAGDROP_CTRL_COPY | SV_DRAGDROP_APP_COPY ); + } + + DataTreeListBox::~DataTreeListBox() + { + DeleteAndClear(); + } + + sal_Int8 DataTreeListBox::AcceptDrop( const AcceptDropEvent& /*rEvt*/ ) + { + return DND_ACTION_NONE; + } + sal_Int8 DataTreeListBox::ExecuteDrop( const ExecuteDropEvent& /*rEvt*/ ) + { + return DND_ACTION_NONE; + } + void DataTreeListBox::StartDrag( sal_Int8 /*_nAction*/, const Point& /*_rPosPixel*/ ) + { + SvLBoxEntry* pSelected = FirstSelected(); + if ( !pSelected ) + // no drag without an entry + return; + + if ( m_eGroup == DGTBinding ) + // for the moment, bindings cannot be dragged. + // #i59395# / 2005-12-15 / frank.schoenheit@sun.com + return; + + // GetServiceNameForNode() requires a datatype repository which + // will be automatically build if requested??? + Reference< css::xforms::XModel > xModel( m_pXFormsPage->GetXFormsHelper(), UNO_QUERY ); + Reference< css::xforms::XDataTypeRepository > xDataTypes = + xModel->getDataTypeRepository(); + if(!xDataTypes.is()) + return; + + using namespace ::com::sun::star::uno; + typedef com::sun::star::form::binding::XValueBinding XValueBinding_t; + + ItemNode *pItemNode = static_cast<ItemNode*>(pSelected->GetUserData()); + + if ( !pItemNode ) + { + // the only known (and allowed?) case where this happens are sub-entries of a submission + // entry + DBG_ASSERT( DGTSubmission == m_eGroup, "DataTreeListBox::StartDrag: how this?" ); + pSelected = GetParent( pSelected ); + DBG_ASSERT( pSelected && !GetParent( pSelected ), "DataTreeListBox::StartDrag: what kind of entry *is* this?" ); + // on the submission page, we have only top-level entries (the submission themself) + // plus direct children of those (facets of a submission) + pItemNode = pSelected ? static_cast< ItemNode* >( pSelected->GetUserData() ) : NULL; + if ( !pItemNode ) + return; + } + + OXFormsDescriptor desc; + desc.szName = GetEntryText(pSelected); + if(pItemNode->m_xNode.is()) { + // a valid node interface tells us that we need to create a control from a binding + desc.szServiceName = m_pXFormsPage->GetServiceNameForNode(pItemNode->m_xNode); + desc.xPropSet = m_pXFormsPage->GetBindingForNode(pItemNode->m_xNode); + DBG_ASSERT( desc.xPropSet.is(), "DataTreeListBox::StartDrag(): invalid node binding" ); + } + else { + desc.szServiceName = FM_COMPONENT_COMMANDBUTTON; + desc.xPropSet = pItemNode->m_xPropSet; + } + OXFormsTransferable *pTransferable = new OXFormsTransferable(desc); + Reference< XTransferable > xEnsureDelete = pTransferable; + if(pTransferable) { + EndSelection(); + pTransferable->StartDrag( this, DND_ACTION_COPY ); + } + } + + PopupMenu* DataTreeListBox::CreateContextMenu() + { + PopupMenu* pMenu = new PopupMenu( SVX_RES( RID_MENU_DATANAVIGATOR ) ); + if ( DGTInstance == m_eGroup ) + pMenu->RemoveItem( pMenu->GetItemPos( TBI_ITEM_ADD ) ); + else + { + pMenu->RemoveItem( pMenu->GetItemPos( TBI_ITEM_ADD_ELEMENT ) ); + pMenu->RemoveItem( pMenu->GetItemPos( TBI_ITEM_ADD_ATTRIBUTE ) ); + + if ( DGTSubmission == m_eGroup ) + { + pMenu->SetItemText( TBI_ITEM_ADD, SVX_RESSTR( RID_STR_DATANAV_ADD_SUBMISSION ) ); + pMenu->SetItemText( TBI_ITEM_EDIT, SVX_RESSTR( RID_STR_DATANAV_EDIT_SUBMISSION ) ); + pMenu->SetItemText( TBI_ITEM_REMOVE, SVX_RESSTR( RID_STR_DATANAV_REMOVE_SUBMISSION ) ); + } + else + { + pMenu->SetItemText( TBI_ITEM_ADD, SVX_RESSTR( RID_STR_DATANAV_ADD_BINDING ) ); + pMenu->SetItemText( TBI_ITEM_EDIT, SVX_RESSTR( RID_STR_DATANAV_EDIT_BINDING ) ); + pMenu->SetItemText( TBI_ITEM_REMOVE, SVX_RESSTR( RID_STR_DATANAV_REMOVE_BINDING ) ); + } + } + m_pXFormsPage->EnableMenuItems( pMenu ); + return pMenu; + } + + void DataTreeListBox::ExcecuteContextMenuAction( USHORT _nSelectedPopupEntry ) + { + m_pXFormsPage->DoMenuAction( _nSelectedPopupEntry ); + } + + void DataTreeListBox::RemoveEntry( SvLBoxEntry* _pEntry ) + { + if ( _pEntry ) + { + delete static_cast< ItemNode* >( _pEntry->GetUserData() ); + SvTreeListBox::GetModel()->Remove( _pEntry ); + } + } + + void DataTreeListBox::DeleteAndClear() + { + ULONG i, nCount = GetEntryCount(); + for ( i = 0; i < nCount; ++i ) + { + SvLBoxEntry* pEntry = GetEntry(i); + if ( pEntry ) + delete static_cast< ItemNode* >( pEntry->GetUserData() ); + } + + Clear(); + } + + //======================================================================== + // class XFormsPage + //======================================================================== + XFormsPage::XFormsPage( Window* pParent, DataNavigatorWindow* _pNaviWin, DataGroupType _eGroup ) : + + TabPage( pParent, SVX_RES( RID_SVX_XFORMS_TABPAGES ) ), + + m_aToolBox ( this, SVX_RES( TB_ITEMS ) ), + m_aItemList ( this, _eGroup, SVX_RES( LB_ITEMS ) ), + m_pNaviWin ( _pNaviWin ), + m_bHasModel ( false ), + m_eGroup ( _eGroup ), + m_TbxImageList ( SVX_RES( IL_TBX_BMPS ) ) + + { + FreeResource(); + + const ImageList& rImageList = m_TbxImageList; + m_aToolBox.SetItemImage( TBI_ITEM_ADD, rImageList.GetImage( IID_ITEM_ADD ) ); + m_aToolBox.SetItemImage( TBI_ITEM_ADD_ELEMENT, rImageList.GetImage( IID_ITEM_ADD_ELEMENT ) ); + m_aToolBox.SetItemImage( TBI_ITEM_ADD_ATTRIBUTE, rImageList.GetImage( IID_ITEM_ADD_ATTRIBUTE ) ); + m_aToolBox.SetItemImage( TBI_ITEM_EDIT, rImageList.GetImage( IID_ITEM_EDIT ) ); + m_aToolBox.SetItemImage( TBI_ITEM_REMOVE, rImageList.GetImage( IID_ITEM_REMOVE ) ); + + if ( DGTInstance == m_eGroup ) + m_aToolBox.RemoveItem( m_aToolBox.GetItemPos( TBI_ITEM_ADD ) ); + else + { + m_aToolBox.RemoveItem( m_aToolBox.GetItemPos( TBI_ITEM_ADD_ELEMENT ) ); + m_aToolBox.RemoveItem( m_aToolBox.GetItemPos( TBI_ITEM_ADD_ATTRIBUTE ) ); + + if ( DGTSubmission == m_eGroup ) + { + m_aToolBox.SetItemText( TBI_ITEM_ADD, SVX_RESSTR( RID_STR_DATANAV_ADD_SUBMISSION ) ); + m_aToolBox.SetItemText( TBI_ITEM_EDIT, SVX_RESSTR( RID_STR_DATANAV_EDIT_SUBMISSION ) ); + m_aToolBox.SetItemText( TBI_ITEM_REMOVE, SVX_RESSTR( RID_STR_DATANAV_REMOVE_SUBMISSION ) ); + } + else + { + m_aToolBox.SetItemText( TBI_ITEM_ADD, SVX_RESSTR( RID_STR_DATANAV_ADD_BINDING ) ); + m_aToolBox.SetItemText( TBI_ITEM_EDIT, SVX_RESSTR( RID_STR_DATANAV_EDIT_BINDING ) ); + m_aToolBox.SetItemText( TBI_ITEM_REMOVE, SVX_RESSTR( RID_STR_DATANAV_REMOVE_BINDING ) ); + } + } + + const Size aTbxSz( m_aToolBox.CalcWindowSizePixel() ); + m_aToolBox.SetSizePixel( aTbxSz ); + m_aToolBox.SetOutStyle( SvtMiscOptions().GetToolboxStyle() ); + m_aToolBox.SetSelectHdl( LINK( this, XFormsPage, TbxSelectHdl ) ); + Point aPos = m_aItemList.GetPosPixel(); + aPos.Y() = aTbxSz.Height(); + m_aItemList.SetPosPixel( aPos ); + + m_aItemList.SetSelectHdl( LINK( this, XFormsPage, ItemSelectHdl ) ); + m_aItemList.SetNodeDefaultImages(); + WinBits nBits = WB_BORDER | WB_TABSTOP | WB_HIDESELECTION | WB_NOINITIALSELECTION; + if ( DGTInstance == m_eGroup || DGTSubmission == m_eGroup ) + nBits |= WB_HASBUTTONS | WB_HASLINES | WB_HASLINESATROOT | WB_HASBUTTONSATROOT; + m_aItemList.SetWindowBits( m_aItemList.GetStyle() | nBits ); + m_aItemList.Show(); + ItemSelectHdl( &m_aItemList ); + } + //------------------------------------------------------------------------ + XFormsPage::~XFormsPage() + { + } + //------------------------------------------------------------------------ + IMPL_LINK( XFormsPage, TbxSelectHdl, ToolBox *, EMPTYARG ) + { + DoToolBoxAction( m_aToolBox.GetCurItemId() ); + return 0; + } + //------------------------------------------------------------------------ + IMPL_LINK( XFormsPage, ItemSelectHdl, DataTreeListBox *, EMPTYARG ) + { + EnableMenuItems( NULL ); + return 0; + } + //------------------------------------------------------------------------ + void XFormsPage::AddChildren( + SvLBoxEntry* _pParent, const ImageList& _rImgLst, + const Reference< css::xml::dom::XNode >& _xNode ) + { + DBG_ASSERT( m_xUIHelper.is(), "XFormsPage::AddChildren(): invalid UIHelper" ); + + try + { + Reference< css::xml::dom::XNodeList > xNodeList = _xNode->getChildNodes(); + if ( xNodeList.is() ) + { + bool bShowDetails = m_pNaviWin->IsShowDetails(); + sal_Int32 i, nNodeCount = xNodeList->getLength(); + for ( i = 0; i < nNodeCount; ++i ) + { + Reference< css::xml::dom::XNode > xChild = xNodeList->item(i); + css::xml::dom::NodeType eChildType = xChild->getNodeType(); + Image aExpImg, aCollImg; + switch ( eChildType ) + { + case css::xml::dom::NodeType_ATTRIBUTE_NODE: + aExpImg = aCollImg = _rImgLst.GetImage( IID_ATTRIBUTE ); + break; + case css::xml::dom::NodeType_ELEMENT_NODE: + aExpImg = aCollImg = _rImgLst.GetImage( IID_ELEMENT ); + break; + case css::xml::dom::NodeType_TEXT_NODE: + aExpImg = aCollImg = _rImgLst.GetImage( IID_TEXT ); + break; + default: + aExpImg = aCollImg = _rImgLst.GetImage( IID_OTHER ); + } + + ::rtl::OUString sName = m_xUIHelper->getNodeDisplayName( xChild, bShowDetails ); + if ( sName.getLength() > 0 ) + { + ItemNode* pNode = new ItemNode( xChild ); + SvLBoxEntry* pEntry = m_aItemList.InsertEntry( + sName, aExpImg, aCollImg, _pParent, FALSE, LIST_APPEND, pNode ); + if ( xChild->hasAttributes() ) + { + Reference< css::xml::dom::XNamedNodeMap > xMap = xChild->getAttributes(); + if ( xMap.is() ) + { + aExpImg = aCollImg = _rImgLst.GetImage( IID_ATTRIBUTE ); + sal_Int32 j, nMapLen = xMap->getLength(); + for ( j = 0; j < nMapLen; ++j ) + { + Reference< css::xml::dom::XNode > xAttr = xMap->item(j); + pNode = new ItemNode( xAttr ); + ::rtl::OUString sAttrName = + m_xUIHelper->getNodeDisplayName( xAttr, bShowDetails ); + m_aItemList.InsertEntry( + sAttrName, aExpImg, aCollImg, + pEntry, FALSE, LIST_APPEND, pNode ); + } + } + } + if ( xChild->hasChildNodes() ) + AddChildren( pEntry, _rImgLst, xChild ); + } + } + } + } + catch( Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + //------------------------------------------------------------------------ + bool XFormsPage::DoToolBoxAction( USHORT _nToolBoxID ) { + + bool bHandled = false; + bool bIsDocModified = false; + m_pNaviWin->DisableNotify( true ); + + switch ( _nToolBoxID ) + { + case TBI_ITEM_ADD: + case TBI_ITEM_ADD_ELEMENT: + case TBI_ITEM_ADD_ATTRIBUTE: + { + bHandled = true; + Reference< css::xforms::XModel > xModel( m_xUIHelper, UNO_QUERY ); + DBG_ASSERT( xModel.is(), "XFormsPage::DoToolBoxAction(): Action without model" ); + if ( DGTSubmission == m_eGroup ) + { + AddSubmissionDialog aDlg( this, NULL, m_xUIHelper ); + if ( aDlg.Execute() == RET_OK && aDlg.GetNewSubmission().is() ) + { + try + { + Reference< css::xforms::XSubmission > xNewSubmission = aDlg.GetNewSubmission(); + Reference< XSet > xSubmissions( xModel->getSubmissions(), UNO_QUERY ); + xSubmissions->insert( makeAny( xNewSubmission ) ); + Reference< XPropertySet > xNewPropSet( xNewSubmission, UNO_QUERY ); + SvLBoxEntry* pEntry = AddEntry( xNewPropSet ); + m_aItemList.Select( pEntry, TRUE ); + bIsDocModified = true; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::DoToolBoxAction(): exception while adding submission" ); + } + } + } + else + { + DataItemType eType = DITElement; + SvLBoxEntry* pEntry = m_aItemList.FirstSelected(); + ItemNode* pNode = NULL; + Reference< css::xml::dom::XNode > xParentNode; + Reference< XPropertySet > xNewBinding; + USHORT nResId = 0; + bool bIsElement = true; + if ( DGTInstance == m_eGroup ) + { + if ( m_sInstanceURL.Len() > 0 ) + { + LinkedInstanceWarningBox aMsgBox( this ); + if ( aMsgBox.Execute() != RET_OK ) + return bHandled; + } + + DBG_ASSERT( pEntry, "XFormsPage::DoToolBoxAction(): no entry" ); + ItemNode* pParentNode = static_cast< ItemNode* >( pEntry->GetUserData() ); + DBG_ASSERT( pParentNode, "XFormsPage::DoToolBoxAction(): no parent node" ); + xParentNode = pParentNode->m_xNode; + Reference< css::xml::dom::XNode > xNewNode; + if ( TBI_ITEM_ADD_ELEMENT == _nToolBoxID ) + { + try + { + nResId = RID_STR_DATANAV_ADD_ELEMENT; + xNewNode = m_xUIHelper->createElement( xParentNode, NEW_ELEMENT ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::DoToolBoxAction(): exception while create element" ); + } + } + else + { + nResId = RID_STR_DATANAV_ADD_ATTRIBUTE; + bIsElement = false; + eType = DITAttribute; + try + { + xNewNode = m_xUIHelper->createAttribute( xParentNode, NEW_ATTRIBUTE ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::DoToolBoxAction(): exception while create attribute" ); + } + } + + try + { + xNewNode = xParentNode->appendChild( xNewNode ); + } + catch ( css::xml::dom::DOMException& e ) + { + if ( e.Code == css::xml::dom::DOMExceptionType_DOMSTRING_SIZE_ERR ) + { + DBG_ERRORFILE( "XFormsPage::DoToolBoxAction(): domexception: size error" ); + } + DBG_ERRORFILE( "XFormsPage::DoToolBoxAction(): domexception while append child" ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::DoToolBoxAction(): exception while append child" ); + } + + try + { + Reference< css::xml::dom::XNode > xPNode; + if ( xNewNode.is() ) + xPNode = xNewNode->getParentNode(); + // attributes don't have parents in the DOM model + DBG_ASSERT( TBI_ITEM_ADD_ATTRIBUTE == _nToolBoxID + || xPNode.is(), "XFormsPage::DoToolboxAction(): node not added" ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::DoToolboxAction(): exception caught" ); + } + + try + { + m_xUIHelper->getBindingForNode( xNewNode, sal_True ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::DoToolBoxAction(): exception while get binding for node" ); + } + pNode = new ItemNode( xNewNode ); + } + else + { + try + { + nResId = RID_STR_DATANAV_ADD_BINDING; + xNewBinding = xModel->createBinding(); + Reference< XSet > xBindings( xModel->getBindings(), UNO_QUERY ); + xBindings->insert( makeAny( xNewBinding ) ); + pNode = new ItemNode( xNewBinding ); + eType = DITBinding; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::DoToolBoxAction(): exception while adding binding" ); + } + } + + AddDataItemDialog aDlg( this, pNode, m_xUIHelper ); + aDlg.SetText( SVX_RESSTR( nResId ) ); + aDlg.InitText( eType ); + short nReturn = aDlg.Execute(); + if ( DGTInstance == m_eGroup ) + { + if ( RET_OK == nReturn ) + { + SvLBoxEntry* pNewEntry = AddEntry( pNode, bIsElement ); + m_aItemList.MakeVisible( pNewEntry ); + m_aItemList.Select( pNewEntry, TRUE ); + bIsDocModified = true; + } + else + { + try + { + Reference< css::xml::dom::XNode > xPNode; + Reference< css::xml::dom::XNode > xNode = + xParentNode->removeChild( pNode->m_xNode ); + if ( xNode.is() ) + xPNode = xNode->getParentNode(); + DBG_ASSERT( !xPNode.is(), "XFormsPage::RemoveEntry(): node not removed" ); + delete pNode; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::DoToolboxAction(): exception caught" ); + } + } + } + else + { + if ( RET_OK == nReturn ) + { + SvLBoxEntry* pNewEntry = AddEntry( xNewBinding ); + m_aItemList.Select( pNewEntry, TRUE ); + bIsDocModified = true; + } + else + { + try + { + Reference< XSet > xBindings( xModel->getBindings(), UNO_QUERY ); + xBindings->remove( makeAny( xNewBinding ) ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::DoToolboxAction(): exception caught" ); + } + } + delete pNode; + } + } + } + break; + + case TBI_ITEM_EDIT: + { + bHandled = true; + SvLBoxEntry* pEntry = m_aItemList.FirstSelected(); + if ( pEntry ) + { + if ( DGTSubmission == m_eGroup && m_aItemList.GetParent( pEntry ) ) + pEntry = m_aItemList.GetParent( pEntry ); + ItemNode* pNode = static_cast< ItemNode* >( pEntry->GetUserData() ); + if ( DGTInstance == m_eGroup || DGTBinding == m_eGroup ) + { + if ( DGTInstance == m_eGroup && m_sInstanceURL.Len() > 0 ) + { + LinkedInstanceWarningBox aMsgBox( this ); + if ( aMsgBox.Execute() != RET_OK ) + return bHandled; + } + + AddDataItemDialog aDlg( this, pNode, m_xUIHelper ); + DataItemType eType = DITElement; + USHORT nResId = RID_STR_DATANAV_EDIT_ELEMENT; + if ( pNode && pNode->m_xNode.is() ) + { + try + { + css::xml::dom::NodeType eChildType = pNode->m_xNode->getNodeType(); + if ( eChildType == css::xml::dom::NodeType_ATTRIBUTE_NODE ) + { + nResId = RID_STR_DATANAV_EDIT_ATTRIBUTE; + eType = DITAttribute; + } + } + catch ( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::DoToolboxAction(): exception caught" ); + } + } + else if ( DGTBinding == m_eGroup ) + { + nResId = RID_STR_DATANAV_EDIT_BINDING; + eType = DITBinding; + } + aDlg.SetText( SVX_RESSTR( nResId ) ); + aDlg.InitText( eType ); + if ( aDlg.Execute() == RET_OK ) + { + // Set the new name + String sNewName; + if ( DGTInstance == m_eGroup ) + { + try + { + sNewName = m_xUIHelper->getNodeDisplayName( + pNode->m_xNode, m_pNaviWin->IsShowDetails() ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::DoToolboxAction(): exception caught" ); + } + } + else + { + try + { + String sDelim( RTL_CONSTASCII_USTRINGPARAM( ": " ) ); + ::rtl::OUString sTemp; + pNode->m_xPropSet->getPropertyValue( PN_BINDING_ID ) >>= sTemp; + sNewName += String( sTemp ); + sNewName += sDelim; + pNode->m_xPropSet->getPropertyValue( PN_BINDING_EXPR ) >>= sTemp; + sNewName += String( sTemp ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::DoToolboxAction(): exception caught" ); + } + } + + m_aItemList.SetEntryText( pEntry, sNewName ); + bIsDocModified = true; + } + } + else + { + AddSubmissionDialog aDlg( this, pNode, m_xUIHelper ); + aDlg.SetText( SVX_RESSTR( RID_STR_DATANAV_EDIT_SUBMISSION ) ); + if ( aDlg.Execute() == RET_OK ) + { + EditEntry( pNode->m_xPropSet ); + bIsDocModified = true; + } + } + } + } + break; + + case TBI_ITEM_REMOVE: + { + bHandled = true; + if ( DGTInstance == m_eGroup && m_sInstanceURL.Len() > 0 ) + { + LinkedInstanceWarningBox aMsgBox( this ); + if ( aMsgBox.Execute() != RET_OK ) + return bHandled; + } + bIsDocModified = RemoveEntry(); + } + break; + + case MID_INSERT_CONTROL: + { + OSL_ENSURE( false, "XFormsPage::DoToolboxAction: MID_INSERT_CONTROL not implemented, yet!" ); + } + break; + + default: + OSL_ENSURE( false, "XFormsPage::DoToolboxAction: unknown ID!" ); + break; + } + + m_pNaviWin->DisableNotify( false ); + EnableMenuItems( NULL ); + if ( bIsDocModified ) + m_pNaviWin->SetDocModified(); + return bHandled; + } + + //------------------------------------------------------------------------ + SvLBoxEntry* XFormsPage::AddEntry( ItemNode* _pNewNode, bool _bIsElement ) + { + SvLBoxEntry* pParent = m_aItemList.FirstSelected(); + const ImageList& rImageList = m_pNaviWin->GetItemImageList(); + USHORT nImageID = ( _bIsElement ) ? IID_ELEMENT : IID_ATTRIBUTE; + Image aImage = rImageList.GetImage( nImageID ); + ::rtl::OUString sName; + try + { + sName = m_xUIHelper->getNodeDisplayName( + _pNewNode->m_xNode, m_pNaviWin->IsShowDetails() ); + } + catch ( Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return m_aItemList.InsertEntry( + sName, aImage, aImage, pParent, FALSE, LIST_APPEND, _pNewNode ); + } + //------------------------------------------------------------------------ + class lcl_ResourceString + { + protected: + lcl_ResourceString() + { + } + + lcl_ResourceString( const lcl_ResourceString& ); + + virtual ~lcl_ResourceString() + { + } + + // load UI resources from resource file + void init() + { + // create a resource manager, for the svx resource file + // and the UI locale + ByteString aResourceFile( "svx" ); + ResMgr* pResMgr = ResMgr::CreateResMgr( + aResourceFile.GetBuffer(), + Application::GetSettings().GetUILocale() ); + + // load the resources for the AddSubmission modal dialog. + // This will create our own resource context. + ResId aRes( RID_SVXDLG_ADD_SUBMISSION, *pResMgr ); + aRes.SetRT( RSC_MODALDIALOG ); + pResMgr->GetResource( aRes ); + + // now, we can access the local resources from the dialog's + // resource context + _initResources(pResMgr); + + // clean up: remove context, and delete the resource manager + // ( Increment(..) is needed since PopContext() requires that + // the file pointer is at the end. ) + pResMgr->Increment( pResMgr->GetRemainSize() ); + pResMgr->PopContext(); + delete pResMgr; + } + + // load resources... to be overloaded in sub-classes + virtual void _initResources( ResMgr* pMgr ) = 0; + }; + + class lcl_ReplaceString : public lcl_ResourceString + { + rtl::OUString m_sDoc_UI; + rtl::OUString m_sInstance_UI; + rtl::OUString m_sNone_UI; + + rtl::OUString m_sDoc_API; + rtl::OUString m_sInstance_API; + rtl::OUString m_sNone_API; + + lcl_ReplaceString() : + lcl_ResourceString(), + m_sDoc_API( RTL_CONSTASCII_USTRINGPARAM("all") ), + m_sInstance_API( RTL_CONSTASCII_USTRINGPARAM("instance") ), + m_sNone_API( RTL_CONSTASCII_USTRINGPARAM("none") ) + { + init(); + } + + lcl_ReplaceString( const lcl_ReplaceString& ); + + virtual ~lcl_ReplaceString() + { + } + + // load UI resources from resource file + virtual void _initResources( ResMgr * pMgr ) + { + // now, we can access the local resources from the dialog's + // resource context + m_sDoc_UI = String( ResId( STR_REPLACE_DOC, *pMgr ) ); + m_sInstance_UI = String( ResId( STR_REPLACE_INST, *pMgr ) ); + m_sNone_UI = String( ResId( STR_REPLACE_NONE, *pMgr ) ); + } + + public: + + /** create and obtain the singleton instance */ + static const lcl_ReplaceString& get() + { + // keep the singleton instance here + static lcl_ReplaceString* m_pInstance = NULL; + + if( m_pInstance == NULL ) + m_pInstance = new lcl_ReplaceString(); + return *m_pInstance; + } + + /** convert submission replace string from API value to UI value. + Use 'none' as default. */ + rtl::OUString toUI( const rtl::OUString& rStr ) const + { + if( rStr == m_sDoc_API ) + return m_sDoc_UI; + else if( rStr == m_sInstance_API ) + return m_sInstance_UI; + else + return m_sNone_UI; + } + + /** convert submission replace string from UI to API. + Use 'none' as default. */ + rtl::OUString toAPI( const rtl::OUString& rStr ) const + { + if( rStr == m_sDoc_UI ) + return m_sDoc_API; + else if( rStr == m_sInstance_UI ) + return m_sInstance_API; + else + return m_sNone_API; + } + }; + + class lcl_MethodString : public lcl_ResourceString + { + rtl::OUString m_sPost_UI; + rtl::OUString m_sPut_UI; + rtl::OUString m_sGet_UI; + + rtl::OUString m_sPost_API; + rtl::OUString m_sPut_API; + rtl::OUString m_sGet_API; + + lcl_MethodString() : + lcl_ResourceString(), + m_sPost_API( RTL_CONSTASCII_USTRINGPARAM("post") ), + m_sPut_API( RTL_CONSTASCII_USTRINGPARAM("put") ), + m_sGet_API( RTL_CONSTASCII_USTRINGPARAM("get") ) + { + init(); + } + + lcl_MethodString( const lcl_MethodString& ); + + virtual ~lcl_MethodString() + { + } + + // load UI resources from resource file + virtual void _initResources(ResMgr* pMgr) + { + m_sPost_UI = String( ResId( STR_METHOD_POST, *pMgr ) ); + m_sPut_UI = String( ResId( STR_METHOD_PUT, *pMgr ) ); + m_sGet_UI = String( ResId( STR_METHOD_GET, *pMgr ) ); + } + + public: + + /** create and obtain the singleton instance */ + static const lcl_MethodString& get() + { + // keep the singleton instance here + static lcl_MethodString* m_pInstance = NULL; + + if( m_pInstance == NULL ) + m_pInstance = new lcl_MethodString(); + return *m_pInstance; + } + + /** convert from API to UI; put is default. */ + rtl::OUString toUI( const rtl::OUString& rStr ) const + { + if( rStr == m_sGet_API ) + return m_sGet_UI; + else if( rStr == m_sPost_API ) + return m_sPost_UI; + else + return m_sPut_UI; + } + + /** convert from UI to API; put is default */ + rtl::OUString toAPI( const rtl::OUString& rStr ) const + { + if( rStr == m_sGet_UI ) + return m_sGet_API; + else if( rStr == m_sPost_UI ) + return m_sPost_API; + else + return m_sPut_API; + } + }; + + //------------------------------------------------------------------------ + SvLBoxEntry* XFormsPage::AddEntry( const Reference< XPropertySet >& _rEntry ) + { + SvLBoxEntry* pEntry = NULL; + const ImageList& rImageList = m_pNaviWin->GetItemImageList(); + Image aImage = rImageList.GetImage( IID_ELEMENT ); + + ItemNode* pNode = new ItemNode( _rEntry ); + rtl::OUString sTemp; + + if ( DGTSubmission == m_eGroup ) + { + try + { + // ID + _rEntry->getPropertyValue( PN_SUBMISSION_ID ) >>= sTemp; + pEntry = m_aItemList.InsertEntry( sTemp, aImage, aImage, NULL, FALSE, LIST_APPEND, pNode ); + // Action + _rEntry->getPropertyValue( PN_SUBMISSION_ACTION ) >>= sTemp; + String sEntry = SVX_RESSTR( RID_STR_DATANAV_SUBM_ACTION ); + sEntry += String( sTemp ); + m_aItemList.InsertEntry( sEntry, aImage, aImage, pEntry ); + // Method + _rEntry->getPropertyValue( PN_SUBMISSION_METHOD ) >>= sTemp; + sEntry = SVX_RESSTR( RID_STR_DATANAV_SUBM_METHOD ); + sEntry += String( lcl_MethodString::get().toUI( sTemp ) ); + m_aItemList.InsertEntry( sEntry, aImage, aImage, pEntry ); + // Ref + _rEntry->getPropertyValue( PN_SUBMISSION_REF ) >>= sTemp; + sEntry = SVX_RESSTR( RID_STR_DATANAV_SUBM_REF ); + sEntry += String( sTemp ); + m_aItemList.InsertEntry( sEntry, aImage, aImage, pEntry ); + // Bind + _rEntry->getPropertyValue( PN_SUBMISSION_BIND ) >>= sTemp; + sEntry = SVX_RESSTR( RID_STR_DATANAV_SUBM_BIND ); + sEntry += String( sTemp ); + m_aItemList.InsertEntry( sEntry, aImage, aImage, pEntry ); + // Replace + _rEntry->getPropertyValue( PN_SUBMISSION_REPLACE ) >>= sTemp; + sEntry = SVX_RESSTR( RID_STR_DATANAV_SUBM_REPLACE ); + sEntry += String( lcl_ReplaceString::get().toUI( sTemp ) ); + m_aItemList.InsertEntry( sEntry, aImage, aImage, pEntry ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::AddEntry(Ref): exception caught" ); + } + } + else // then Binding Page + { + try + { + String sDelim( RTL_CONSTASCII_USTRINGPARAM( ": " ) ); + ::rtl::OUString sName; + _rEntry->getPropertyValue( PN_BINDING_ID ) >>= sTemp; + sName += String( sTemp ); + sName += sDelim; + _rEntry->getPropertyValue( PN_BINDING_EXPR ) >>= sTemp; + sName += String( sTemp ); + pEntry = m_aItemList.InsertEntry( + sName, aImage, aImage, NULL, FALSE, LIST_APPEND, pNode ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::AddEntry(Ref): exception caught" ); + } + } + + return pEntry; + } + + //------------------------------------------------------------------------ + void XFormsPage::EditEntry( const Reference< XPropertySet >& _rEntry ) + { + SvLBoxEntry* pEntry = NULL; + rtl::OUString sTemp; + + if ( DGTSubmission == m_eGroup ) + { + try + { + pEntry = m_aItemList.FirstSelected(); + + // #i36262# may be called for submission entry *or* for + // submission children. If we don't have any children, we + // assume the latter case and use the parent + if( m_aItemList.GetEntry( pEntry, 0 ) == NULL ) + { + pEntry = m_aItemList.GetModel()->GetParent( pEntry ); + } + + _rEntry->getPropertyValue( PN_SUBMISSION_ID ) >>= sTemp; + m_aItemList.SetEntryText( pEntry, sTemp ); + + _rEntry->getPropertyValue( PN_SUBMISSION_BIND ) >>= sTemp; + String sEntry = SVX_RESSTR( RID_STR_DATANAV_SUBM_BIND ); + sEntry += String( sTemp ); + ULONG nPos = 0; + SvLBoxEntry* pChild = m_aItemList.GetEntry( pEntry, nPos++ ); + m_aItemList.SetEntryText( pChild, sEntry ); + _rEntry->getPropertyValue( PN_SUBMISSION_REF ) >>= sTemp; + sEntry = SVX_RESSTR( RID_STR_DATANAV_SUBM_REF ); + sEntry += String( sTemp ); + pChild = m_aItemList.GetEntry( pEntry, nPos++ ); + m_aItemList.SetEntryText( pChild, sEntry ); + _rEntry->getPropertyValue( PN_SUBMISSION_ACTION ) >>= sTemp; + sEntry = SVX_RESSTR( RID_STR_DATANAV_SUBM_ACTION ); + sEntry += String( sTemp ); + pChild = m_aItemList.GetEntry( pEntry, nPos++ ); + m_aItemList.SetEntryText( pChild, sEntry ); + _rEntry->getPropertyValue( PN_SUBMISSION_METHOD ) >>= sTemp; + sEntry = SVX_RESSTR( RID_STR_DATANAV_SUBM_METHOD ); + sEntry += String( lcl_MethodString::get().toUI( sTemp ) ); + pChild = m_aItemList.GetEntry( pEntry, nPos++ ); + m_aItemList.SetEntryText( pChild, sEntry ); + _rEntry->getPropertyValue( PN_SUBMISSION_REPLACE ) >>= sTemp; + sEntry = SVX_RESSTR( RID_STR_DATANAV_SUBM_REPLACE ); + sEntry += String( lcl_ReplaceString::get().toUI( sTemp ) ); + pChild = m_aItemList.GetEntry( pEntry, nPos++ ); + m_aItemList.SetEntryText( pChild, sEntry ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::EditEntry(): exception caught" ); + } + } + } + + //------------------------------------------------------------------------ + bool XFormsPage::RemoveEntry() + { + bool bRet = false; + SvLBoxEntry* pEntry = m_aItemList.FirstSelected(); + if ( pEntry && + ( DGTInstance != m_eGroup || m_aItemList.GetParent( pEntry ) ) ) + { + Reference< css::xforms::XModel > xModel( m_xUIHelper, UNO_QUERY ); + DBG_ASSERT( xModel.is(), "XFormsPage::RemoveEntry(): no model" ); + ItemNode* pNode = static_cast< ItemNode* >( pEntry->GetUserData() ); + DBG_ASSERT( pNode, "XFormsPage::RemoveEntry(): no node" ); + + if ( DGTInstance == m_eGroup ) + { + try + { + DBG_ASSERT( pNode->m_xNode.is(), "XFormsPage::RemoveEntry(): no XNode" ); + css::xml::dom::NodeType eChildType = pNode->m_xNode->getNodeType(); + bool bIsElement = ( eChildType == css::xml::dom::NodeType_ELEMENT_NODE ); + USHORT nResId = bIsElement ? RID_QRY_REMOVE_ELEMENT : RID_QRY_REMOVE_ATTRIBUTE; + String sVar = bIsElement ? ELEMENTNAME : ATTRIBUTENAME; + QueryBox aQBox( this, SVX_RES( nResId ) ); + String sMessText = aQBox.GetMessText(); + sMessText.SearchAndReplace( + sVar, m_xUIHelper->getNodeDisplayName( pNode->m_xNode, sal_False ) ); + aQBox.SetMessText( sMessText ); + if ( aQBox.Execute() == RET_YES ) + { + SvLBoxEntry* pParent = m_aItemList.GetParent( pEntry ); + DBG_ASSERT( pParent, "XFormsPage::RemoveEntry(): no parent entry" ); + ItemNode* pParentNode = static_cast< ItemNode* >( pParent->GetUserData() ); + DBG_ASSERT( pParentNode && pParentNode->m_xNode.is(), "XFormsPage::RemoveEntry(): no parent XNode" ); + + Reference< css::xml::dom::XNode > xPNode; + Reference< css::xml::dom::XNode > xNode = + pParentNode->m_xNode->removeChild( pNode->m_xNode ); + if ( xNode.is() ) + xPNode = xNode->getParentNode(); + DBG_ASSERT( !xPNode.is(), "XFormsPage::RemoveEntry(): node not removed" ); + bRet = true; + } + } + catch ( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::RemoveEntry(): exception caught" ); + } + } + else + { + DBG_ASSERT( pNode->m_xPropSet.is(), "XFormsPage::RemoveEntry(): no propset" ); + bool bSubmission = ( DGTSubmission == m_eGroup ); + USHORT nResId = bSubmission ? RID_QRY_REMOVE_SUBMISSION : RID_QRY_REMOVE_BINDING; + rtl::OUString sProperty = bSubmission ? PN_SUBMISSION_ID : PN_BINDING_ID; + String sSearch = bSubmission ? SUBMISSIONNAME : BINDINGNAME; + rtl::OUString sName; + try + { + pNode->m_xPropSet->getPropertyValue( sProperty ) >>= sName; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::RemoveEntry(): exception caught" ); + } + QueryBox aQBox( this, SVX_RES( nResId ) ); + String sMessText = aQBox.GetMessText(); + sMessText.SearchAndReplace( sSearch, String( sName ) ); + aQBox.SetMessText( sMessText ); + if ( aQBox.Execute() == RET_YES ) + { + try + { + if ( bSubmission ) + xModel->getSubmissions()->remove( makeAny( pNode->m_xPropSet ) ); + else // then Binding Page + xModel->getBindings()->remove( makeAny( pNode->m_xPropSet ) ); + bRet = true; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::RemoveEntry(): exception caught" ); + } + } + } + + if ( bRet ) + m_aItemList.RemoveEntry( pEntry ); + } + + return bRet; + } + + //------------------------------------------------------------------------ + long XFormsPage::Notify( NotifyEvent& rNEvt ) + { + long nHandled = 0; + + if ( rNEvt.GetType() == EVENT_KEYINPUT ) + { + USHORT nCode = rNEvt.GetKeyEvent()->GetKeyCode().GetCode(); + + switch ( nCode ) + { + case KEY_DELETE: + nHandled = DoMenuAction( TBI_ITEM_REMOVE ); + break; + } + } + + return nHandled ? nHandled : Window::Notify( rNEvt ); + } + //------------------------------------------------------------------------ + void XFormsPage::Resize() + { + Size aSize = GetOutputSizePixel(); + Size aTbxSize = m_aToolBox.GetSizePixel(); + aTbxSize.Width() = aSize.Width(); + m_aToolBox.SetSizePixel( aTbxSize ); + aSize.Width() -= 4; + aSize.Height() -= ( 4 + aTbxSize.Height() ); + m_aItemList.SetPosSizePixel( Point( 2, 2 + aTbxSize.Height() ), aSize ); + } + //------------------------------------------------------------------------ + String XFormsPage::SetModel( const Reference< css::xforms::XModel >& _xModel, USHORT _nPagePos ) + { + DBG_ASSERT( _xModel.is(), "XFormsPage::SetModel(): invalid model" ); + + m_xUIHelper = Reference< css::xforms::XFormsUIHelper1 >( _xModel, UNO_QUERY ); + String sRet; + m_bHasModel = true; + const ImageList& rImageList = m_pNaviWin->GetItemImageList(); + + switch ( m_eGroup ) + { + case DGTInstance : + { + DBG_ASSERT( _nPagePos != TAB_PAGE_NOTFOUND, "XFormsPage::SetModel(): invalid page position" ); + try + { + Reference< XContainer > xContainer( _xModel->getInstances(), UNO_QUERY ); + if ( xContainer.is() ) + m_pNaviWin->AddContainerBroadcaster( xContainer ); + + Reference< XEnumerationAccess > xNumAccess( _xModel->getInstances(), UNO_QUERY ); + if ( xNumAccess.is() ) + { + Reference < XEnumeration > xNum = xNumAccess->createEnumeration(); + if ( xNum.is() && xNum->hasMoreElements() ) + { + USHORT nIter = 0; + while ( xNum->hasMoreElements() ) + { + if ( nIter == _nPagePos ) + { + Sequence< PropertyValue > xPropSeq; + Any aAny = xNum->nextElement(); + if ( aAny >>= xPropSeq ) + sRet = LoadInstance( xPropSeq, rImageList ); + else + { + DBG_ERRORFILE( "XFormsPage::SetModel(): invalid instance" ); + } + break; + } + else + { + xNum->nextElement(); + nIter++; + } + } + } + } + } + catch( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::SetModel(): exception caught" ); + } + break; + } + + case DGTSubmission : + { + DBG_ASSERT( TAB_PAGE_NOTFOUND == _nPagePos, "XFormsPage::SetModel(): invalid page position" ); + try + { + Reference< XContainer > xContainer( _xModel->getSubmissions(), UNO_QUERY ); + if ( xContainer.is() ) + m_pNaviWin->AddContainerBroadcaster( xContainer ); + + Reference< XEnumerationAccess > xNumAccess( _xModel->getSubmissions(), UNO_QUERY ); + if ( xNumAccess.is() ) + { + Reference < XEnumeration > xNum = xNumAccess->createEnumeration(); + if ( xNum.is() && xNum->hasMoreElements() ) + { + while ( xNum->hasMoreElements() ) + { + Reference< XPropertySet > xPropSet; + Any aAny = xNum->nextElement(); + if ( aAny >>= xPropSet ) + AddEntry( xPropSet ); + } + } + } + } + catch( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::SetModel(): exception caught" ); + } + break; + } + + case DGTBinding : + { + DBG_ASSERT( TAB_PAGE_NOTFOUND == _nPagePos, "XFormsPage::SetModel(): invalid page position" ); + try + { + Reference< XContainer > xContainer( _xModel->getBindings(), UNO_QUERY ); + if ( xContainer.is() ) + m_pNaviWin->AddContainerBroadcaster( xContainer ); + + Reference< XEnumerationAccess > xNumAccess( _xModel->getBindings(), UNO_QUERY ); + if ( xNumAccess.is() ) + { + Reference < XEnumeration > xNum = xNumAccess->createEnumeration(); + if ( xNum.is() && xNum->hasMoreElements() ) + { + Image aImage1 = rImageList.GetImage( IID_ELEMENT ); + Image aImage2 = rImageList.GetImage( IID_ELEMENT ); + String sDelim( RTL_CONSTASCII_USTRINGPARAM( ": " ) ); + while ( xNum->hasMoreElements() ) + { + Reference< XPropertySet > xPropSet; + Any aAny = xNum->nextElement(); + if ( aAny >>= xPropSet ) + { + String sEntry; + rtl::OUString sTemp; + xPropSet->getPropertyValue( PN_BINDING_ID ) >>= sTemp; + sEntry += String( sTemp ); + sEntry += sDelim; + xPropSet->getPropertyValue( PN_BINDING_EXPR ) >>= sTemp; + sEntry += String( sTemp ); + + ItemNode* pNode = new ItemNode( xPropSet ); + m_aItemList.InsertEntry( + sEntry, aImage1, aImage2, NULL, FALSE, LIST_APPEND, pNode ); + } + } + } + } + } + catch( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::SetModel(): exception caught" ); + } + break; + } + default: + DBG_ERROR( "XFormsPage::SetModel: unknown group!" ); + break; + } + + EnableMenuItems( NULL ); + + return sRet; + } + //------------------------------------------------------------------------ + void XFormsPage::ClearModel() + { + m_bHasModel = false; + m_aItemList.DeleteAndClear(); + } + //------------------------------------------------------------------------ + String XFormsPage::LoadInstance( + const Sequence< PropertyValue >& _xPropSeq, const ImageList& _rImgLst ) + { + String sRet; + rtl::OUString sTemp; + rtl::OUString sInstModel = PN_INSTANCE_MODEL; + rtl::OUString sInstName = PN_INSTANCE_ID; + rtl::OUString sInstURL = PN_INSTANCE_URL; + const PropertyValue* pProps = _xPropSeq.getConstArray(); + const PropertyValue* pPropsEnd = pProps + _xPropSeq.getLength(); + for ( ; pProps != pPropsEnd; ++pProps ) + { + if ( sInstModel.compareTo( pProps->Name ) == 0 ) + { + Reference< css::xml::dom::XNode > xRoot; + if ( pProps->Value >>= xRoot ) + { + try + { + Reference< XEventTarget > xTarget( xRoot, UNO_QUERY ); + if ( xTarget.is() ) + m_pNaviWin->AddEventBroadcaster( xTarget ); + + #if OSL_DEBUG_LEVEL > 0 + css::xml::dom::NodeType eNodeType = xRoot->getNodeType(); (void)eNodeType; + #endif + ::rtl::OUString sNodeName = + m_xUIHelper->getNodeDisplayName( xRoot, m_pNaviWin->IsShowDetails() ); + if ( sNodeName.getLength() == 0 ) + sNodeName = xRoot->getNodeName(); + if ( xRoot->hasChildNodes() ) + AddChildren( NULL, _rImgLst, xRoot ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::LoadInstance(): exception caught" ); + } + } + } + else if ( sInstName.compareTo( pProps->Name ) == 0 && ( pProps->Value >>= sTemp ) ) + m_sInstanceName = sRet = sTemp; + else if ( sInstURL.compareTo( pProps->Name ) == 0 && ( pProps->Value >>= sTemp ) ) + m_sInstanceURL = sTemp; + } + + return sRet; + } + + //------------------------------------------------------------------------ + bool XFormsPage::DoMenuAction( USHORT _nMenuID ) + { + return DoToolBoxAction( _nMenuID ); + } + + //------------------------------------------------------------------------ + void XFormsPage::EnableMenuItems( Menu* _pMenu ) + { + BOOL bEnableAdd = FALSE; + BOOL bEnableEdit = FALSE; + BOOL bEnableRemove = FALSE; + + SvLBoxEntry* pEntry = m_aItemList.FirstSelected(); + if ( pEntry ) + { + bEnableAdd = TRUE; + bool bSubmitChild = false; + if ( DGTSubmission == m_eGroup && m_aItemList.GetParent( pEntry ) ) + { + pEntry = m_aItemList.GetParent( pEntry ); + bSubmitChild = true; + } + ItemNode* pNode = static_cast< ItemNode* >( pEntry->GetUserData() ); + if ( pNode && ( pNode->m_xNode.is() || pNode->m_xPropSet.is() ) ) + { + bEnableEdit = TRUE; + bEnableRemove = ( bSubmitChild != true ); + if ( DGTInstance == m_eGroup && !m_aItemList.GetParent( pEntry ) ) + bEnableRemove = FALSE; + if ( pNode->m_xNode.is() ) + { + try + { + css::xml::dom::NodeType eChildType = pNode->m_xNode->getNodeType(); + if ( eChildType != css::xml::dom::NodeType_ELEMENT_NODE + && eChildType != css::xml::dom::NodeType_DOCUMENT_NODE ) + { + bEnableAdd = FALSE; + } + } + catch ( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::EnableMenuItems(): exception caught" ); + } + } + } + } + else if ( m_eGroup != DGTInstance ) + bEnableAdd = TRUE; + + m_aToolBox.EnableItem( TBI_ITEM_ADD, bEnableAdd ); + m_aToolBox.EnableItem( TBI_ITEM_ADD_ELEMENT, bEnableAdd ); + m_aToolBox.EnableItem( TBI_ITEM_ADD_ATTRIBUTE, bEnableAdd ); + m_aToolBox.EnableItem( TBI_ITEM_EDIT, bEnableEdit ); + m_aToolBox.EnableItem( TBI_ITEM_REMOVE, bEnableRemove ); + + if ( _pMenu ) + { + _pMenu->EnableItem( TBI_ITEM_ADD, bEnableAdd ); + _pMenu->EnableItem( TBI_ITEM_ADD_ELEMENT, bEnableAdd ); + _pMenu->EnableItem( TBI_ITEM_ADD_ATTRIBUTE, bEnableAdd ); + _pMenu->EnableItem( TBI_ITEM_EDIT, bEnableEdit ); + _pMenu->EnableItem( TBI_ITEM_REMOVE, bEnableRemove ); + } + if ( DGTInstance == m_eGroup ) + { + USHORT nResId1 = RID_STR_DATANAV_EDIT_ELEMENT; + USHORT nResId2 = RID_STR_DATANAV_REMOVE_ELEMENT; + if ( pEntry ) + { + ItemNode* pNode = static_cast< ItemNode* >( pEntry->GetUserData() ); + if ( pNode && pNode->m_xNode.is() ) + { + try + { + css::xml::dom::NodeType eChildType = pNode->m_xNode->getNodeType(); + if ( eChildType == css::xml::dom::NodeType_ATTRIBUTE_NODE ) + { + nResId1 = RID_STR_DATANAV_EDIT_ATTRIBUTE; + nResId2 = RID_STR_DATANAV_REMOVE_ATTRIBUTE; + } + } + catch ( Exception& ) + { + DBG_ERRORFILE( "XFormsPage::EnableMenuItems(): exception caught" ); + } + } + } + m_aToolBox.SetItemText( TBI_ITEM_EDIT, SVX_RESSTR( nResId1 ) ); + m_aToolBox.SetItemText( TBI_ITEM_REMOVE, SVX_RESSTR( nResId2 ) ); + if ( _pMenu ) + { + _pMenu->SetItemText( TBI_ITEM_EDIT, SVX_RESSTR( nResId1 ) ); + _pMenu->SetItemText( TBI_ITEM_REMOVE, SVX_RESSTR( nResId2 ) ); + } + } + } + + + //======================================================================== + // class DataNavigatorWindow + //======================================================================== + DataNavigatorWindow::DataNavigatorWindow( Window* pParent, SfxBindings* pBindings ) : + + Window( pParent, SVX_RES( RID_SVXWIN_DATANAVIGATOR ) ), + + m_aModelsBox ( this, SVX_RES( LB_MODELS ) ), + m_aModelBtn ( this, SVX_RES( MB_MODELS ) ), + m_aTabCtrl ( this, SVX_RES( TC_ITEMS ) ), + m_aInstanceBtn ( this, SVX_RES( MB_INSTANCES ) ), + + m_pInstPage ( NULL ), + m_pSubmissionPage ( NULL ), + m_pBindingPage ( NULL ), + + m_nMinWidth ( 0 ), + m_nMinHeight ( 0 ), + m_nBorderHeight ( 0 ), + m_nLastSelectedPos ( LISTBOX_ENTRY_NOTFOUND ), + m_bShowDetails ( false ), + m_bIsNotifyDisabled ( false ), + + m_aItemImageList ( SVX_RES( IL_ITEM_BMPS ) ), + m_xDataListener ( new DataListener( this ) ) + + { + FreeResource(); + + // init minimal metric + m_a2Size = LogicToPixel( Size( 2, 2 ), MAP_APPFONT ); + m_a3Size = LogicToPixel( Size( 3, 3 ), MAP_APPFONT ); + Size aOutSz = GetOutputSizePixel(); + Size aLogSize = PixelToLogic( aOutSz, MAP_APPFONT ); + m_nMinWidth = aLogSize.Width(); + m_nMinHeight = aLogSize.Height(); + m_nBorderHeight = 4*m_a3Size.Height() + + m_aModelBtn.GetSizePixel().Height() + m_aInstanceBtn.GetSizePixel().Height(); + + // handler + m_aModelsBox.SetSelectHdl( LINK( this, DataNavigatorWindow, ModelSelectHdl ) ); + Link aLink = LINK( this, DataNavigatorWindow, MenuSelectHdl ); + m_aModelBtn.SetSelectHdl( aLink ); + m_aInstanceBtn.SetSelectHdl( aLink ); + aLink = LINK( this, DataNavigatorWindow, MenuActivateHdl ); + m_aModelBtn.SetActivateHdl( aLink ); + m_aInstanceBtn.SetActivateHdl( aLink ); + m_aTabCtrl.SetActivatePageHdl( LINK( this, DataNavigatorWindow, ActivatePageHdl ) ); + m_aUpdateTimer.SetTimeout( 2000 ); + m_aUpdateTimer.SetTimeoutHdl( LINK( this, DataNavigatorWindow, UpdateHdl ) ); + + // init tabcontrol + m_aTabCtrl.Show(); + sal_Int32 nPageId = TID_INSTANCE; + SvtViewOptions aViewOpt( E_TABDIALOG, CFGNAME_DATANAVIGATOR ); + if ( aViewOpt.Exists() ) + { + nPageId = aViewOpt.GetPageID(); + aViewOpt.GetUserItem(CFGNAME_SHOWDETAILS) >>= m_bShowDetails; + } + + Menu* pMenu = m_aInstanceBtn.GetPopupMenu(); + pMenu->SetItemBits( MID_SHOW_DETAILS, MIB_CHECKABLE ); + pMenu->CheckItem( MID_SHOW_DETAILS, m_bShowDetails ); + + m_aTabCtrl.SetCurPageId( static_cast< USHORT >( nPageId ) ); + ActivatePageHdl( &m_aTabCtrl ); + + // get our frame + DBG_ASSERT( pBindings != NULL, + "DataNavigatorWindow::LoadModels(): no SfxBindings; can't get frame" ); + m_xFrame = Reference<XFrame>( + pBindings->GetDispatcher()->GetFrame()->GetFrame().GetFrameInterface(), + UNO_QUERY ); + DBG_ASSERT( m_xFrame.is(), "DataNavigatorWindow::LoadModels(): no frame" ); + // add frameaction listener + Reference< XFrameActionListener > xListener( + static_cast< XFrameActionListener* >( m_xDataListener.get() ), UNO_QUERY ); + m_xFrame->addFrameActionListener( xListener ); + + // load xforms models of the current document + LoadModels(); + } + //------------------------------------------------------------------------ + DataNavigatorWindow::~DataNavigatorWindow() + { + SvtViewOptions aViewOpt( E_TABDIALOG, CFGNAME_DATANAVIGATOR ); + aViewOpt.SetPageID( static_cast< sal_Int32 >( m_aTabCtrl.GetCurPageId() ) ); + Any aAny; + aAny <<= m_bShowDetails; + aViewOpt.SetUserItem(CFGNAME_SHOWDETAILS,aAny); + + delete m_pInstPage; + delete m_pSubmissionPage; + delete m_pBindingPage; + + sal_Int32 i, nCount = m_aPageList.size(); + for ( i = 0; i < nCount; ++i ) + delete m_aPageList[i]; + Reference< XFrameActionListener > xListener( + static_cast< XFrameActionListener* >( m_xDataListener.get() ), UNO_QUERY ); + m_xFrame->removeFrameActionListener( xListener ); + RemoveBroadcaster(); + m_xDataListener.clear(); + } + + // ----------------------------------------------------------------------- + IMPL_LINK( DataNavigatorWindow, ModelSelectHdl, ListBox *, pBox ) + { + USHORT nPos = m_aModelsBox.GetSelectEntryPos(); + // pBox == NULL, if you want to force a new fill. + if ( nPos != m_nLastSelectedPos || !pBox ) + { + m_nLastSelectedPos = nPos; + ClearAllPageModels( pBox != NULL ); + InitPages(); + SetPageModel(); + } + + return 0; + } + // ----------------------------------------------------------------------- + IMPL_LINK( DataNavigatorWindow, MenuSelectHdl, MenuButton *, pBtn ) + { + bool bIsDocModified = false; + Reference< css::xforms::XFormsUIHelper1 > xUIHelper; + USHORT nSelectedPos = m_aModelsBox.GetSelectEntryPos(); + ::rtl::OUString sSelectedModel( m_aModelsBox.GetEntry( nSelectedPos ) ); + Reference< css::xforms::XModel > xModel; + try + { + Any aAny = m_xDataContainer->getByName( sSelectedModel ); + if ( aAny >>= xModel ) + xUIHelper = Reference< css::xforms::XFormsUIHelper1 >( xModel, UNO_QUERY ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "DataNavigatorWindow::MenuSelectHdl(): exception caught" ); + } + DBG_ASSERT( xUIHelper.is(), "DataNavigatorWindow::MenuSelectHdl(): no UIHelper" ); + + m_bIsNotifyDisabled = true; + + if ( &m_aModelBtn == pBtn ) + { + switch ( pBtn->GetCurItemId() ) + { + case MID_MODELS_ADD : + { + AddModelDialog aDlg( this, false ); + bool bShowDialog = true; + while ( bShowDialog ) + { + bShowDialog = false; + if ( aDlg.Execute() == RET_OK ) + { + String sNewName = aDlg.GetName(); + sal_Bool bDocumentData = aDlg.GetModifyDoc(); + + if ( m_aModelsBox.GetEntryPos( sNewName ) != LISTBOX_ENTRY_NOTFOUND ) + { + // error: model name already exists + ErrorBox aErrBox( this, SVX_RES( RID_ERR_DOUBLE_MODELNAME ) ); + String sMessText = aErrBox.GetMessText(); + sMessText.SearchAndReplace( MSG_VARIABLE, sNewName ); + aErrBox.SetMessText( sMessText ); + aErrBox.Execute(); + bShowDialog = true; + } + else + { + try + { + // add new model to frame model + Reference< css::xforms::XModel > xNewModel( + xUIHelper->newModel( m_xFrameModel, sNewName ), UNO_SET_THROW ); + + Reference< XPropertySet > xModelProps( xNewModel, UNO_QUERY_THROW ); + xModelProps->setPropertyValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ExternalData" ) ), + makeAny( sal_Bool( !bDocumentData ) ) ); + + USHORT nNewPos = m_aModelsBox.InsertEntry( sNewName ); + m_aModelsBox.SelectEntryPos( nNewPos ); + ModelSelectHdl( &m_aModelsBox ); + bIsDocModified = true; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "DataNavigatorWindow::MenuSelectHdl(): exception caught" ); + } + } + } + } + break; + } + case MID_MODELS_EDIT : + { + AddModelDialog aDlg( this, true ); + aDlg.SetName( sSelectedModel ); + + bool bDocumentData( false ); + try + { + Reference< css::xforms::XFormsSupplier > xFormsSupp( m_xFrameModel, UNO_QUERY_THROW ); + Reference< XNameContainer > xXForms( xFormsSupp->getXForms(), UNO_SET_THROW ); + Reference< XPropertySet > xModelProps( xXForms->getByName( sSelectedModel ), UNO_QUERY_THROW ); + sal_Bool bExternalData = sal_False; + OSL_VERIFY( xModelProps->getPropertyValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ExternalData" ) ) ) >>= bExternalData ); + bDocumentData = ( bExternalData == sal_False ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + aDlg.SetModifyDoc( bDocumentData ); + + if ( aDlg.Execute() == RET_OK ) + { + if ( aDlg.GetModifyDoc() != bool( bDocumentData ) ) + { + bDocumentData = aDlg.GetModifyDoc(); + try + { + Reference< css::xforms::XFormsSupplier > xFormsSupp( m_xFrameModel, UNO_QUERY_THROW ); + Reference< XNameContainer > xXForms( xFormsSupp->getXForms(), UNO_SET_THROW ); + Reference< XPropertySet > xModelProps( xXForms->getByName( sSelectedModel ), UNO_QUERY_THROW ); + xModelProps->setPropertyValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ExternalData" ) ), + makeAny( sal_Bool( !bDocumentData ) ) ); + bIsDocModified = true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + String sNewName = aDlg.GetName(); + if ( sNewName.Len() > 0 && ( sNewName != String( sSelectedModel ) ) ) + { + try + { + xUIHelper->renameModel( m_xFrameModel, sSelectedModel, sNewName ); + + m_aModelsBox.RemoveEntry( nSelectedPos ); + nSelectedPos = m_aModelsBox.InsertEntry( sNewName ); + m_aModelsBox.SelectEntryPos( nSelectedPos ); + bIsDocModified = true; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "DataNavigatorWindow::MenuSelectHdl(): exception caught" ); + } + } + } + break; + } + case MID_MODELS_REMOVE : + { + QueryBox aQBox( this, SVX_RES( RID_QRY_REMOVE_MODEL ) ); + String sText = aQBox.GetMessText(); + sText.SearchAndReplace( MODELNAME, sSelectedModel ); + aQBox.SetMessText( sText ); + if ( aQBox.Execute() == RET_YES ) + { + try + { + xUIHelper->removeModel( m_xFrameModel, sSelectedModel ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "DataNavigatorWindow::MenuSelectHdl(): exception caught" ); + } + m_aModelsBox.RemoveEntry( nSelectedPos ); + if ( m_aModelsBox.GetEntryCount() <= nSelectedPos ) + nSelectedPos = m_aModelsBox.GetEntryCount() - 1; + m_aModelsBox.SelectEntryPos( nSelectedPos ); + ModelSelectHdl( &m_aModelsBox ); + bIsDocModified = true; + } + break; + } + default: + { + DBG_ERRORFILE( "DataNavigatorWindow::MenuSelectHdl(): wrong menu item" ); + } + } + } + else if ( &m_aInstanceBtn == pBtn ) + { + switch ( pBtn->GetCurItemId() ) + { + case MID_INSTANCES_ADD : + { + AddInstanceDialog aDlg( this, false ); + if ( aDlg.Execute() == RET_OK ) + { + USHORT nInst = GetNewPageId(); + ::rtl::OUString sName = aDlg.GetName(); + ::rtl::OUString sURL = aDlg.GetURL(); + bool bLinkOnce = aDlg.IsLinkInstance(); + try + { + Reference< css::xml::dom::XDocument > xNewInst = + xUIHelper->newInstance( sName, sURL, !bLinkOnce ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "DataNavigatorWindow::MenuSelectHdl(): exception caught" ); + } + ModelSelectHdl( NULL ); + m_aTabCtrl.SetCurPageId( nInst ); + XFormsPage* pPage = GetCurrentPage( nInst ); + pPage->SetInstanceName(sName); + pPage->SetInstanceURL(sURL); + pPage->SetLinkOnce(bLinkOnce); + ActivatePageHdl( &m_aTabCtrl ); + bIsDocModified = true; + } + break; + } + case MID_INSTANCES_EDIT : + { + USHORT nId = 0; + XFormsPage* pPage = GetCurrentPage( nId ); + if ( pPage ) + { + AddInstanceDialog aDlg( this, true ); + aDlg.SetName( pPage->GetInstanceName() ); + aDlg.SetURL( pPage->GetInstanceURL() ); + aDlg.SetLinkInstance( pPage->GetLinkOnce() ); + String sOldName = aDlg.GetName(); + if ( aDlg.Execute() == RET_OK ) + { + String sNewName = aDlg.GetName(); + ::rtl::OUString sURL = aDlg.GetURL(); + bool bLinkOnce = aDlg.IsLinkInstance(); + try + { + xUIHelper->renameInstance( sOldName, + sNewName, + sURL, + !bLinkOnce ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "DataNavigatorWindow::MenuSelectHdl(): exception caught" ); + } + pPage->SetInstanceName(sNewName); + pPage->SetInstanceURL(sURL); + pPage->SetLinkOnce(bLinkOnce); + m_aTabCtrl.SetPageText( nId, sNewName ); + bIsDocModified = true; + } + delete(pPage); + } + break; + } + case MID_INSTANCES_REMOVE : + { + USHORT nId = 0; + XFormsPage* pPage = GetCurrentPage( nId ); + if ( pPage ) + { + String sInstName = pPage->GetInstanceName(); + QueryBox aQBox( this, SVX_RES( RID_QRY_REMOVE_INSTANCE ) ); + String sMessText = aQBox.GetMessText(); + sMessText.SearchAndReplace( INSTANCENAME, sInstName ); + aQBox.SetMessText( sMessText ); + if ( aQBox.Execute() == RET_YES ) + { + bool bDoRemove = false; + if ( nId > TID_INSTANCE ) + { + PageList::iterator aPageListEnd = m_aPageList.end(); + PageList::iterator aFoundPage = + std::find( m_aPageList.begin(), aPageListEnd, pPage ); + if ( aFoundPage != aPageListEnd ) + { + m_aPageList.erase( aFoundPage ); + delete pPage; + bDoRemove = true; + } + } + else + { + DELETEZ( m_pInstPage ); + bDoRemove = true; + } + + if ( bDoRemove ) + { + try + { + xUIHelper->removeInstance( sInstName ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "DataNavigatorWindow::MenuSelectHdl(): exception caught" ); + } + m_aTabCtrl.RemovePage( nId ); + m_aTabCtrl.SetCurPageId( TID_INSTANCE ); + ModelSelectHdl( NULL ); + bIsDocModified = true; + } + } + } + break; + } + case MID_SHOW_DETAILS : + { + m_bShowDetails = !m_bShowDetails; + m_aInstanceBtn.GetPopupMenu()->CheckItem( MID_SHOW_DETAILS, m_bShowDetails ); + ModelSelectHdl( &m_aModelsBox ); + break; + } + default: + { + DBG_ERRORFILE( "DataNavigatorWindow::MenuSelectHdl(): wrong menu item" ); + } + } + } + else + { + DBG_ERRORFILE( "DataNavigatorWindow::MenuSelectHdl(): wrong button" ); + } + + m_bIsNotifyDisabled = false; + + if ( bIsDocModified ) + SetDocModified(); + return 0; + } + // ----------------------------------------------------------------------- + IMPL_LINK( DataNavigatorWindow, MenuActivateHdl, MenuButton *, pBtn ) + { + Menu* pMenu = pBtn->GetPopupMenu(); + + if ( &m_aInstanceBtn == pBtn ) + { + bool bIsInstPage = ( m_aTabCtrl.GetCurPageId() >= TID_INSTANCE ); + pMenu->EnableItem( MID_INSTANCES_EDIT, bIsInstPage ); + pMenu->EnableItem( MID_INSTANCES_REMOVE, + bIsInstPage && m_aTabCtrl.GetPageCount() > MIN_PAGE_COUNT ); + pMenu->EnableItem( MID_SHOW_DETAILS, bIsInstPage ); + } + else if ( &m_aModelBtn == pBtn ) + { + // we need at least one model! + pMenu->EnableItem( MID_MODELS_REMOVE, m_aModelsBox.GetEntryCount() > 1 ); + } + else + { + DBG_ERRORFILE( "DataNavigatorWindow::MenuActivateHdl(): wrong button" ); + } + return 0; + } + // ----------------------------------------------------------------------- + IMPL_LINK( DataNavigatorWindow, ActivatePageHdl, TabControl *, EMPTYARG ) + { + USHORT nId = 0; + XFormsPage* pPage = GetCurrentPage( nId ); + if ( pPage ) + { + m_aTabCtrl.SetTabPage( nId, pPage ); + if ( m_xDataContainer.is() && !pPage->HasModel() ) + SetPageModel(); + } + + return 0; + } + // ----------------------------------------------------------------------- + IMPL_LINK( DataNavigatorWindow, UpdateHdl, Timer *, EMPTYARG ) + { + ModelSelectHdl( NULL ); + return 0; + } + // ----------------------------------------------------------------------- + XFormsPage* DataNavigatorWindow::GetCurrentPage( USHORT& rCurId ) + { + rCurId = m_aTabCtrl.GetCurPageId(); + XFormsPage* pPage = NULL; + switch ( rCurId ) + { + case TID_SUBMISSION: + { + if ( !m_pSubmissionPage ) + m_pSubmissionPage = new XFormsPage( &m_aTabCtrl, this, DGTSubmission ); + pPage = m_pSubmissionPage; + break; + } + + case TID_BINDINGS: + { + if ( !m_pBindingPage ) + m_pBindingPage = new XFormsPage( &m_aTabCtrl, this, DGTBinding ); + pPage = m_pBindingPage; + break; + } + + case TID_INSTANCE: + { + if ( !m_pInstPage ) + m_pInstPage = new XFormsPage( &m_aTabCtrl, this, DGTInstance ); + pPage = m_pInstPage; + break; + } + } + + if ( rCurId > TID_INSTANCE ) + { + USHORT nPos = m_aTabCtrl.GetPagePos( rCurId ); + if ( HasFirstInstancePage() && nPos > 0 ) + nPos--; + if ( m_aPageList.size() > nPos ) + pPage = m_aPageList[nPos]; + else + { + pPage = new XFormsPage( &m_aTabCtrl, this, DGTInstance ); + m_aPageList.push_back( pPage ); + } + } + + return pPage; + } + // ----------------------------------------------------------------------- + void DataNavigatorWindow::LoadModels() + { + if ( !m_xFrameModel.is() ) + { + // get model of active frame + Reference< XController > xCtrl = m_xFrame->getController(); + if ( xCtrl.is() ) + { + try + { + m_xFrameModel = xCtrl->getModel(); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "DataNavigatorWindow::LoadModels(): exception caught" ); + } + } + } + + if ( m_xFrameModel.is() ) + { + try + { + ::rtl::OUString sURL = m_xFrameModel->getURL(); + Reference< css::xforms::XFormsSupplier > xFormsSupp( m_xFrameModel, UNO_QUERY ); + if ( xFormsSupp.is() ) + { + Reference< XNameContainer > xContainer = xFormsSupp->getXForms(); + if ( xContainer.is() ) + { + m_xDataContainer = xContainer; + Sequence< ::rtl::OUString > aNameList = m_xDataContainer->getElementNames(); + sal_Int32 i, nCount = aNameList.getLength(); + ::rtl::OUString* pNames = aNameList.getArray(); + for ( i = 0; i < nCount; ++i ) + { + Any aAny = m_xDataContainer->getByName( pNames[i] ); + Reference< css::xforms::XModel > xFormsModel; + if ( aAny >>= xFormsModel ) + m_aModelsBox.InsertEntry( xFormsModel->getID() ); + } + } + } + } + catch( Exception& ) + { + DBG_ERRORFILE( "DataNavigatorWindow::LoadModels(): exception caught" ); + } + } + + if ( m_aModelsBox.GetEntryCount() > 0 ) + { + m_aModelsBox.SelectEntryPos(0); + ModelSelectHdl( &m_aModelsBox ); + } + } + // ----------------------------------------------------------------------- + void DataNavigatorWindow::SetPageModel() + { + rtl::OUString sModel( m_aModelsBox.GetSelectEntry() ); + try + { + Any aAny = m_xDataContainer->getByName( sModel ); + Reference< css::xforms::XModel > xFormsModel; + if ( aAny >>= xFormsModel ) + { + USHORT nPagePos = TAB_PAGE_NOTFOUND; + USHORT nId = 0; + XFormsPage* pPage = GetCurrentPage( nId ); + DBG_ASSERT( pPage, "DataNavigatorWindow::SetPageModel(): no page" ); + if ( nId >= TID_INSTANCE ) + // instance page + nPagePos = m_aTabCtrl.GetPagePos( nId ); + m_bIsNotifyDisabled = true; + String sText = pPage->SetModel( xFormsModel, nPagePos ); + m_bIsNotifyDisabled = false; + if ( sText.Len() > 0 ) + m_aTabCtrl.SetPageText( nId, sText ); + } + } + catch ( NoSuchElementException& ) + { + DBG_ERRORFILE( "DataNavigatorWindow::SetPageModel(): no such element" ); + } + catch( Exception& ) + { + DBG_ERRORFILE( "DataNavigatorWindow::SetPageModel(): unexpected exception" ); + } + } + // ----------------------------------------------------------------------- + void DataNavigatorWindow::InitPages() + { + rtl::OUString sModel( m_aModelsBox.GetSelectEntry() ); + try + { + Any aAny = m_xDataContainer->getByName( sModel ); + Reference< css::xforms::XModel > xModel; + if ( aAny >>= xModel ) + { + Reference< XEnumerationAccess > xNumAccess( xModel->getInstances(), UNO_QUERY ); + if ( xNumAccess.is() ) + { + Reference < XEnumeration > xNum = xNumAccess->createEnumeration(); + if ( xNum.is() && xNum->hasMoreElements() ) + { + sal_Int32 nAlreadyLoadedCount = m_aPageList.size(); + if ( !HasFirstInstancePage() && nAlreadyLoadedCount > 0 ) + nAlreadyLoadedCount--; + sal_Int32 nIdx = 0; + while ( xNum->hasMoreElements() ) + { + if ( nIdx > nAlreadyLoadedCount ) + { + Sequence< PropertyValue > xPropSeq; + if ( xNum->nextElement() >>= xPropSeq ) + CreateInstancePage( xPropSeq ); + else + { + DBG_ERRORFILE( "DataNavigator::InitPages(): invalid instance" ); + } + } + else + xNum->nextElement(); + nIdx++; + } + } + } + } + } + catch ( NoSuchElementException& ) + { + DBG_ERRORFILE( "DataNavigatorWindow::SetPageModel(): no such element" ); + } + catch( Exception& ) + { + DBG_ERRORFILE( "DataNavigatorWindow::SetPageModel(): unexpected exception" ); + } + } + // ----------------------------------------------------------------------- + void DataNavigatorWindow::ClearAllPageModels( bool bClearPages ) + { + if ( m_pInstPage ) + m_pInstPage->ClearModel(); + if ( m_pSubmissionPage ) + m_pSubmissionPage->ClearModel(); + if ( m_pBindingPage ) + m_pBindingPage->ClearModel(); + + sal_Int32 i, nCount = m_aPageList.size(); + for ( i = 0; i < nCount; ++i ) + { + XFormsPage* pPage = m_aPageList[i]; + pPage->ClearModel(); + if ( bClearPages ) + delete pPage; + } + + if ( bClearPages ) + { + m_aPageList.clear(); + while ( m_aTabCtrl.GetPageCount() > MIN_PAGE_COUNT ) + m_aTabCtrl.RemovePage( m_aTabCtrl.GetPageId( 1 ) ); + } + } + // ----------------------------------------------------------------------- + void DataNavigatorWindow::CreateInstancePage( const Sequence< PropertyValue >& _xPropSeq ) + { + rtl::OUString sInstName; + rtl::OUString sID( PN_INSTANCE_ID ); + const PropertyValue* pProps = _xPropSeq.getConstArray(); + const PropertyValue* pPropsEnd = pProps + _xPropSeq.getLength(); + for ( ; pProps != pPropsEnd; ++pProps ) + { + if ( sID.compareTo( pProps->Name ) == 0 ) + { + pProps->Value >>= sInstName; + break; + } + } + + USHORT nPageId = GetNewPageId(); + if ( sInstName.getLength() == 0 ) + { + DBG_ERRORFILE( "DataNavigatorWindow::CreateInstancePage(): instance without name" ); + String sTemp = String::CreateFromAscii( "untitled" ); + sTemp += String::CreateFromInt32( nPageId ); + sInstName = sTemp; + } + m_aTabCtrl.InsertPage( nPageId, sInstName, m_aTabCtrl.GetPageCount() - 2 ); + } + + //------------------------------------------------------------------------ + bool DataNavigatorWindow::HasFirstInstancePage() const + { + return ( m_aTabCtrl.GetPageId( 0 ) == TID_INSTANCE ); + } + + //------------------------------------------------------------------------ + USHORT DataNavigatorWindow::GetNewPageId() const + { + USHORT i, nMax = 0, nCount = m_aTabCtrl.GetPageCount(); + for ( i = 0; i < nCount; ++i ) + { + if ( nMax < m_aTabCtrl.GetPageId(i) ) + nMax = m_aTabCtrl.GetPageId(i); + } + return ( nMax + 1 ); + } + + //------------------------------------------------------------------------ + void DataNavigatorWindow::Resize() + { + Window::Resize(); + + Size aOutSz = GetOutputSizePixel(); + long nWidth = Max( aOutSz.Width(), m_nMinWidth ); + long nHeight = Max( aOutSz.Height(), m_nMinHeight ); + + Size aSz = m_aModelsBox.GetSizePixel(); + aSz.Width() = nWidth - 3*m_a3Size.Width() - m_aModelBtn.GetSizePixel().Width(); + m_aModelsBox.SetSizePixel( aSz ); + Point aPos = m_aModelBtn.GetPosPixel(); + aPos.X() = m_aModelsBox.GetPosPixel().X() + aSz.Width() + m_a3Size.Width(); + m_aModelBtn.SetPosPixel( aPos ); + + aSz = m_aTabCtrl.GetSizePixel(); + aSz.Width() = nWidth - 2*m_a3Size.Width(); + aSz.Height() = nHeight - m_nBorderHeight; + m_aTabCtrl.SetSizePixel( aSz ); + // Instance button positioning + aPos = m_aInstanceBtn.GetPosPixel(); + // right aligned + aPos.X() = nWidth - m_aInstanceBtn.GetSizePixel().Width() - m_a3Size.Width(); + // under the tabcontrol + aPos.Y() = m_aTabCtrl.GetPosPixel().Y() + aSz.Height() + m_a3Size.Height(); + m_aInstanceBtn.SetPosPixel( aPos ); + } + + //------------------------------------------------------------------------ + void DataNavigatorWindow::SetDocModified() + { + SfxObjectShell* pCurrentDoc = SfxObjectShell::Current(); + DBG_ASSERT( pCurrentDoc, "DataNavigatorWindow::SetDocModified(): no objectshell" ); + if ( !pCurrentDoc->IsModified() && pCurrentDoc->IsEnableSetModified() ) + pCurrentDoc->SetModified(); + } + + //------------------------------------------------------------------------ + void DataNavigatorWindow::NotifyChanges( bool _bLoadAll ) + { + if ( !m_bIsNotifyDisabled ) + { + if ( _bLoadAll ) + { + // reset all members + RemoveBroadcaster(); + m_xDataContainer.clear(); + m_xFrameModel.clear(); + m_aModelsBox.Clear(); + m_nLastSelectedPos = LISTBOX_ENTRY_NOTFOUND; + // for a reload + LoadModels(); + } + else + m_aUpdateTimer.Start(); + } + } + + //------------------------------------------------------------------------ + void DataNavigatorWindow::AddContainerBroadcaster( const XContainer_ref& xContainer ) + { + Reference< XContainerListener > xListener( + static_cast< XContainerListener* >( m_xDataListener.get() ), UNO_QUERY ); + xContainer->addContainerListener( xListener ); + m_aContainerList.push_back( xContainer ); + } + + //------------------------------------------------------------------------ + void DataNavigatorWindow::AddEventBroadcaster( const XEventTarget_ref& xTarget ) + { + Reference< XEventListener > xListener( + static_cast< XEventListener* >( m_xDataListener.get() ), UNO_QUERY ); + xTarget->addEventListener( EVENTTYPE_CHARDATA, xListener, true ); + xTarget->addEventListener( EVENTTYPE_CHARDATA, xListener, false ); + xTarget->addEventListener( EVENTTYPE_ATTR, xListener, true ); + xTarget->addEventListener( EVENTTYPE_ATTR, xListener, false ); + m_aEventTargetList.push_back( xTarget ); + } + + //------------------------------------------------------------------------ + void DataNavigatorWindow::RemoveBroadcaster() + { + Reference< XContainerListener > xContainerListener( + static_cast< XContainerListener* >( m_xDataListener.get() ), UNO_QUERY ); + sal_Int32 i, nCount = m_aContainerList.size(); + for ( i = 0; i < nCount; ++i ) + m_aContainerList[i]->removeContainerListener( xContainerListener ); + Reference< XEventListener > xEventListener( + static_cast< XEventListener* >( m_xDataListener.get() ), UNO_QUERY ); + nCount = m_aEventTargetList.size(); + for ( i = 0; i < nCount; ++i ) + { + m_aEventTargetList[i]->removeEventListener( EVENTTYPE_CHARDATA, xEventListener, true ); + m_aEventTargetList[i]->removeEventListener( EVENTTYPE_CHARDATA, xEventListener, false ); + m_aEventTargetList[i]->removeEventListener( EVENTTYPE_ATTR, xEventListener, true ); + m_aEventTargetList[i]->removeEventListener( EVENTTYPE_ATTR, xEventListener, false ); + } + } + + //======================================================================== + // class DataNavigator + //======================================================================== + DBG_NAME(DataNavigator) + //------------------------------------------------------------------------ + DataNavigator::DataNavigator( SfxBindings* _pBindings, SfxChildWindow* _pMgr, Window* _pParent ) : + + SfxDockingWindow( _pBindings, _pMgr, _pParent, + WinBits(WB_STDMODELESS|WB_SIZEABLE|WB_ROLLABLE|WB_3DLOOK|WB_DOCKABLE) ), + SfxControllerItem( SID_FM_DATANAVIGATOR_CONTROL, *_pBindings ), + + m_aDataWin( this, _pBindings ) + + { + DBG_CTOR(DataNavigator,NULL); + + SetHelpId( HID_DATA_NAVIGATOR_WIN ); + SetText( SVX_RES( RID_STR_DATANAVIGATOR ) ); + + Size aSize = m_aDataWin.GetOutputSizePixel(); + Size aLogSize = PixelToLogic( aSize, MAP_APPFONT ); + SfxDockingWindow::SetFloatingSize( aLogSize ); + + m_aDataWin.Show(); + } + + //------------------------------------------------------------------------ + DataNavigator::~DataNavigator() + { + DBG_DTOR(DataNavigator,NULL); + } + + //----------------------------------------------------------------------- + void DataNavigator::Update( FmFormShell* /*pFormShell*/ ) + { + } + //----------------------------------------------------------------------- + void DataNavigator::StateChanged( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState ) + { + if ( !pState || SID_FM_DATANAVIGATOR_CONTROL != nSID ) + return; + + if ( eState >= SFX_ITEM_AVAILABLE ) + { + FmFormShell* pShell = PTR_CAST( FmFormShell,((SfxObjectItem*)pState)->GetShell() ); + Update( pShell ); + } + else + Update( NULL ); + } + + //----------------------------------------------------------------------- + void DataNavigator::GetFocus() + { + SfxDockingWindow::GetFocus(); + } + + //----------------------------------------------------------------------- + sal_Bool DataNavigator::Close() + { + Update( NULL ); + return SfxDockingWindow::Close(); + } + + //----------------------------------------------------------------------- + Size DataNavigator::CalcDockingSize( SfxChildAlignment eAlign ) + { + if ( ( eAlign == SFX_ALIGN_TOP ) || ( eAlign == SFX_ALIGN_BOTTOM ) ) + return Size(); + + return SfxDockingWindow::CalcDockingSize( eAlign ); + } + + //----------------------------------------------------------------------- + SfxChildAlignment DataNavigator::CheckAlignment( SfxChildAlignment eActAlign, SfxChildAlignment eAlign ) + { + switch ( eAlign ) + { + case SFX_ALIGN_LEFT: + case SFX_ALIGN_RIGHT: + case SFX_ALIGN_NOALIGNMENT: + return eAlign; + default: + break; + } + return eActAlign; + } + + //------------------------------------------------------------------------ + void DataNavigator::Resize() + { + SfxDockingWindow::Resize(); + + Size aLogOutputSize = PixelToLogic( GetOutputSizePixel(), MAP_APPFONT ); + Size aLogExplSize = aLogOutputSize; + aLogExplSize.Width() -= 2; + aLogExplSize.Height() -= 2; + + Point aExplPos = LogicToPixel( Point(1,1), MAP_APPFONT ); + Size aExplSize = LogicToPixel( aLogExplSize, MAP_APPFONT ); + + m_aDataWin.SetPosSizePixel( aExplPos, aExplSize ); + } + + + //======================================================================== + // class NavigatorFrameManager + //======================================================================== + + //----------------------------------------------------------------------- + SFX_IMPL_DOCKINGWINDOW( DataNavigatorManager, SID_FM_SHOW_DATANAVIGATOR ) + + //----------------------------------------------------------------------- + DataNavigatorManager::DataNavigatorManager( + Window* _pParent, sal_uInt16 _nId, SfxBindings* _pBindings, SfxChildWinInfo* _pInfo ) : + + SfxChildWindow( _pParent, _nId ) + + { + pWindow = new DataNavigator( _pBindings, this, _pParent ); + eChildAlignment = SFX_ALIGN_RIGHT; + pWindow->SetSizePixel( Size( 250, 400 ) ); + ( (SfxDockingWindow*)pWindow )->Initialize( _pInfo ); + } + + //======================================================================== + // class AddDataItemDialog + //======================================================================== + + AddDataItemDialog::AddDataItemDialog( + Window* pParent, ItemNode* _pNode, + const Reference< css::xforms::XFormsUIHelper1 >& _rUIHelper ) : + + ModalDialog( pParent, SVX_RES( RID_SVXDLG_ADD_DATAITEM ) ), + + m_aItemFL ( this, SVX_RES( FL_ITEM ) ), + m_aNameFT ( this, SVX_RES( FT_NAME ) ), + m_aNameED ( this, SVX_RES( ED_NAME ) ), + m_aDefaultFT ( this, SVX_RES( FT_DEFAULT ) ), + m_aDefaultED ( this, SVX_RES( ED_DEFAULT ) ), + m_aDefaultBtn ( this, SVX_RES( PB_DEFAULT ) ), + m_aSettingsFL ( this, SVX_RES( FL_SETTINGS ) ), + m_aDataTypeFT ( this, SVX_RES( FT_DATATYPE ) ), + m_aDataTypeLB ( this, SVX_RES( LB_DATATYPE ) ), + m_aRequiredCB ( this, SVX_RES( CB_REQUIRED ) ), + m_aRequiredBtn ( this, SVX_RES( PB_REQUIRED ) ), + m_aRelevantCB ( this, SVX_RES( CB_RELEVANT ) ), + m_aRelevantBtn ( this, SVX_RES( PB_RELEVANT ) ), + m_aConstraintCB ( this, SVX_RES( CB_CONSTRAINT ) ), + m_aConstraintBtn( this, SVX_RES( PB_CONSTRAINT ) ), + m_aReadonlyCB ( this, SVX_RES( CB_READONLY ) ), + m_aReadonlyBtn ( this, SVX_RES( PB_READONLY ) ), + m_aCalculateCB ( this, SVX_RES( CB_CALCULATE ) ), + m_aCalculateBtn ( this, SVX_RES( PB_CALCULATE ) ), + m_aButtonsFL ( this, SVX_RES( FL_DATANAV_BTN ) ), + m_aOKBtn ( this, SVX_RES( BTN_DATANAV_OK ) ), + m_aEscBtn ( this, SVX_RES( BTN_DATANAV_ESC ) ), + m_aHelpBtn ( this, SVX_RES( BTN_DATANAV_HELP ) ), + + m_xUIHelper ( _rUIHelper ), + m_pItemNode ( _pNode ), + m_eItemType ( DITNone ), + m_sFL_Element ( SVX_RES( STR_FIXEDLINE_ELEMENT ) ), + m_sFL_Attribute ( SVX_RES( STR_FIXEDLINE_ATTRIBUTE ) ), + m_sFL_Binding ( SVX_RES( STR_FIXEDLINE_BINDING ) ), + m_sFT_BindingExp( SVX_RES( STR_FIXEDTEXT_BINDING ) ) + + { + FreeResource(); + m_aDataTypeLB.SetDropDownLineCount( 10 ); + + InitDialog(); + InitFromNode(); + InitDataTypeBox(); + CheckHdl( NULL ); + } + + //------------------------------------------------------------------------ + AddDataItemDialog::~AddDataItemDialog() + { + if ( m_xTempBinding.is() ) + { + Reference< css::xforms::XModel > xModel( m_xUIHelper, UNO_QUERY ); + if ( xModel.is() ) + { + try + { + Reference < XSet > xBindings = xModel->getBindings(); + if ( xBindings.is() ) + xBindings->remove( makeAny( m_xTempBinding ) ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "AddDataItemDialog::Dtor(): exception caught" ); + } + } + } + if( m_xUIHelper.is() && m_xBinding.is() ) + { + // remove binding, if it does not convey 'useful' information + m_xUIHelper->removeBindingIfUseless( m_xBinding ); + } + } + + //------------------------------------------------------------------------ + IMPL_LINK( AddDataItemDialog, CheckHdl, CheckBox *, pBox ) + { + // Condition buttons are only enable if their check box is checked + m_aReadonlyBtn.Enable( m_aReadonlyCB.IsChecked() ); + m_aRequiredBtn.Enable( m_aRequiredCB.IsChecked() ); + m_aRelevantBtn.Enable( m_aRelevantCB.IsChecked() ); + m_aConstraintBtn.Enable( m_aConstraintCB.IsChecked() ); + m_aCalculateBtn.Enable( m_aCalculateCB.IsChecked() ); + + if ( pBox && m_xTempBinding.is() ) + { + ::rtl::OUString sTemp, sPropName; + if ( &m_aRequiredCB == pBox ) + sPropName = PN_REQUIRED_EXPR; + else if ( &m_aRelevantCB == pBox ) + sPropName = PN_RELEVANT_EXPR; + else if ( &m_aConstraintCB == pBox ) + sPropName = PN_CONSTRAINT_EXPR; + else if ( &m_aReadonlyCB == pBox ) + sPropName = PN_READONLY_EXPR; + else if ( &m_aCalculateCB == pBox ) + sPropName = PN_CALCULATE_EXPR; + bool bIsChecked = ( pBox->IsChecked() != FALSE ); + m_xTempBinding->getPropertyValue( sPropName ) >>= sTemp; + if ( bIsChecked && sTemp.getLength() == 0 ) + sTemp = TRUE_VALUE; + else if ( !bIsChecked && sTemp.getLength() > 0 ) + sTemp = ::rtl::OUString(); + m_xTempBinding->setPropertyValue( sPropName, makeAny( sTemp ) ); + } + + return 0; + } + + //------------------------------------------------------------------------ + IMPL_LINK( AddDataItemDialog, ConditionHdl, PushButton *, pBtn ) + { + ::rtl::OUString sTemp, sPropName; + if ( &m_aDefaultBtn == pBtn ) + sPropName = PN_BINDING_EXPR; + else if ( &m_aRequiredBtn == pBtn ) + sPropName = PN_REQUIRED_EXPR; + else if ( &m_aRelevantBtn == pBtn ) + sPropName = PN_RELEVANT_EXPR; + else if ( &m_aConstraintBtn == pBtn ) + sPropName = PN_CONSTRAINT_EXPR; + else if ( &m_aReadonlyBtn == pBtn ) + sPropName = PN_READONLY_EXPR; + else if ( &m_aCalculateBtn == pBtn ) + sPropName = PN_CALCULATE_EXPR; + AddConditionDialog aDlg( this, sPropName, m_xTempBinding ); + bool bIsDefBtn = ( &m_aDefaultBtn == pBtn ); + String sCondition; + if ( bIsDefBtn ) + sCondition = m_aDefaultED.GetText(); + else + { + m_xTempBinding->getPropertyValue( sPropName ) >>= sTemp; + if ( sTemp.getLength() == 0 ) + sTemp = TRUE_VALUE; + sCondition = sTemp; + } + aDlg.SetCondition( sCondition ); + + if ( aDlg.Execute() == RET_OK ) + { + String sNewCondition = aDlg.GetCondition(); + if ( bIsDefBtn ) + m_aDefaultED.SetText( sNewCondition ); + else + { + + m_xTempBinding->setPropertyValue( + sPropName, makeAny( ::rtl::OUString( sNewCondition ) ) ); + } + } + return 0; + } + + void copyPropSet( const Reference< XPropertySet >& xFrom, Reference< XPropertySet >& xTo ) + { + DBG_ASSERT( xFrom.is(), "copyPropSet(): no source" ); + DBG_ASSERT( xTo.is(), "copyPropSet(): no target" ); + + try + { + // get property names & infos, and iterate over target properties + Sequence< Property > aProperties = xTo->getPropertySetInfo()->getProperties(); + sal_Int32 nProperties = aProperties.getLength(); + const Property* pProperties = aProperties.getConstArray(); + Reference< XPropertySetInfo > xFromInfo = xFrom->getPropertySetInfo(); + for ( sal_Int32 i = 0; i < nProperties; ++i ) + { + const ::rtl::OUString& rName = pProperties[i].Name; + + // if both set have the property, copy the value + // (catch and ignore exceptions, if any) + if ( xFromInfo->hasPropertyByName( rName ) ) + { + // don't set readonly properties + Property aProperty = xFromInfo->getPropertyByName( rName ); + if ( ( aProperty.Attributes & PropertyAttribute::READONLY ) == 0 ) + xTo->setPropertyValue(rName, xFrom->getPropertyValue( rName )); + } + // else: no property? then ignore. + } + } + catch ( Exception& ) + { + DBG_ERRORFILE( "copyPropSet(): exception caught" ); + } + } + + //------------------------------------------------------------------------ + IMPL_LINK( AddDataItemDialog, OKHdl, OKButton *, EMPTYARG ) + { + bool bIsHandleBinding = ( DITBinding == m_eItemType ); + bool bIsHandleText = ( DITText == m_eItemType ); + ::rtl::OUString sNewName( m_aNameED.GetText() ); + + if ( ( !bIsHandleBinding && !bIsHandleText && !m_xUIHelper->isValidXMLName( sNewName ) ) || + ( bIsHandleBinding && sNewName.getLength() == 0 ) ) + { + // Error and don't close the dialog + ErrorBox aErrBox( this, SVX_RES( RID_ERR_INVALID_XMLNAME ) ); + String sMessText = aErrBox.GetMessText(); + sMessText.SearchAndReplace( MSG_VARIABLE, sNewName ); + aErrBox.SetMessText( sMessText ); + aErrBox.Execute(); + return 0; + } + + ::rtl::OUString sDataType( m_aDataTypeLB.GetSelectEntry() ); + m_xTempBinding->setPropertyValue( PN_BINDING_TYPE, makeAny( sDataType ) ); + + if ( bIsHandleBinding ) + { + // copy properties from temp binding to original binding + copyPropSet( m_xTempBinding, m_pItemNode->m_xPropSet ); + try + { + ::rtl::OUString sValue = m_aNameED.GetText(); + m_pItemNode->m_xPropSet->setPropertyValue( PN_BINDING_ID, makeAny( sValue ) ); + sValue = m_aDefaultED.GetText(); + m_pItemNode->m_xPropSet->setPropertyValue( PN_BINDING_EXPR, makeAny( sValue ) ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "AddDataDialog::OKHdl(): exception caught" ); + } + } + else + { + // copy properties from temp binding to original binding + copyPropSet( m_xTempBinding, m_xBinding ); + try + { + if ( bIsHandleText ) + m_xUIHelper->setNodeValue( m_pItemNode->m_xNode, m_aDefaultED.GetText() ); + else + { + Reference< css::xml::dom::XNode > xNewNode = + m_xUIHelper->renameNode( m_pItemNode->m_xNode, m_aNameED.GetText() ); + m_xUIHelper->setNodeValue( xNewNode, m_aDefaultED.GetText() ); + m_pItemNode->m_xNode = xNewNode; + } + } + catch ( Exception& ) + { + DBG_ERRORFILE( "AddDataDialog::OKHdl(): exception caught" ); + } + } + // then close the dialog + EndDialog( RET_OK ); + return 0; + } + + //------------------------------------------------------------------------ + void AddDataItemDialog::InitDialog() + { + // set handler + Link aLink = LINK( this, AddDataItemDialog, CheckHdl ); + m_aRequiredCB.SetClickHdl( aLink ); + m_aRelevantCB.SetClickHdl( aLink ); + m_aConstraintCB.SetClickHdl( aLink ); + m_aReadonlyCB.SetClickHdl( aLink ); + m_aCalculateCB.SetClickHdl( aLink ); + + aLink = LINK( this, AddDataItemDialog, ConditionHdl ); + m_aDefaultBtn.SetClickHdl( aLink ); + m_aRequiredBtn.SetClickHdl( aLink ); + m_aRelevantBtn.SetClickHdl( aLink ); + m_aConstraintBtn.SetClickHdl( aLink ); + m_aReadonlyBtn.SetClickHdl( aLink ); + m_aCalculateBtn.SetClickHdl( aLink ); + + m_aOKBtn.SetClickHdl( LINK( this, AddDataItemDialog, OKHdl ) ); + } + + //------------------------------------------------------------------------ + void AddDataItemDialog::InitFromNode() + { + if ( m_pItemNode ) + { + if ( m_pItemNode->m_xNode.is() ) + { + try + { + // detect type of the node + css::xml::dom::NodeType eChildType = m_pItemNode->m_xNode->getNodeType(); + switch ( eChildType ) + { + case css::xml::dom::NodeType_ATTRIBUTE_NODE: + m_eItemType = DITAttribute; + break; + case css::xml::dom::NodeType_ELEMENT_NODE: + m_eItemType = DITElement; + break; + case css::xml::dom::NodeType_TEXT_NODE: + m_eItemType = DITText; + break; + default: + DBG_ERROR( "AddDataItemDialog::InitFronNode: cannot handle this node type!" ); + break; + } + + /** Get binding of the node and clone it + Then use this temporary binding in the dialog. + When the user click OK the temporary binding will be copied + into the original binding. + */ + + Reference< css::xml::dom::XNode > xNode = m_pItemNode->m_xNode; + m_xBinding = m_xUIHelper->getBindingForNode( xNode, sal_True ); + if ( m_xBinding.is() ) + { + Reference< css::xforms::XModel > xModel( m_xUIHelper, UNO_QUERY ); + if ( xModel.is() ) + { + m_xTempBinding = m_xUIHelper->cloneBindingAsGhost( m_xBinding ); + Reference < XSet > xBindings = xModel->getBindings(); + if ( xBindings.is() ) + xBindings->insert( makeAny( m_xTempBinding ) ); + } + } + + if ( m_eItemType != DITText ) + { + ::rtl::OUString sName( m_xUIHelper->getNodeName( m_pItemNode->m_xNode ) ); + m_aNameED.SetText( sName ); + } + m_aDefaultED.SetText( m_pItemNode->m_xNode->getNodeValue() ); + } + catch( Exception& ) + { + DBG_ERRORFILE( "AddDataItemDialog::InitFromNode(): exception caught" ); + } + } + else if ( m_pItemNode->m_xPropSet.is() ) + { + m_eItemType = DITBinding; + Reference< css::xforms::XModel > xModel( m_xUIHelper, UNO_QUERY ); + if ( xModel.is() ) + { + try + { + m_xTempBinding = m_xUIHelper->cloneBindingAsGhost( m_pItemNode->m_xPropSet ); + Reference < XSet > xBindings = xModel->getBindings(); + if ( xBindings.is() ) + xBindings->insert( makeAny( m_xTempBinding ) ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "AddDataItemDialog::InitFromNode(): exception caught" ); + } + } + rtl::OUString sTemp; + try + { + Reference< XPropertySetInfo > xInfo = m_pItemNode->m_xPropSet->getPropertySetInfo(); + if ( xInfo->hasPropertyByName( PN_BINDING_ID ) ) + { + m_pItemNode->m_xPropSet->getPropertyValue( PN_BINDING_ID ) >>= sTemp; + m_aNameED.SetText( sTemp ); + m_pItemNode->m_xPropSet->getPropertyValue( PN_BINDING_EXPR ) >>= sTemp; + m_aDefaultED.SetText( sTemp ); + } + else if ( xInfo->hasPropertyByName( PN_SUBMISSION_BIND ) ) + { + m_pItemNode->m_xPropSet->getPropertyValue( PN_SUBMISSION_ID ) >>= sTemp; + m_aNameED.SetText( sTemp ); + } + } + catch( Exception& ) + { + DBG_ERRORFILE( "AddDataItemDialog::InitFromNode(): exception caught" ); + } + + Size a3and1Sz = LogicToPixel( Size( 3, 1 ), MAP_APPFONT ); + Size aNewSz = m_aDefaultED.GetSizePixel(); + Point aNewPnt = m_aDefaultED.GetPosPixel(); + aNewPnt.Y() += a3and1Sz.Height(); + aNewSz.Width() -= ( m_aDefaultBtn.GetSizePixel().Width() + a3and1Sz.Width() ); + m_aDefaultED.SetPosSizePixel( aNewPnt, aNewSz ); + m_aDefaultBtn.Show(); + } + + if ( m_xTempBinding.is() ) + { + ::rtl::OUString sTemp; + try + { + if ( ( m_xTempBinding->getPropertyValue( PN_REQUIRED_EXPR ) >>= sTemp ) + && sTemp.getLength() > 0 ) + m_aRequiredCB.Check( TRUE ); + if ( ( m_xTempBinding->getPropertyValue( PN_RELEVANT_EXPR ) >>= sTemp ) + && sTemp.getLength() > 0 ) + m_aRelevantCB.Check( TRUE ); + if ( ( m_xTempBinding->getPropertyValue( PN_CONSTRAINT_EXPR ) >>= sTemp ) + && sTemp.getLength() > 0 ) + m_aConstraintCB.Check( TRUE ); + if ( ( m_xTempBinding->getPropertyValue( PN_READONLY_EXPR ) >>= sTemp ) + && sTemp.getLength() > 0 ) + m_aReadonlyCB.Check( TRUE ); + if ( ( m_xTempBinding->getPropertyValue( PN_CALCULATE_EXPR ) >>= sTemp ) + && sTemp.getLength() > 0 ) + m_aCalculateCB.Check( TRUE ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "AddDataItemDialog::InitFromNode(): exception caught" ); + } + } + } + + if ( DITText == m_eItemType ) + { + long nDelta = m_aButtonsFL.GetPosPixel().Y() - m_aSettingsFL.GetPosPixel().Y(); + size_t i = 0; + Window* pWinsForHide[] = + { + &m_aSettingsFL, &m_aDataTypeFT, &m_aDataTypeLB, &m_aRequiredCB, + &m_aRequiredBtn, &m_aRelevantCB, &m_aRelevantBtn, &m_aConstraintCB, + &m_aConstraintBtn, &m_aReadonlyCB, &m_aReadonlyBtn, &m_aCalculateCB, + &m_aCalculateBtn + }; + Window** pCurrent = pWinsForHide; + for ( ; i < SAL_N_ELEMENTS( pWinsForHide ); ++i, ++pCurrent ) + (*pCurrent)->Hide(); + + Window* pWinsForMove[] = + { + &m_aButtonsFL, &m_aOKBtn, &m_aEscBtn, &m_aHelpBtn + }; + pCurrent = pWinsForMove; + for ( i = 0; i < SAL_N_ELEMENTS( pWinsForMove ); ++i, ++pCurrent ) + { + Point aNewPos = (*pCurrent)->GetPosPixel(); + aNewPos.Y() -= nDelta; + (*pCurrent)->SetPosPixel( aNewPos ); + } + Size aNewWinSz = GetSizePixel(); + aNewWinSz.Height() -= nDelta; + SetSizePixel( aNewWinSz ); + + m_aNameFT.Disable(); + m_aNameED.Disable(); + } + } + + //------------------------------------------------------------------------ + void AddDataItemDialog::InitDataTypeBox() + { + if ( m_eItemType != DITText ) + { + Reference< css::xforms::XModel > xModel( m_xUIHelper, UNO_QUERY ); + if ( xModel.is() ) + { + try + { + Reference< css::xforms::XDataTypeRepository > xDataTypes = + xModel->getDataTypeRepository(); + if ( xDataTypes.is() ) + { + Sequence< ::rtl::OUString > aNameList = xDataTypes->getElementNames(); + sal_Int32 i, nCount = aNameList.getLength(); + ::rtl::OUString* pNames = aNameList.getArray(); + for ( i = 0; i < nCount; ++i ) + m_aDataTypeLB.InsertEntry( pNames[i] ); + } + + if ( m_xTempBinding.is() ) + { + rtl::OUString sTemp; + if ( m_xTempBinding->getPropertyValue( PN_BINDING_TYPE ) >>= sTemp ) + { + USHORT nPos = m_aDataTypeLB.GetEntryPos( String( sTemp ) ); + if ( LISTBOX_ENTRY_NOTFOUND == nPos ) + nPos = m_aDataTypeLB.InsertEntry( sTemp ); + m_aDataTypeLB.SelectEntryPos( nPos ); + } + } + } + catch ( Exception& ) + { + DBG_ERRORFILE( "AddDataItemDialog::InitDataTypeBox(): exception caught" ); + } + } + } + } + + void AddDataItemDialog::InitText( DataItemType _eType ) + { + String sText; + + switch ( _eType ) + { + case DITAttribute : + { + sText = m_sFL_Attribute; + break; + } + + case DITBinding : + { + sText = m_sFL_Binding; + m_aDefaultFT.SetText( m_sFT_BindingExp ); + break; + } + + default: + { + sText = m_sFL_Element; + } + } + + m_aItemFL.SetText( sText ); + } + + //======================================================================== + // class AddConditionDialog + //======================================================================== + + AddConditionDialog::AddConditionDialog( + Window* pParent, const ::rtl::OUString& _rPropertyName, + const Reference< XPropertySet >& _rPropSet ) : + + ModalDialog( pParent, SVX_RES( RID_SVXDLG_ADD_CONDITION ) ), + + m_aConditionFT ( this, SVX_RES( FT_CONDITION ) ), + m_aConditionED ( this, SVX_RES( ED_CONDITION ) ), + m_aResultFT ( this, SVX_RES( FT_RESULT ) ), + m_aResultWin ( this, SVX_RES( FT_RESULT_PREVIEW ) ), + m_aEditNamespacesBtn( this, SVX_RES( PB_EDIT_NAMESPACES ) ), + m_aButtonsFL ( this, SVX_RES( FL_DATANAV_BTN ) ), + m_aOKBtn ( this, SVX_RES( BTN_DATANAV_OK ) ), + m_aEscBtn ( this, SVX_RES( BTN_DATANAV_ESC ) ), + m_aHelpBtn ( this, SVX_RES( BTN_DATANAV_HELP ) ), + + m_sPropertyName ( _rPropertyName ), + m_xBinding ( _rPropSet ) + + { + FreeResource(); + + DBG_ASSERT( m_xBinding.is(), "AddConditionDialog::Ctor(): no Binding" ); + + m_aResultWin.SetBackground( m_aConditionED.GetBackground() ); + m_aConditionED.SetModifyHdl( LINK( this, AddConditionDialog, ModifyHdl ) ); + m_aEditNamespacesBtn.SetClickHdl( LINK( this, AddConditionDialog, EditHdl ) ); + m_aOKBtn.SetClickHdl( LINK( this, AddConditionDialog, OKHdl ) ); + m_aResultTimer.SetTimeout( 500 ); + m_aResultTimer.SetTimeoutHdl( LINK( this, AddConditionDialog, ResultHdl ) ); + + if ( m_sPropertyName.getLength() > 0 ) + { + try + { + rtl::OUString sTemp; + if ( ( m_xBinding->getPropertyValue( m_sPropertyName ) >>= sTemp ) + && sTemp.getLength() > 0 ) + { + m_aConditionED.SetText( sTemp ); + } + else + { +//! m_xBinding->setPropertyValue( m_sPropertyName, makeAny( TRUE_VALUE ) ); + m_aConditionED.SetText( TRUE_VALUE ); + } + + Reference< css::xforms::XModel > xModel; + if ( ( m_xBinding->getPropertyValue( PN_BINDING_MODEL ) >>= xModel ) && xModel.is() ) + m_xUIHelper = Reference< css::xforms::XFormsUIHelper1 >( xModel, UNO_QUERY ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "AddConditionDialog::Ctor(): exception caught" ); + } + } + + DBG_ASSERT( m_xUIHelper.is(), "AddConditionDialog::Ctor(): no UIHelper" ); + ResultHdl( &m_aResultTimer ); + } + + //------------------------------------------------------------------------ + AddConditionDialog::~AddConditionDialog() + { + } + + //------------------------------------------------------------------------ + IMPL_LINK( AddConditionDialog, EditHdl, PushButton *, EMPTYARG ) + { + Reference< XNameContainer > xNameContnr; + try + { + m_xBinding->getPropertyValue( PN_BINDING_NAMESPACES ) >>= xNameContnr; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "AddDataItemDialog::EditHdl(): exception caught" ); + } + NamespaceItemDialog aDlg( this, xNameContnr ); + aDlg.Execute(); + try + { + m_xBinding->setPropertyValue( PN_BINDING_NAMESPACES, makeAny( xNameContnr ) ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "AddDataItemDialog::EditHdl(): exception caught" ); + } + return 0; + } + + //------------------------------------------------------------------------ + IMPL_LINK( AddConditionDialog, OKHdl, OKButton *, EMPTYARG ) + { +/*!!! + try + { + if ( m_xBinding.is() ) + m_xBinding->setPropertyValue( m_sPropertyName, makeAny( ::rtl::OUString( m_aConditionED.GetText() ) ) ); + } + catch( const Exception& ) + { + DBG_ERRORFILE( "AddConditionDialog, OKHdl: caught an exception!" ); + } +*/ + EndDialog( RET_OK ); + return 0; + } + + //------------------------------------------------------------------------ + IMPL_LINK( AddConditionDialog, ModifyHdl, MultiLineEdit *, EMPTYARG ) + { + m_aResultTimer.Start(); + return 0; + } + + //------------------------------------------------------------------------ + IMPL_LINK( AddConditionDialog, ResultHdl, Timer *, EMPTYARG ) + { + String sCondition = m_aConditionED.GetText().EraseLeadingChars().EraseTrailingChars(); + String sResult; + if ( sCondition.Len() > 0 ) + { + try + { + sResult = m_xUIHelper->getResultForExpression( m_xBinding, ( m_sPropertyName == PN_BINDING_EXPR ), sCondition ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "AddConditionDialog::ResultHdl(): exception caught" ); + } + } + m_aResultWin.SetText( sResult ); + return 0; + } + + //======================================================================== + // class NamespaceItemDialog + //======================================================================== + + NamespaceItemDialog::NamespaceItemDialog( + AddConditionDialog* _pCondDlg, Reference< XNameContainer >& _rContainer ) : + + ModalDialog( _pCondDlg, SVX_RES( RID_SVXDLG_NAMESPACE_ITEM ) ), + + m_aNamespacesFT ( this, SVX_RES( FT_NAMESPACES ) ), + m_aNamespacesList ( this, SVX_RES( LB_NAMESPACES ) ), + m_aAddNamespaceBtn ( this, SVX_RES( PB_ADD_NAMESPACE ) ), + m_aEditNamespaceBtn ( this, SVX_RES( PB_EDIT_NAMESPACE ) ), + m_aDeleteNamespaceBtn ( this, SVX_RES( PB_DELETE_NAMESPACE ) ), + m_aButtonsFL ( this, SVX_RES( FL_DATANAV_BTN ) ), + m_aOKBtn ( this, SVX_RES( BTN_DATANAV_OK ) ), + m_aEscBtn ( this, SVX_RES( BTN_DATANAV_ESC ) ), + m_aHelpBtn ( this, SVX_RES( BTN_DATANAV_HELP ) ), + + m_pConditionDlg ( _pCondDlg ), + m_rNamespaces ( _rContainer ) + + { + static long aStaticTabs[]= { 3, 0, 35, 200 }; + m_aNamespacesList.SvxSimpleTable::SetTabs( aStaticTabs ); + String sHeader = String( SVX_RES( STR_HEADER_PREFIX ) ); + sHeader += '\t'; + sHeader += String( SVX_RES( STR_HEADER_URL ) ); + m_aNamespacesList.InsertHeaderEntry( + sHeader, HEADERBAR_APPEND, HIB_LEFT /*| HIB_FIXEDPOS | HIB_FIXED*/ ); + + FreeResource(); + + m_aNamespacesList.SetSelectHdl( LINK( this, NamespaceItemDialog, SelectHdl ) ); + Link aLink = LINK( this, NamespaceItemDialog, ClickHdl ); + m_aAddNamespaceBtn.SetClickHdl( aLink ); + m_aEditNamespaceBtn.SetClickHdl( aLink ); + m_aDeleteNamespaceBtn.SetClickHdl( aLink ); + m_aOKBtn.SetClickHdl( LINK( this, NamespaceItemDialog, OKHdl ) ); + + LoadNamespaces(); + SelectHdl( &m_aNamespacesList ); + } + + //------------------------------------------------------------------------ + NamespaceItemDialog::~NamespaceItemDialog() + { + } + + //------------------------------------------------------------------------ + IMPL_LINK( NamespaceItemDialog, SelectHdl, SvxSimpleTable *, EMPTYARG ) + { + BOOL bEnable = ( m_aNamespacesList.FirstSelected() != NULL ); + m_aEditNamespaceBtn.Enable( bEnable ); + m_aDeleteNamespaceBtn.Enable( bEnable ); + + return 0; + } + + //------------------------------------------------------------------------ + IMPL_LINK( NamespaceItemDialog, ClickHdl, PushButton *, pBtn ) + { + if ( &m_aAddNamespaceBtn == pBtn ) + { + ManageNamespaceDialog aDlg( this, m_pConditionDlg, false ); + if ( aDlg.Execute() == RET_OK ) + { + String sEntry = aDlg.GetPrefix(); + sEntry += '\t'; + sEntry += aDlg.GetURL(); + m_aNamespacesList.InsertEntry( sEntry ); + } + } + else if ( &m_aEditNamespaceBtn == pBtn ) + { + ManageNamespaceDialog aDlg( this, m_pConditionDlg, true ); + SvLBoxEntry* pEntry = m_aNamespacesList.FirstSelected(); + DBG_ASSERT( pEntry, "NamespaceItemDialog::ClickHdl(): no entry" ); + String sPrefix( m_aNamespacesList.GetEntryText( pEntry, 0 ) ); + aDlg.SetNamespace( + sPrefix, + m_aNamespacesList.GetEntryText( pEntry, 1 ) ); + if ( aDlg.Execute() == RET_OK ) + { + // if a prefix was changed, mark the old prefix as 'removed' + if( sPrefix != aDlg.GetPrefix() ) + m_aRemovedList.push_back( sPrefix ); + + m_aNamespacesList.SetEntryText( aDlg.GetPrefix(), pEntry, 0 ); + m_aNamespacesList.SetEntryText( aDlg.GetURL(), pEntry, 1 ); + } + } + else if ( &m_aDeleteNamespaceBtn == pBtn ) + { + SvLBoxEntry* pEntry = m_aNamespacesList.FirstSelected(); + DBG_ASSERT( pEntry, "NamespaceItemDialog::ClickHdl(): no entry" ); + ::rtl::OUString sPrefix( m_aNamespacesList.GetEntryText( pEntry, 0 ) ); + m_aRemovedList.push_back( sPrefix ); + m_aNamespacesList.GetModel()->Remove( pEntry ); + } + else + { + DBG_ERRORFILE( "NamespaceItemDialog::ClickHdl(): invalid button" ); + } + + SelectHdl( &m_aNamespacesList ); + return 0; + } + + //------------------------------------------------------------------------ + IMPL_LINK( NamespaceItemDialog, OKHdl, OKButton *, EMPTYARG ) + { + try + { + // update namespace container + sal_Int32 i, nRemovedCount = m_aRemovedList.size(); + for( i = 0; i < nRemovedCount; ++i ) + m_rNamespaces->removeByName( m_aRemovedList[i] ); + + sal_Int32 nEntryCount = m_aNamespacesList.GetEntryCount(); + for( i = 0; i < nEntryCount; ++i ) + { + SvLBoxEntry* pEntry = m_aNamespacesList.GetEntry(i); + ::rtl::OUString sPrefix( m_aNamespacesList.GetEntryText( pEntry, 0 ) ); + ::rtl::OUString sURL( m_aNamespacesList.GetEntryText( pEntry, 1 ) ); + + if ( m_rNamespaces->hasByName( sPrefix ) ) + m_rNamespaces->replaceByName( sPrefix, makeAny( sURL ) ); + else + m_rNamespaces->insertByName( sPrefix, makeAny( sURL ) ); + } + } + catch ( Exception& ) + { + DBG_ERRORFILE( "NamespaceItemDialog::OKHdl(): exception caught" ); + } + // and close the dialog + EndDialog( RET_OK ); + return 0; + } + + //------------------------------------------------------------------------ + void NamespaceItemDialog::LoadNamespaces() + { + try + { + Sequence< ::rtl::OUString > aAllNames = m_rNamespaces->getElementNames(); + const ::rtl::OUString* pAllNames = aAllNames.getConstArray(); + const ::rtl::OUString* pAllNamesEnd = pAllNames + aAllNames.getLength(); + for ( ; pAllNames != pAllNamesEnd; ++pAllNames ) + { + ::rtl::OUString sURL; + ::rtl::OUString sPrefix = *pAllNames; + if ( m_rNamespaces->hasByName( sPrefix ) ) + { + Any aAny = m_rNamespaces->getByName( sPrefix ); + if ( aAny >>= sURL ) + { + String sEntry( sPrefix ); + sEntry += '\t'; + sEntry += String( sURL ); + + m_aNamespacesList.InsertEntry( sEntry ); + } + } + } + } + catch ( Exception& ) + { + DBG_ERRORFILE( "NamespaceItemDialog::LoadNamespaces(): exception caught" ); + } + } + + //======================================================================== + // class ManageNamespaceDialog + //======================================================================== + + ManageNamespaceDialog::ManageNamespaceDialog( + Window* pParent, AddConditionDialog* _pCondDlg, bool _bIsEdit ) : + + ModalDialog( pParent, SVX_RES( RID_SVXDLG_MANAGE_NAMESPACE ) ), + + m_aPrefixFT ( this, SVX_RES( FT_PREFIX ) ), + m_aPrefixED ( this, SVX_RES( ED_PREFIX ) ), + m_aUrlFT ( this, SVX_RES( FT_URL ) ), + m_aUrlED ( this, SVX_RES( ED_URL ) ), + m_aButtonsFL ( this, SVX_RES( FL_DATANAV_BTN ) ), + m_aOKBtn ( this, SVX_RES( BTN_DATANAV_OK ) ), + m_aEscBtn ( this, SVX_RES( BTN_DATANAV_ESC ) ), + m_aHelpBtn ( this, SVX_RES( BTN_DATANAV_HELP ) ), + + m_pConditionDlg ( _pCondDlg ) + + { + if ( _bIsEdit ) + SetText( String( SVX_RES( STR_EDIT_TEXT ) ) ); + + FreeResource(); + + m_aOKBtn.SetClickHdl( LINK( this, ManageNamespaceDialog, OKHdl ) ); + } + + //------------------------------------------------------------------------ + ManageNamespaceDialog::~ManageNamespaceDialog() + { + } + + //------------------------------------------------------------------------ + IMPL_LINK( ManageNamespaceDialog, OKHdl, OKButton *, EMPTYARG ) + { + String sPrefix = m_aPrefixED.GetText(); + + try + { + if ( !m_pConditionDlg->GetUIHelper()->isValidPrefixName( sPrefix ) ) + { + ErrorBox aErrBox( this, SVX_RES( RID_ERR_INVALID_XMLPREFIX ) ); + String sMessText = aErrBox.GetMessText(); + sMessText.SearchAndReplace( MSG_VARIABLE, sPrefix ); + aErrBox.SetMessText( sMessText ); + aErrBox.Execute(); + return 0; + } + } + catch ( Exception& ) + { + DBG_ERRORFILE( "ManageNamespacesDialog::OKHdl(): exception caught" ); + } + + // no error so close the dialog + EndDialog( RET_OK ); + return 0; + } + + //======================================================================== + // class AddSubmissionDialog + //======================================================================== + + AddSubmissionDialog::AddSubmissionDialog( + Window* pParent, ItemNode* _pNode, + const Reference< css::xforms::XFormsUIHelper1 >& _rUIHelper ) : + + ModalDialog( pParent, SVX_RES( RID_SVXDLG_ADD_SUBMISSION ) ), + + m_aSubmissionFL ( this, SVX_RES( FL_SUBMISSION ) ), + m_aNameFT ( this, SVX_RES( FT_SUBMIT_NAME ) ), + m_aNameED ( this, SVX_RES( ED_SUBMIT_NAME ) ), + m_aActionFT ( this, SVX_RES( FT_SUBMIT_ACTION ) ), + m_aActionED ( this, SVX_RES( ED_SUBMIT_ACTION ) ), + m_aMethodFT ( this, SVX_RES( FT_SUBMIT_METHOD ) ), + m_aMethodLB ( this, SVX_RES( LB_SUBMIT_METHOD ) ), + m_aRefFT ( this, SVX_RES( FT_SUBMIT_REF ) ), + m_aRefED ( this, SVX_RES( ED_SUBMIT_REF ) ), + m_aRefBtn ( this, SVX_RES( PB_SUBMIT_REF ) ), + m_aBindFT ( this, SVX_RES( FT_SUBMIT_BIND ) ), + m_aBindLB ( this, SVX_RES( LB_SUBMIT_BIND ) ), + m_aReplaceFT ( this, SVX_RES( FT_SUBMIT_REPLACE ) ), + m_aReplaceLB ( this, SVX_RES( LB_SUBMIT_REPLACE ) ), + + m_aButtonsFL ( this, SVX_RES( FL_DATANAV_BTN ) ), + m_aOKBtn ( this, SVX_RES( BTN_DATANAV_OK ) ), + m_aEscBtn ( this, SVX_RES( BTN_DATANAV_ESC ) ), + m_aHelpBtn ( this, SVX_RES( BTN_DATANAV_HELP ) ), + + m_pItemNode ( _pNode ), + m_xUIHelper ( _rUIHelper ) + + { + FillAllBoxes(); // we need local resources here, so call before FreeResource!!! + + FreeResource(); + + m_aRefBtn.SetClickHdl( LINK( this, AddSubmissionDialog, RefHdl ) ); + m_aOKBtn.SetClickHdl( LINK( this, AddSubmissionDialog, OKHdl ) ); + } + + //------------------------------------------------------------------------ + AddSubmissionDialog::~AddSubmissionDialog() + { + // #i38991# if we have added a binding, we need to remove it as well. + if( m_xCreatedBinding.is() && m_xUIHelper.is() ) + m_xUIHelper->removeBindingIfUseless( m_xCreatedBinding ); + } + + //------------------------------------------------------------------------ + IMPL_LINK( AddSubmissionDialog, RefHdl, PushButton *, EMPTYARG ) + { + AddConditionDialog aDlg( this, PN_BINDING_EXPR, m_xTempBinding ); + aDlg.SetCondition( m_aRefED.GetText() ); + if ( aDlg.Execute() == RET_OK ) + m_aRefED.SetText( aDlg.GetCondition() ); + + return 0; + } + + //------------------------------------------------------------------------ + IMPL_LINK( AddSubmissionDialog, OKHdl, OKButton *, EMPTYARG ) + { + rtl::OUString sName(m_aNameED.GetText()); + if(!sName.getLength()) { + + ErrorBox aErrorBox(this,SVX_RES(RID_ERR_EMPTY_SUBMISSIONNAME)); + aErrorBox.SetText( Application::GetDisplayName() ); + aErrorBox.Execute(); + return 0; + } + + if ( !m_xSubmission.is() ) + { + DBG_ASSERT( !m_xNewSubmission.is(), + "AddSubmissionDialog::OKHdl(): new submission already exists" ); + + // add a new submission + Reference< css::xforms::XModel > xModel( m_xUIHelper, UNO_QUERY ); + if ( xModel.is() ) + { + try + { + m_xNewSubmission = xModel->createSubmission(); + m_xSubmission = Reference< XPropertySet >( m_xNewSubmission, UNO_QUERY ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "AddSubmissionDialog::OKHdl(): exception caught" ); + } + } + } + + if ( m_xSubmission.is() ) + { + rtl::OUString sTemp = m_aNameED.GetText(); + try + { + m_xSubmission->setPropertyValue( PN_SUBMISSION_ID, makeAny( sTemp ) ); + sTemp = m_aActionED.GetText(); + m_xSubmission->setPropertyValue( PN_SUBMISSION_ACTION, makeAny( sTemp ) ); + sTemp = lcl_MethodString::get().toAPI( m_aMethodLB.GetSelectEntry() ); + m_xSubmission->setPropertyValue( PN_SUBMISSION_METHOD, makeAny( sTemp ) ); + sTemp = m_aRefED.GetText(); + m_xSubmission->setPropertyValue( PN_SUBMISSION_REF, makeAny( sTemp ) ); + String sEntry = m_aBindLB.GetSelectEntry(); + sEntry.Erase( sEntry.Search( ':' ) ); + sTemp = sEntry; + m_xSubmission->setPropertyValue( PN_SUBMISSION_BIND, makeAny( sTemp ) ); + sTemp = lcl_ReplaceString::get().toAPI( m_aReplaceLB.GetSelectEntry() ); + m_xSubmission->setPropertyValue( PN_SUBMISSION_REPLACE, makeAny( sTemp ) ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "AddSubmissionDialog::OKHdl(): exception caught" ); + } + } + + EndDialog( RET_OK ); + return 0; + } + + //------------------------------------------------------------------------ + void AddSubmissionDialog::FillAllBoxes() + { + // method box + m_aMethodLB.InsertEntry( String( SVX_RES( STR_METHOD_POST ) ) ); + m_aMethodLB.InsertEntry( String( SVX_RES( STR_METHOD_PUT ) ) ); + m_aMethodLB.InsertEntry( String( SVX_RES( STR_METHOD_GET ) ) ); + m_aMethodLB.SelectEntryPos(0); + + // binding box + Reference< css::xforms::XModel > xModel( m_xUIHelper, UNO_QUERY ); + if ( xModel.is() ) + { + try + { + Reference< XEnumerationAccess > xNumAccess( xModel->getBindings(), UNO_QUERY ); + if ( xNumAccess.is() ) + { + Reference < XEnumeration > xNum = xNumAccess->createEnumeration(); + if ( xNum.is() && xNum->hasMoreElements() ) + { + String sDelim( RTL_CONSTASCII_USTRINGPARAM( ": " ) ); + while ( xNum->hasMoreElements() ) + { + Reference< XPropertySet > xPropSet; + Any aAny = xNum->nextElement(); + if ( aAny >>= xPropSet ) + { + String sEntry; + rtl::OUString sTemp; + xPropSet->getPropertyValue( PN_BINDING_ID ) >>= sTemp; + sEntry += String( sTemp ); + sEntry += sDelim; + xPropSet->getPropertyValue( PN_BINDING_EXPR ) >>= sTemp; + sEntry += String( sTemp ); + m_aBindLB.InsertEntry( sEntry ); + + if ( !m_xTempBinding.is() ) + m_xTempBinding = xPropSet; + } + } + } + } + } + catch ( Exception& ) + { + DBG_ERRORFILE( "AddSubmissionDialog::FillAllBoxes(): exception caught" ); + } + } + + // #i36342# we need a temporary binding; create one if no existing binding + // is found + if( !m_xTempBinding.is() ) + { + m_xCreatedBinding = m_xUIHelper->getBindingForNode( + Reference<css::xml::dom::XNode>( + xModel->getDefaultInstance()->getDocumentElement(), + UNO_QUERY_THROW ), + sal_True ); + m_xTempBinding = m_xCreatedBinding; + } + + // replace box + m_aReplaceLB.InsertEntry( String( SVX_RES( STR_REPLACE_NONE ) ) ); + m_aReplaceLB.InsertEntry( String( SVX_RES( STR_REPLACE_INST ) ) ); + m_aReplaceLB.InsertEntry( String( SVX_RES( STR_REPLACE_DOC ) ) ); + + + // init the controls with the values of the submission + if ( m_pItemNode && m_pItemNode->m_xPropSet.is() ) + { + m_xSubmission = m_pItemNode->m_xPropSet; + rtl::OUString sTemp; + try + { + m_xSubmission->getPropertyValue( PN_SUBMISSION_ID ) >>= sTemp; + m_aNameED.SetText( sTemp ); + m_xSubmission->getPropertyValue( PN_SUBMISSION_ACTION ) >>= sTemp; + m_aActionED.SetText( sTemp ); + m_xSubmission->getPropertyValue( PN_SUBMISSION_REF ) >>= sTemp; + m_aRefED.SetText( sTemp ); + + m_xSubmission->getPropertyValue( PN_SUBMISSION_METHOD ) >>= sTemp; + sTemp = lcl_MethodString::get().toUI( sTemp ); + USHORT nPos = m_aMethodLB.GetEntryPos( String( sTemp ) ); + if ( LISTBOX_ENTRY_NOTFOUND == nPos ) + nPos = m_aMethodLB.InsertEntry( sTemp ); + m_aMethodLB.SelectEntryPos( nPos ); + + m_xSubmission->getPropertyValue( PN_SUBMISSION_BIND ) >>= sTemp; + nPos = m_aBindLB.GetEntryPos( String( sTemp ) ); + if ( LISTBOX_ENTRY_NOTFOUND == nPos ) + nPos = m_aBindLB.InsertEntry( sTemp ); + m_aBindLB.SelectEntryPos( nPos ); + + m_xSubmission->getPropertyValue( PN_SUBMISSION_REPLACE ) >>= sTemp; + sTemp = lcl_ReplaceString::get().toUI( sTemp ); + if ( sTemp.getLength() == 0 ) + sTemp = m_aReplaceLB.GetEntry(0); // first entry == "none" + nPos = m_aReplaceLB.GetEntryPos( String( sTemp ) ); + if ( LISTBOX_ENTRY_NOTFOUND == nPos ) + nPos = m_aReplaceLB.InsertEntry( sTemp ); + m_aReplaceLB.SelectEntryPos( nPos ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "AddSubmissionDialog::FillAllBoxes(): exception caught" ); + } + } + + m_aRefBtn.Enable( m_xTempBinding.is() ); + } + + //======================================================================== + // class AddModelDialog + //======================================================================== + + AddModelDialog::AddModelDialog( Window* pParent, bool _bEdit ) : + + ModalDialog( pParent, SVX_RES( RID_SVXDLG_ADD_MODEL ) ), + + m_aModelFL ( this, SVX_RES( FL_MODEL ) ), + m_aNameFT ( this, SVX_RES( FT_MODEL_NAME ) ), + m_aNameED ( this, SVX_RES( ED_MODEL_NAME ) ), + m_aModifyCB ( this, SVX_RES( CB_MODIFIES_DOCUMENT ) ), + m_aButtonsFL ( this, SVX_RES( FL_DATANAV_BTN ) ), + m_aOKBtn ( this, SVX_RES( BTN_DATANAV_OK ) ), + m_aEscBtn ( this, SVX_RES( BTN_DATANAV_ESC ) ), + m_aHelpBtn ( this, SVX_RES( BTN_DATANAV_HELP ) ) + + { + if ( _bEdit ) + SetText( String( SVX_RES( STR_EDIT_TEXT ) ) ); + + FreeResource(); + } + + AddModelDialog::~AddModelDialog() + { + } + + //======================================================================== + // class AddInstanceDialog + //======================================================================== + + AddInstanceDialog::AddInstanceDialog( Window* pParent, bool _bEdit ) : + + ModalDialog( pParent, SVX_RES( RID_SVXDLG_ADD_INSTANCE ) ), + + m_aInstanceFL ( this, SVX_RES( FL_INSTANCE ) ), + m_aNameFT ( this, SVX_RES( FT_INST_NAME ) ), + m_aNameED ( this, SVX_RES( ED_INST_NAME ) ), + m_aURLFT ( this, SVX_RES( FT_INST_URL ) ), + m_aURLED ( this, SVX_RES( ED_INST_URL ) ), + m_aFilePickerBtn ( this, SVX_RES( PB_FILEPICKER ) ), + m_aLinkInstanceCB ( this, SVX_RES( CB_INST_LINKINST ) ), + m_aButtonsFL ( this, SVX_RES( FL_DATANAV_BTN ) ), + m_aOKBtn ( this, SVX_RES( BTN_DATANAV_OK ) ), + m_aEscBtn ( this, SVX_RES( BTN_DATANAV_ESC ) ), + m_aHelpBtn ( this, SVX_RES( BTN_DATANAV_HELP ) ) + + { + if ( _bEdit ) + SetText( String( SVX_RES( STR_EDIT_TEXT ) ) ); + + FreeResource(); + + m_aURLED.DisableHistory(); + m_aFilePickerBtn.SetClickHdl( LINK( this, AddInstanceDialog, FilePickerHdl ) ); + + // load the filter name from fps_office resource + m_sAllFilterName = String( ResId( STR_FILTERNAME_ALL, *CREATEVERSIONRESMGR(fps_office) ) ); + } + + AddInstanceDialog::~AddInstanceDialog() + { + } + + //------------------------------------------------------------------------ + IMPL_LINK( AddInstanceDialog, FilePickerHdl, PushButton *, EMPTYARG ) + { + ::sfx2::FileDialogHelper aDlg( + css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, 0 ); + INetURLObject aFile( SvtPathOptions().GetWorkPath() ); + + aDlg.AddFilter( m_sAllFilterName, DEFINE_CONST_UNICODE(FILEDIALOG_FILTER_ALL) ); + String sFilterName( DEFINE_CONST_UNICODE("XML") ); + aDlg.AddFilter( sFilterName, DEFINE_CONST_UNICODE("*.xml") ); + aDlg.SetCurrentFilter( sFilterName ); + aDlg.SetDisplayDirectory( aFile.GetMainURL( INetURLObject::NO_DECODE ) ); + + if( aDlg.Execute() == ERRCODE_NONE ) + m_aURLED.SetText( aDlg.GetPath() ); + + return 0; + } + + //======================================================================== + // class LinkedInstanceWarningBox + //======================================================================== + + LinkedInstanceWarningBox::LinkedInstanceWarningBox( Window* pParent ) : + + MessBox( pParent, SVX_RES( RID_QRY_LINK_WARNING ) ) + + { + SetText( Application::GetDisplayName() ); + SetImage( QueryBox::GetStandardImage() ); + AddButton( SVX_RESSTR( RID_STR_DATANAV_LINKWARN_BUTTON ), BUTTONID_OK, BUTTONDIALOG_DEFBUTTON ); + AddButton( BUTTON_CANCEL, BUTTONID_CANCEL, BUTTONDIALOG_CANCELBUTTON ); + } + +//............................................................................ +} // namespace svxform +//............................................................................ + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/datanavi.src b/svx/source/form/datanavi.src new file mode 100644 index 000000000000..f6265b6b0596 --- /dev/null +++ b/svx/source/form/datanavi.src @@ -0,0 +1,1148 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "datanavi.hrc" +#include "globlmn.hrc" +#include "fmresids.hrc" +#include "fmhelp.hrc" + +#define MASKCOLOR MaskColor = Color { Red = 0xFFFF ; Green = 0x0000 ; Blue = 0xFFFF ; }; + +TabPage RID_SVX_XFORMS_TABPAGES +{ + Hide = TRUE ; + DialogControl = TRUE; + Size = MAP_APPFONT ( 63 , 100 ) ; + ToolBox TB_ITEMS + { + HelpId = HID_XFORMS_TOOLBOX ; + SVLook = TRUE ; + Pos = MAP_APPFONT ( 0 , 0 ) ; + ItemList = + { + ToolBoxItem + { + Identifier = TBI_ITEM_ADD ; + HelpId = HID_XFORMS_TOOLBOX_ITEM_ADD ; + Text [ en-US ] = "Add Item" ; + }; + ToolBoxItem + { + Identifier = TBI_ITEM_ADD_ELEMENT ; + HelpId = HID_XFORMS_TOOLBOX_ITEM_ADD_ELEMENT ; + Text [ en-US ] = "Add Element" ; + }; + ToolBoxItem + { + Identifier = TBI_ITEM_ADD_ATTRIBUTE ; + HelpId = HID_XFORMS_TOOLBOX_ITEM_ADD_ATTRIBUTE ; + Text [ en-US ] = "Add Attribute" ; + }; + ToolBoxItem + { + Identifier = TBI_ITEM_EDIT ; + HelpId = HID_XFORMS_TOOLBOX_ITEM_EDIT ; + Text [ en-US ] = "Edit" ; + }; + ToolBoxItem + { + Type = TOOLBOXITEM_SEPARATOR ; + }; + ToolBoxItem + { + Identifier = TBI_ITEM_REMOVE ; + HelpId = HID_XFORMS_TOOLBOX_ITEM_REMOVE ; + Text [ en-US ] = "Delete" ; + }; + }; + }; + Control LB_ITEMS + { + HelpId = HID_XFORMS_ITEMS_LIST ; + Pos = MAP_APPFONT ( 0 , 0 ) ; + Size = MAP_APPFONT ( 63 , 100 ) ; + Border = TRUE ; + TabStop = TRUE; + }; +#define IMG_LST \ +IdList = \ +{ \ + IID_ITEM_ADD ; \ + IID_ITEM_ADD_ELEMENT ; \ + IID_ITEM_ADD_ATTRIBUTE ; \ + IID_ITEM_EDIT ; \ + IID_ITEM_REMOVE ; \ +}; \ +IdCount = { 5 ; } ; + + ImageList IL_TBX_BMPS + { + Prefix = "tb"; + MASKCOLOR + IMG_LST + }; +#undef IMG_LST +}; + +Window RID_SVXWIN_DATANAVIGATOR +{ + OutputSize = TRUE ; + Hide = TRUE ; + SVLook = TRUE ; + DialogControl = TRUE ; + HelpId = HID_DATA_NAVIGATOR_WIN ; + Pos = MAP_APPFONT ( 0 , 0 ) ; + Size = MAP_APPFONT ( 300 , 400 ) ; + ListBox LB_MODELS + { + HelpId = HID_XFORMS_MODELS_LIST ; + Pos = MAP_APPFONT ( 3 , 4 ) ; + Size = MAP_APPFONT ( 63 , 45 ) ; + DropDown = TRUE ; + DDExtraWidth = TRUE ; + }; + MenuButton MB_MODELS + { + HelpId = HID_XFORMS_MODELS_MENUBTN ; + Pos = MAP_APPFONT ( 69 , 3 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + Text [ en-US ] = "~Models"; + ButtonMenu = Menu + { + ItemList = + { + MenuItem + { + Identifier = MID_MODELS_ADD ; + HelpId = HID_MN_XFORMS_MODELS_ADD ; + Text [ en-US ] = "~Add..." ; + }; + MenuItem + { + Identifier = MID_MODELS_EDIT ; + HelpId = HID_MN_XFORMS_MODELS_EDIT ; + Text [ en-US ] = "~Edit..." ; + }; + MenuItem + { + Identifier = MID_MODELS_REMOVE ; + HelpId = HID_MN_XFORMS_MODELS_REMOVE ; + Text [ en-US ] = "~Remove" ; + }; + }; + }; + }; + TabControl TC_ITEMS + { + HelpId = HID_XFORMS_TAB_CONTROL ; + Pos = MAP_APPFONT ( 3, 20 ) ; + TabStop = TRUE; + PageList = + { + PageItem + { + Identifier = TID_INSTANCE ; + Text [ en-US ] = "Instance"; + }; + PageItem + { + Identifier = TID_SUBMISSION ; + Text [ en-US ] = "Submissions"; + }; + PageItem + { + Identifier = TID_BINDINGS ; + Text [ en-US ] = "Bindings"; + }; + }; + }; + MenuButton MB_INSTANCES + { + HelpId = HID_XFORMS_INSTANCES_MENUBTN ; + Pos = MAP_APPFONT ( 69 , 133 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + Text [ en-US ] = "~Instances"; + ButtonMenu = Menu + { + ItemList = + { + MenuItem + { + Identifier = MID_INSTANCES_ADD ; + HelpId = HID_MN_XFORMS_INSTANCES_ADD ; + Text [ en-US ] = "~Add..." ; + }; + MenuItem + { + Identifier = MID_INSTANCES_EDIT ; + HelpId = HID_MN_XFORMS_INSTANCES_EDIT ; + Text [ en-US ] = "~Edit..." ; + }; + MenuItem + { + Identifier = MID_INSTANCES_REMOVE ; + HelpId = HID_MN_XFORMS_INSTANCES_REMOVE ; + Text [ en-US ] = "~Remove" ; + }; + MenuItem + { + Separator = TRUE; + }; + MenuItem + { + Identifier = MID_SHOW_DETAILS ; + HelpId = HID_MN_XFORMS_SHOW_DETAILS ; + Text [ en-US ] = "~Show Details" ; + }; + }; + }; + }; + +#define IMG_LST2 \ +IdList = \ +{ \ + IID_GROUP_CLOSED ; \ + IID_GROUP_OPEN ; \ + IID_ELEMENT ; \ + IID_ATTRIBUTE ; \ + IID_TEXT ; \ + IID_OTHER ; \ +}; \ +IdCount = { 6 ; } ; + + ImageList IL_ITEM_BMPS + { + Prefix = "da"; + MASKCOLOR + IMG_LST2 + }; +}; + +QueryBox RID_QRY_REMOVE_MODEL +{ + Buttons = WB_YES_NO ; + DefButton = WB_DEF_NO ; + Message [ en-US ] = "Deleting the model '$MODELNAME' affects all controls currently bound to this model.\nDo you really want to delete this model?" ; +}; + +QueryBox RID_QRY_REMOVE_INSTANCE +{ + Buttons = WB_YES_NO ; + DefButton = WB_DEF_NO ; + Message [ en-US ] = "Deleting the instance '$INSTANCENAME' affects all controls currently bound to this instance.\nDo you really want to delete this instance?" ; +}; + +QueryBox RID_QRY_REMOVE_ELEMENT +{ + Buttons = WB_YES_NO ; + DefButton = WB_DEF_NO ; + Message [ en-US ] = "Deleting the element '$ELEMENTNAME' affects all controls currently bound to this element.\nDo you really want to delete this element?" ; +}; + +QueryBox RID_QRY_REMOVE_ATTRIBUTE +{ + Buttons = WB_YES_NO ; + DefButton = WB_DEF_NO ; + Message [ en-US ] = "Do you really want to delete the attribute '$ATTRIBUTENAME'?" ; +}; + +QueryBox RID_QRY_REMOVE_SUBMISSION +{ + Buttons = WB_YES_NO ; + DefButton = WB_DEF_NO ; + Message [ en-US ] = "Deleting the submission '$SUBMISSIONNAME' affects all controls currently bound to this submission.\n\nDo you really want to delete this submission?" ; +}; + +QueryBox RID_QRY_REMOVE_BINDING +{ + Buttons = WB_YES_NO ; + DefButton = WB_DEF_NO ; + Message [ en-US ] = "Deleting the binding '$BINDINGNAME' affects all controls currently bound to this binding.\n\nDo you really want to delete this binding?" ; +}; + +MessBox RID_QRY_LINK_WARNING +{ + Buttons = 0 ; + Message [ en-US ] = "This instance is linked with the form.\n\nThe changes you make to this instance will be lost when the form is reloaded.\n\nHow do you want to proceed?" ; +}; + +ErrorBox RID_ERR_INVALID_XMLNAME +{ + Buttons = WB_OK ; + Message [ en-US ] = "The name '%1' is not valid in XML. Please enter a different name." ; +}; + +ErrorBox RID_ERR_INVALID_XMLPREFIX +{ + Buttons = WB_OK ; + Message [ en-US ] = "The prefix '%1' is not valid in XML. Please enter a different prefix." ; +}; + +ErrorBox RID_ERR_DOUBLE_MODELNAME +{ + Buttons = WB_OK ; + Message [ en-US ] = "The name '%1' already exists. Please enter a new name." ; +}; + +ErrorBox RID_ERR_EMPTY_SUBMISSIONNAME +{ + Buttons = WB_OK ; + Message [ en-US ] = "The submission must have a name." ; +}; + +ModalDialog RID_SVXDLG_ADD_DATAITEM +{ + HelpID = HID_XFORMS_ADDDATAITEM_DLG ; + OutputSize = TRUE ; + SVLook = TRUE ; + Size = MAP_APPFONT ( 180 , 186 ) ; + Moveable = TRUE ; + FixedLine FL_ITEM + { + Pos = MAP_APPFONT ( 4 , 3 ) ; + Size = MAP_APPFONT ( 172 , 8 ) ; + Text [ en-US ] = "Item" ; + }; + FixedText FT_NAME + { + Pos = MAP_APPFONT ( 6 , 15 ) ; + Size = MAP_APPFONT ( 69 , 8 ) ; + LeftLabel = TRUE ; + Text [ en-US ] = "~Name" ; + }; + Edit ED_NAME + { + Pos = MAP_APPFONT ( 78 , 14 ) ; + Size = MAP_APPFONT ( 96 , 12 ) ; + Border = TRUE ; + }; + FixedText FT_DEFAULT + { + Pos = MAP_APPFONT ( 6 , 30 ) ; + Size = MAP_APPFONT ( 69 , 8 ) ; + LeftLabel = TRUE ; + Text [ en-US ] = "~Default Value" ; + }; + Edit ED_DEFAULT + { + Pos = MAP_APPFONT ( 78 , 29 ) ; + Size = MAP_APPFONT ( 96 , 12 ) ; + Border = TRUE ; + }; + PushButton PB_DEFAULT + { + Pos = MAP_APPFONT ( 160 , 29 ) ; + Size = MAP_APPFONT ( 14 , 14 ) ; + TabStop = TRUE ; + Hide = TRUE ; + Text = "..." ; + }; + FixedLine FL_SETTINGS + { + Pos = MAP_APPFONT ( 4 , 44 ) ; + Size = MAP_APPFONT ( 172 , 8 ) ; + Text [ en-US ] = "Settings" ; + }; + FixedText FT_DATATYPE + { + Pos = MAP_APPFONT ( 6 , 56 ) ; + Size = MAP_APPFONT ( 69 , 8 ) ; + LeftLabel = TRUE ; + Text [ en-US ] = "~Data Type" ; + }; + ListBox LB_DATATYPE + { + Pos = MAP_APPFONT ( 78 , 55 ) ; + Size = MAP_APPFONT ( 96 , 45 ) ; + Border = TRUE ; + DropDown = TRUE; + }; + CheckBox CB_REQUIRED + { + Pos = MAP_APPFONT ( 6 , 72 ) ; + Size = MAP_APPFONT ( 69 , 10 ) ; + TabStop = TRUE ; + Text [ en-US ] = "~Required" ; + }; + PushButton PB_REQUIRED + { + Pos = MAP_APPFONT ( 78 , 70 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + Text [ en-US ] = "Condition" ; + }; + CheckBox CB_RELEVANT + { + Pos = MAP_APPFONT ( 6 , 89 ) ; + Size = MAP_APPFONT ( 69 , 10 ) ; + TabStop = TRUE ; + Text [ en-US ] = "R~elevant" ; + }; + PushButton PB_RELEVANT + { + Pos = MAP_APPFONT ( 78 , 87 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + Text [ en-US ] = "Condition" ; + }; + CheckBox CB_CONSTRAINT + { + Pos = MAP_APPFONT ( 6 , 106 ) ; + Size = MAP_APPFONT ( 69 , 10 ) ; + TabStop = TRUE ; + Text [ en-US ] = "~Constraint" ; + }; + PushButton PB_CONSTRAINT + { + Pos = MAP_APPFONT ( 78 , 104 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + Text [ en-US ] = "Condition" ; + }; + CheckBox CB_READONLY + { + Pos = MAP_APPFONT ( 6 , 123 ) ; + Size = MAP_APPFONT ( 69 , 10 ) ; + TabStop = TRUE ; + Text [ en-US ] = "Read-~only" ; + }; + PushButton PB_READONLY + { + Pos = MAP_APPFONT ( 78 , 121 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + Text [ en-US ] = "Condition" ; + }; + CheckBox CB_CALCULATE + { + Pos = MAP_APPFONT ( 6 , 140 ) ; + Size = MAP_APPFONT ( 69 , 10 ) ; + TabStop = TRUE ; + Text [ en-US ] = "Calc~ulate" ; + }; + PushButton PB_CALCULATE + { + Pos = MAP_APPFONT ( 78 , 138 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + Text [ en-US ] = "Condition" ; + }; + FixedLine FL_DATANAV_BTN + { + Pos = MAP_APPFONT ( 4 , 155 ) ; + Size = MAP_APPFONT ( 172 , 8 ) ; + }; + OKButton BTN_DATANAV_OK + { + Pos = MAP_APPFONT ( 15 , 166 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + DefButton = TRUE ; + }; + CancelButton BTN_DATANAV_ESC + { + Pos = MAP_APPFONT ( 68 , 166 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + }; + HelpButton BTN_DATANAV_HELP + { + Pos = MAP_APPFONT ( 124 , 166 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + }; + String STR_FIXEDLINE_ELEMENT + { + Text [ en-US ] = "Element" ; + }; + String STR_FIXEDLINE_ATTRIBUTE + { + Text [ en-US ] = "Attribute" ; + }; + String STR_FIXEDLINE_BINDING + { + Text [ en-US ] = "Binding" ; + }; + String STR_FIXEDTEXT_BINDING + { + Text [ en-US ] = "Binding expression" ; + }; +}; + +Menu RID_MENU_DATANAVIGATOR +{ + ItemList = + { + // MID_INSERT_CONTROL not implemented, yet (#i99890#) + /*MenuItem + { + Identifier = MID_INSERT_CONTROL ; + HelpId = HID_XFORMS_MID_INSERT_CONTROL ; + Text [ en-US ] = "Insert Control" ; + }; + MenuItem + { + Separator = TRUE; + };*/ + MenuItem + { + Identifier = TBI_ITEM_ADD ; + HelpId = HID_XFORMS_TOOLBOX_ITEM_ADD ; + Text [ en-US ] = "Add Item" ; + }; + MenuItem + { + Identifier = TBI_ITEM_ADD_ELEMENT ; + HelpId = HID_XFORMS_TOOLBOX_ITEM_ADD_ELEMENT ; + Text [ en-US ] = "Add Element" ; + }; + MenuItem + { + Identifier = TBI_ITEM_ADD_ATTRIBUTE ; + HelpId = HID_XFORMS_TOOLBOX_ITEM_ADD_ATTRIBUTE ; + Text [ en-US ] = "Add Attribute" ; + }; + MenuItem + { + Identifier = TBI_ITEM_EDIT ; + HelpId = HID_XFORMS_TOOLBOX_ITEM_EDIT ; + Text [ en-US ] = "Edit" ; + }; + MenuItem + { + Separator = TRUE; + }; + MenuItem + { + Identifier = TBI_ITEM_REMOVE ; + HelpId = HID_XFORMS_TOOLBOX_ITEM_REMOVE ; + Text [ en-US ] = "Delete" ; + }; + }; +}; + +ModalDialog RID_SVXDLG_ADD_CONDITION +{ + HelpID = HID_XFORMS_ADDCONDITION_DLG ; + OutputSize = TRUE ; + SVLook = TRUE ; + Size = MAP_APPFONT ( 210 , 150 ) ; + Text [ en-US ] = "Add Condition" ; + Moveable = TRUE ; + FixedText FT_CONDITION + { + Pos = MAP_APPFONT ( 6 , 3 ) ; + Size = MAP_APPFONT ( 198 , 8 ) ; + LeftLabel = TRUE ; + Text [ en-US ] = "~Condition" ; + }; + MultiLineEdit ED_CONDITION + { + Border = TRUE ; + Pos = MAP_APPFONT ( 6 , 14 ) ; + Size = MAP_APPFONT ( 198 , 34 ) ; + TabStop = TRUE ; + Left = TRUE ; + IgnoreTab = TRUE; + }; + FixedText FT_RESULT + { + Pos = MAP_APPFONT ( 6 , 51 ) ; + Size = MAP_APPFONT ( 198 , 8 ) ; + LeftLabel = TRUE ; + Text [ en-US ] = "~Result" ; + }; + FixedText FT_RESULT_PREVIEW + { + Pos = MAP_APPFONT ( 6 , 62 ) ; + Size = MAP_APPFONT ( 198 , 34 ) ; + Border = TRUE; + TabStop = TRUE ; + Left = TRUE ; + WordBreak = TRUE ; + }; + PushButton PB_EDIT_NAMESPACES + { + Pos = MAP_APPFONT ( 132 , 102 ) ; + Size = MAP_APPFONT ( 72 , 14 ) ; + TabStop = TRUE ; + Text [ en-US ] = "~Edit Namespaces..." ; + }; + FixedLine FL_DATANAV_BTN + { + Pos = MAP_APPFONT ( 4 , 119 ) ; + Size = MAP_APPFONT ( 202 , 8 ) ; + }; + OKButton BTN_DATANAV_OK + { + Pos = MAP_APPFONT ( 45 , 130 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + DefButton = TRUE ; + }; + CancelButton BTN_DATANAV_ESC + { + Pos = MAP_APPFONT ( 98 , 130 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + }; + HelpButton BTN_DATANAV_HELP + { + Pos = MAP_APPFONT ( 154 , 130 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + }; +}; + +ModalDialog RID_SVXDLG_NAMESPACE_ITEM +{ + HelpID = HID_XFORMS_NAMESPACEITEM_DLG ; + OutputSize = TRUE ; + SVLook = TRUE ; + Size = MAP_APPFONT ( 240 , 120 ) ; + Text [ en-US ] = "Namespaces for Forms" ; + Moveable = TRUE ; + FixedText FT_NAMESPACES + { + Pos = MAP_APPFONT ( 6 , 3 ) ; + Size = MAP_APPFONT ( 228 , 8 ) ; + LeftLabel = TRUE ; + Text [ en-US ] = "~Namespaces" ; + }; + Control LB_NAMESPACES + { + HelpId = HID_XFORMS_NAMESPACEITEM_LIST; + Pos = MAP_APPFONT ( 6 , 14 ) ; + Size = MAP_APPFONT ( 175 , 72 ) ; + Border = TRUE ; + TabStop = TRUE ; + }; + PushButton PB_ADD_NAMESPACE + { + Pos = MAP_APPFONT ( 184 , 14 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + Text [ en-US ] = "~Add..." ; + }; + PushButton PB_EDIT_NAMESPACE + { + Pos = MAP_APPFONT ( 184 , 31 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + Text [ en-US ] = "~Edit..." ; + }; + PushButton PB_DELETE_NAMESPACE + { + Pos = MAP_APPFONT ( 184 , 48 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + Text [ en-US ] = "~Delete" ; + }; + FixedLine FL_DATANAV_BTN + { + Pos = MAP_APPFONT ( 4 , 89 ) ; + Size = MAP_APPFONT ( 232 , 8 ) ; + }; + OKButton BTN_DATANAV_OK + { + Pos = MAP_APPFONT ( 75 , 100 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + DefButton = TRUE ; + }; + CancelButton BTN_DATANAV_ESC + { + Pos = MAP_APPFONT ( 128 , 100 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + }; + HelpButton BTN_DATANAV_HELP + { + Pos = MAP_APPFONT ( 184 , 100 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + }; + String STR_HEADER_PREFIX + { + Text [ en-US ] = "Prefix" ; + }; + String STR_HEADER_URL + { + Text [ en-US ] = "URL" ; + }; +}; + +ModalDialog RID_SVXDLG_MANAGE_NAMESPACE +{ + HelpID = HID_XFORMS_MANAGENAMESPACE_DLG ; + OutputSize = TRUE ; + SVLook = TRUE ; + Size = MAP_APPFONT ( 210 , 60 ) ; + Text [ en-US ] = "Add Namespace" ; + Moveable = TRUE ; + FixedText FT_PREFIX + { + Pos = MAP_APPFONT ( 6 , 3 ) ; + Size = MAP_APPFONT ( 45 , 8 ) ; + LeftLabel = TRUE ; + Text [ en-US ] = "~Prefix" ; + }; + Edit ED_PREFIX + { + Pos = MAP_APPFONT ( 6 , 14 ) ; + Size = MAP_APPFONT ( 45 , 12 ) ; + Border = TRUE; + }; + FixedText FT_URL + { + Pos = MAP_APPFONT ( 54 , 3 ) ; + Size = MAP_APPFONT ( 150 , 8 ) ; + LeftLabel = TRUE ; + Text [ en-US ] = "~URL" ; + }; + Edit ED_URL + { + Pos = MAP_APPFONT ( 54 , 14 ) ; + Size = MAP_APPFONT ( 150 , 12 ) ; + Border = TRUE; + }; + FixedLine FL_DATANAV_BTN + { + Pos = MAP_APPFONT ( 4 , 29 ) ; + Size = MAP_APPFONT ( 202 , 8 ) ; + }; + OKButton BTN_DATANAV_OK + { + Pos = MAP_APPFONT ( 45 , 40 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + DefButton = TRUE ; + }; + CancelButton BTN_DATANAV_ESC + { + Pos = MAP_APPFONT ( 98 , 40 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + }; + HelpButton BTN_DATANAV_HELP + { + Pos = MAP_APPFONT ( 154 , 40 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + }; + String STR_EDIT_TEXT + { + Text [ en-US ] = "Edit Namespace" ; + }; +}; + +ModalDialog RID_SVXDLG_ADD_SUBMISSION +{ + HelpID = HID_XFORMS_ADDSUBMISSION_DLG ; + OutputSize = TRUE ; + SVLook = TRUE ; + Size = MAP_APPFONT ( 180 , 136 ) ; + Text [ en-US ] = "Add Submission" ; + Moveable = TRUE ; + FixedLine FL_SUBMISSION + { + Pos = MAP_APPFONT ( 4 , 3 ) ; + Size = MAP_APPFONT ( 172 , 8 ) ; + Text [ en-US ] = "Submission" ; + }; + FixedText FT_SUBMIT_NAME + { + Pos = MAP_APPFONT ( 6 , 16 ) ; + Size = MAP_APPFONT ( 69 , 8 ) ; + LeftLabel = TRUE ; + Text [ en-US ] = "~Name" ; + }; + Edit ED_SUBMIT_NAME + { + Pos = MAP_APPFONT ( 78 , 14 ) ; + Size = MAP_APPFONT ( 96 , 12 ) ; + Border = TRUE ; + }; + FixedText FT_SUBMIT_ACTION + { + Pos = MAP_APPFONT ( 6 , 31 ) ; + Size = MAP_APPFONT ( 69 , 8 ) ; + LeftLabel = TRUE ; + Text [ en-US ] = "~Action" ; + }; + Edit ED_SUBMIT_ACTION + { + Pos = MAP_APPFONT ( 78 , 29 ) ; + Size = MAP_APPFONT ( 96 , 12 ) ; + Border = TRUE ; + }; + FixedText FT_SUBMIT_METHOD + { + Pos = MAP_APPFONT ( 6 , 46 ) ; + Size = MAP_APPFONT ( 69 , 8 ) ; + LeftLabel = TRUE ; + Text [ en-US ] = "~Method" ; + }; + ListBox LB_SUBMIT_METHOD + { + Pos = MAP_APPFONT ( 78 , 44 ) ; + Size = MAP_APPFONT ( 96 , 51 ) ; + Border = TRUE ; + DropDown = TRUE; + }; + FixedText FT_SUBMIT_REF + { + Pos = MAP_APPFONT ( 6 , 62 ) ; + Size = MAP_APPFONT ( 69 , 8 ) ; + LeftLabel = TRUE ; + Text [ en-US ] = "Binding e~xpression" ; + }; + Edit ED_SUBMIT_REF + { + Pos = MAP_APPFONT ( 78 , 60 ) ; + Size = MAP_APPFONT ( 79, 12 ) ; + Border = TRUE ; + }; + PushButton PB_SUBMIT_REF + { + Pos = MAP_APPFONT ( 159 , 59 ) ; + Size = MAP_APPFONT ( 14 , 14 ) ; + TabStop = TRUE ; + Text [ en-US ] = "~..." ; + }; + FixedText FT_SUBMIT_BIND + { + Pos = MAP_APPFONT ( 6 , 77 ) ; + Size = MAP_APPFONT ( 69 , 8 ) ; + LeftLabel = TRUE ; + Text [ en-US ] = "~Binding" ; + }; + ListBox LB_SUBMIT_BIND + { + Pos = MAP_APPFONT ( 78 , 75 ) ; + Size = MAP_APPFONT ( 96 , 51 ) ; + Border = TRUE ; + DropDown = TRUE; + }; + FixedText FT_SUBMIT_REPLACE + { + Pos = MAP_APPFONT ( 6 , 92 ) ; + Size = MAP_APPFONT ( 69 , 8 ) ; + LeftLabel = TRUE ; + Text [ en-US ] = "~Replace" ; + }; + ListBox LB_SUBMIT_REPLACE + { + Pos = MAP_APPFONT ( 78 , 90 ) ; + Size = MAP_APPFONT ( 96 , 51 ) ; + Border = TRUE ; + DropDown = TRUE; + }; + FixedLine FL_DATANAV_BTN + { + Pos = MAP_APPFONT ( 4 , 105 ) ; + Size = MAP_APPFONT ( 172 , 8 ) ; + }; + OKButton BTN_DATANAV_OK + { + Pos = MAP_APPFONT ( 15 , 116 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + DefButton = TRUE ; + }; + CancelButton BTN_DATANAV_ESC + { + Pos = MAP_APPFONT ( 68 , 116 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + }; + HelpButton BTN_DATANAV_HELP + { + Pos = MAP_APPFONT ( 124 , 116 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + }; + + String STR_METHOD_POST + { + Text [ en-US ] = "Post" ; + }; + String STR_METHOD_PUT + { + Text [ en-US ] = "Put" ; + }; + String STR_METHOD_GET + { + Text [ en-US ] = "Get" ; + }; + String STR_REPLACE_NONE + { + Text [ en-US ] = "None" ; + }; + String STR_REPLACE_INST + { + Text [ en-US ] = "Instance" ; + }; + String STR_REPLACE_DOC + { + Text [ en-US ] = "Document" ; + }; +}; + +ModalDialog RID_SVXDLG_ADD_MODEL +{ + HelpID = HID_XFORMS_ADDMODEL_DLG ; + OutputSize = TRUE ; + SVLook = TRUE ; + Size = MAP_APPFONT ( 180 , 82 ) ; + Text [ en-US ] = "Add Model" ; + Moveable = TRUE ; + FixedLine FL_INSTANCE + { + Pos = MAP_APPFONT ( 4 , 3 ) ; + Size = MAP_APPFONT ( 172 , 8 ) ; + Text [ en-US ] = "Model" ; + }; + FixedText FT_INST_NAME + { + Pos = MAP_APPFONT ( 6 , 14 ) ; + Size = MAP_APPFONT ( 51 , 12 ) ; + LeftLabel = TRUE ; + VCenter = TRUE; + Text [ en-US ] = "~Name" ; + }; + Edit ED_INST_NAME + { + Pos = MAP_APPFONT ( 60 , 14 ) ; + Size = MAP_APPFONT ( 114 , 12 ) ; + Border = TRUE ; + }; + CheckBox CB_MODIFIES_DOCUMENT + { + Pos = MAP_APPFONT( 6, 32 ); + Size = MAP_APPFONT( 168, 16 ); + Top = TRUE; + WordBreak = TRUE; + + Text [ en-US ] = "Model data updates change document's modification status"; + }; + FixedLine FL_DATANAV_BTN + { + Pos = MAP_APPFONT ( 4 , 51 ) ; + Size = MAP_APPFONT ( 172 , 8 ) ; + }; + OKButton BTN_DATANAV_OK + { + Pos = MAP_APPFONT ( 15 , 62 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + DefButton = TRUE ; + }; + CancelButton BTN_DATANAV_ESC + { + Pos = MAP_APPFONT ( 68 , 62 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + }; + HelpButton BTN_DATANAV_HELP + { + Pos = MAP_APPFONT ( 124 , 62 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + }; + String STR_EDIT_TEXT + { + Text [ en-US ] = "Edit Model" ; + }; +}; + +ModalDialog RID_SVXDLG_ADD_INSTANCE +{ + HelpID = HID_XFORMS_ADDINSTANCE_DLG ; + OutputSize = TRUE ; + SVLook = TRUE ; + Size = MAP_APPFONT ( 210 , 88 ) ; + Text [ en-US ] = "Add Instance" ; + Moveable = TRUE ; + FixedLine FL_INSTANCE + { + Pos = MAP_APPFONT ( 4 , 3 ) ; + Size = MAP_APPFONT ( 202 , 8 ) ; + Text [ en-US ] = "Instance" ; + }; + FixedText FT_INST_NAME + { + Pos = MAP_APPFONT ( 6 , 15 ) ; + Size = MAP_APPFONT ( 51 , 8 ) ; + LeftLabel = TRUE ; + Text [ en-US ] = "~Name" ; + }; + Edit ED_INST_NAME + { + Pos = MAP_APPFONT ( 60 , 14 ) ; + Size = MAP_APPFONT ( 144 , 12 ) ; + Border = TRUE ; + }; + FixedText FT_INST_URL + { + Pos = MAP_APPFONT ( 6 , 30 ) ; + Size = MAP_APPFONT ( 51 , 8 ) ; + LeftLabel = TRUE ; + Text [ en-US ] = "~URL" ; + }; + ComboBox ED_INST_URL + { + Pos = MAP_APPFONT ( 60 , 29 ) ; + Size = MAP_APPFONT ( 127 , 48 ) ; + DropDown = TRUE ; + Border = TRUE ; + }; + PushButton PB_FILEPICKER + { + Pos = MAP_APPFONT ( 190 , 28 ) ; + Size = MAP_APPFONT ( 14 , 14 ) ; + TabStop = TRUE ; + Text = "~..." ; + }; + CheckBox CB_INST_LINKINST + { + Pos = MAP_APPFONT ( 6 , 44 ) ; + Size = MAP_APPFONT ( 198 , 10 ) ; + TabStop = TRUE ; + Text [ en-US ] = "~Link instance" ; + }; + FixedLine FL_DATANAV_BTN + { + Pos = MAP_APPFONT ( 4 , 57 ) ; + Size = MAP_APPFONT ( 202 , 8 ) ; + }; + OKButton BTN_DATANAV_OK + { + Pos = MAP_APPFONT ( 45 , 68 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + DefButton = TRUE ; + }; + CancelButton BTN_DATANAV_ESC + { + Pos = MAP_APPFONT ( 98 , 68 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + }; + HelpButton BTN_DATANAV_HELP + { + Pos = MAP_APPFONT ( 154 , 68 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + }; + String STR_EDIT_TEXT + { + Text [ en-US ] = "Edit Instance" ; + }; +}; + +String RID_STR_DATANAV_SUBM_PARENT +{ + Text [ en-US ] = "Submission: " ; +}; +String RID_STR_DATANAV_SUBM_ID +{ + Text [ en-US ] = "ID: " ; +}; +String RID_STR_DATANAV_SUBM_BIND +{ + Text [ en-US ] = "Binding: " ; +}; +String RID_STR_DATANAV_SUBM_REF +{ + Text [ en-US ] = "Reference: " ; +}; +String RID_STR_DATANAV_SUBM_ACTION +{ + Text [ en-US ] = "Action: " ; +}; +String RID_STR_DATANAV_SUBM_METHOD +{ + Text [ en-US ] = "Method: " ; +}; +String RID_STR_DATANAV_SUBM_REPLACE +{ + Text [ en-US ] = "Replace: " ; +}; +String RID_STR_DATANAV_ADD_ELEMENT +{ + Text [ en-US ] = "Add Element" ; +}; +String RID_STR_DATANAV_EDIT_ELEMENT +{ + Text [ en-US ] = "Edit Element" ; +}; +String RID_STR_DATANAV_REMOVE_ELEMENT +{ + Text [ en-US ] = "Delete Element" ; +}; +String RID_STR_DATANAV_ADD_ATTRIBUTE +{ + Text [ en-US ] = "Add Attribute" ; +}; +String RID_STR_DATANAV_EDIT_ATTRIBUTE +{ + Text [ en-US ] = "Edit Attribute" ; +}; +String RID_STR_DATANAV_REMOVE_ATTRIBUTE +{ + Text [ en-US ] = "Delete Attribute" ; +}; +String RID_STR_DATANAV_ADD_BINDING +{ + Text [ en-US ] = "Add Binding" ; +}; +String RID_STR_DATANAV_EDIT_BINDING +{ + Text [ en-US ] = "Edit Binding" ; +}; +String RID_STR_DATANAV_REMOVE_BINDING +{ + Text [ en-US ] = "Delete Binding" ; +}; +String RID_STR_DATANAV_ADD_SUBMISSION +{ + Text [ en-US ] = "Add Submission" ; +}; +String RID_STR_DATANAV_EDIT_SUBMISSION +{ + Text [ en-US ] = "Edit Submission" ; +}; +String RID_STR_DATANAV_REMOVE_SUBMISSION +{ + Text [ en-US ] = "Delete Submission" ; +}; +String RID_STR_DATANAV_LINKWARN_BUTTON +{ + Text [ en-US ] = "~Edit" ; +}; + diff --git a/svx/source/form/dbcharsethelper.cxx b/svx/source/form/dbcharsethelper.cxx new file mode 100644 index 000000000000..f77e95b49a5e --- /dev/null +++ b/svx/source/form/dbcharsethelper.cxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include "svx/dbcharsethelper.hxx" + +//........................................................................ +namespace svxform +{ +//........................................................................ + + //==================================================================== + //= ODataAccessCharsetHelper + //==================================================================== + //-------------------------------------------------------------------- + ODataAccessCharsetHelper::ODataAccessCharsetHelper( ) + { + } + + //-------------------------------------------------------------------- + bool ODataAccessCharsetHelper::ensureLoaded() const + { + if ( !ODbtoolsClient::ensureLoaded() ) + return false; + m_xCharsetHelper = getFactory()->createCharsetHelper( ); + return m_xCharsetHelper.is(); + } + +//........................................................................ +} // namespace svxform +//........................................................................ + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/dbtoolsclient.cxx b/svx/source/form/dbtoolsclient.cxx new file mode 100644 index 000000000000..62d283ab3a7a --- /dev/null +++ b/svx/source/form/dbtoolsclient.cxx @@ -0,0 +1,368 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbc/XDataSource.hpp> +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> +#include <com/sun/star/sdb/SQLContext.hpp> +#include "svx/dbtoolsclient.hxx" +#include <osl/diagnose.h> +#include <connectivity/formattedcolumnvalue.hxx> + +//........................................................................ +namespace svxform +{ +//........................................................................ + + using namespace ::connectivity::simple; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::sdb; + using namespace ::com::sun::star::container; + + //==================================================================== + //= ODbtoolsClient + //==================================================================== + ::osl::Mutex ODbtoolsClient::s_aMutex; + sal_Int32 ODbtoolsClient::s_nClients = 0; + oslModule ODbtoolsClient::s_hDbtoolsModule = NULL; + createDataAccessToolsFactoryFunction + ODbtoolsClient::s_pFactoryCreationFunc = NULL; + + //-------------------------------------------------------------------- + ODbtoolsClient::ODbtoolsClient() + { + m_bCreateAlready = FALSE; + } + + //-------------------------------------------------------------------- + bool ODbtoolsClient::ensureLoaded() const + { + if ( !m_bCreateAlready ) + { + m_bCreateAlready = true; + + registerClient(); + if ( s_pFactoryCreationFunc ) + { // loading the lib succeeded + void* pUntypedFactory = (*s_pFactoryCreationFunc)(); + IDataAccessToolsFactory* pDBTFactory = static_cast< IDataAccessToolsFactory* >( pUntypedFactory ); + OSL_ENSURE( pDBTFactory, "ODbtoolsClient::ODbtoolsClient: no factory returned!" ); + if ( pDBTFactory ) + { + m_xDataAccessFactory = pDBTFactory; + // by definition, the factory was aquired once + m_xDataAccessFactory->release(); + } + } + } + return m_xDataAccessFactory.is(); + } + + //-------------------------------------------------------------------- + ODbtoolsClient::~ODbtoolsClient() + { + // clear the factory _before_ revoking the client + // (the revocation may unload the DBT lib) + m_xDataAccessFactory = NULL; + // revoke the client + if ( m_bCreateAlready ) + revokeClient(); + } + + //-------------------------------------------------------------------- + extern "C" { static void SAL_CALL thisModule() {} } + + void ODbtoolsClient::registerClient() + { + ::osl::MutexGuard aGuard(s_aMutex); + if (1 == ++s_nClients) + { + OSL_ENSURE(NULL == s_hDbtoolsModule, "ODbtoolsClient::registerClient: inconsistence: already have a module!"); + OSL_ENSURE(NULL == s_pFactoryCreationFunc, "ODbtoolsClient::registerClient: inconsistence: already have a factory function!"); + + const ::rtl::OUString sModuleName(RTL_CONSTASCII_USTRINGPARAM( + SVLIBRARY( "dbtools" )) + ); + + // load the dbtools library + s_hDbtoolsModule = osl_loadModuleRelative( + &thisModule, sModuleName.pData, 0); + OSL_ENSURE(NULL != s_hDbtoolsModule, "ODbtoolsClient::registerClient: could not load the dbtools library!"); + if (NULL != s_hDbtoolsModule) + { + // get the symbol for the method creating the factory + const ::rtl::OUString sFactoryCreationFunc( RTL_CONSTASCII_USTRINGPARAM("createDataAccessToolsFactory") ); + // reinterpret_cast<createDataAccessToolsFactoryFunction> + s_pFactoryCreationFunc = (createDataAccessToolsFactoryFunction)( + osl_getFunctionSymbol(s_hDbtoolsModule, sFactoryCreationFunc.pData)); + + if (NULL == s_pFactoryCreationFunc) + { // did not find the symbol + OSL_ENSURE(sal_False, "ODbtoolsClient::registerClient: could not find the symbol for creating the factory!"); + osl_unloadModule(s_hDbtoolsModule); + s_hDbtoolsModule = NULL; + } + } + } + } + + //-------------------------------------------------------------------- + void ODbtoolsClient::revokeClient() + { + ::osl::MutexGuard aGuard(s_aMutex); + if (0 == --s_nClients) + { + s_pFactoryCreationFunc = NULL; + if (s_hDbtoolsModule) + osl_unloadModule(s_hDbtoolsModule); + s_hDbtoolsModule = NULL; + } + + OSL_ENSURE(s_nClients >= 0,"Illegall call of revokeClient()"); + } + + //==================================================================== + //= OStaticDataAccessTools + //==================================================================== + //-------------------------------------------------------------------- + OStaticDataAccessTools::OStaticDataAccessTools() + { + } + + //-------------------------------------------------------------------- + + bool OStaticDataAccessTools::ensureLoaded() const + { + if ( !ODbtoolsClient::ensureLoaded() ) + return false; + m_xDataAccessTools = getFactory()->getDataAccessTools(); + return m_xDataAccessTools.is(); + } + + //-------------------------------------------------------------------- + Reference< XNumberFormatsSupplier > OStaticDataAccessTools::getNumberFormats(const Reference< XConnection>& _rxConn, sal_Bool _bAllowDefault) const + { + Reference< XNumberFormatsSupplier > xReturn; + if ( ensureLoaded() ) + xReturn = m_xDataAccessTools->getNumberFormats(_rxConn, _bAllowDefault); + return xReturn; + } + + //-------------------------------------------------------------------- + sal_Int32 OStaticDataAccessTools::getDefaultNumberFormat( const Reference< XPropertySet >& _xColumn, const Reference< XNumberFormatTypes >& _xTypes, const Locale& _rLocale ) + { + sal_Int32 nReturn = 0; + if ( ensureLoaded() ) + nReturn = m_xDataAccessTools->getDefaultNumberFormat( _xColumn, _xTypes, _rLocale ); + return nReturn; + } + + //-------------------------------------------------------------------- + Reference< XConnection> OStaticDataAccessTools::getConnection_withFeedback(const ::rtl::OUString& _rDataSourceName, + const ::rtl::OUString& _rUser, const ::rtl::OUString& _rPwd, const Reference< XMultiServiceFactory>& _rxFactory) const + SAL_THROW ( (SQLException) ) + { + Reference< XConnection > xReturn; + if ( ensureLoaded() ) + xReturn = m_xDataAccessTools->getConnection_withFeedback(_rDataSourceName, _rUser, _rPwd, _rxFactory); + return xReturn; + } + + //-------------------------------------------------------------------- + Reference< XConnection > OStaticDataAccessTools::connectRowset( const Reference< XRowSet >& _rxRowSet, + const Reference< XMultiServiceFactory >& _rxFactory, sal_Bool _bSetAsActiveConnection ) const + SAL_THROW ( ( SQLException, WrappedTargetException, RuntimeException ) ) + { + Reference< XConnection > xReturn; + if ( ensureLoaded() ) + xReturn = m_xDataAccessTools->connectRowset( _rxRowSet, _rxFactory, _bSetAsActiveConnection ); + return xReturn; + } + + //-------------------------------------------------------------------- + Reference< XConnection > OStaticDataAccessTools::getRowSetConnection(const Reference< XRowSet >& _rxRowSet) const SAL_THROW ( (RuntimeException) ) + { + Reference< XConnection > xReturn; + if ( ensureLoaded() ) + xReturn = m_xDataAccessTools->getRowSetConnection(_rxRowSet); + return xReturn; + } + + //-------------------------------------------------------------------- + void OStaticDataAccessTools::TransferFormComponentProperties(const Reference< XPropertySet>& _rxOld, + const Reference< XPropertySet>& _rxNew, const Locale& _rLocale) const + { + if ( ensureLoaded() ) + m_xDataAccessTools->TransferFormComponentProperties(_rxOld, _rxNew, _rLocale); + } + + //-------------------------------------------------------------------- + ::rtl::OUString OStaticDataAccessTools::quoteName(const ::rtl::OUString& _rQuote, const ::rtl::OUString& _rName) const + { + ::rtl::OUString sReturn; + if ( ensureLoaded() ) + sReturn = m_xDataAccessTools->quoteName(_rQuote, _rName); + return sReturn; + } + + // ------------------------------------------------ + ::rtl::OUString OStaticDataAccessTools::composeTableNameForSelect( const Reference< XConnection >& _rxConnection, const Reference< XPropertySet>& _xTable ) const + { + ::rtl::OUString sReturn; + if ( ensureLoaded() ) + sReturn = m_xDataAccessTools->composeTableNameForSelect( _rxConnection, _xTable ); + return sReturn; + } + + //-------------------------------------------------------------------- + SQLContext OStaticDataAccessTools::prependContextInfo(SQLException& _rException, const Reference< XInterface >& _rxContext, + const ::rtl::OUString& _rContextDescription, const ::rtl::OUString& _rContextDetails) const + { + SQLContext aReturn; + if ( ensureLoaded() ) + aReturn = m_xDataAccessTools->prependContextInfo(_rException, _rxContext, _rContextDescription, _rContextDetails); + return aReturn; + } + + //---------------------------------------------------------------- + Reference< XDataSource > OStaticDataAccessTools::getDataSource( const ::rtl::OUString& _rsRegisteredName, const Reference< XMultiServiceFactory>& _rxFactory ) const + { + Reference< XDataSource > xReturn; + if ( ensureLoaded() ) + xReturn = m_xDataAccessTools->getDataSource(_rsRegisteredName,_rxFactory); + return xReturn; + } + + //---------------------------------------------------------------- + sal_Bool OStaticDataAccessTools::canInsert(const Reference< XPropertySet>& _rxCursorSet) const + { + sal_Bool bRet = sal_False; + if ( ensureLoaded() ) + bRet = m_xDataAccessTools->canInsert( _rxCursorSet ); + return bRet; + } + + //---------------------------------------------------------------- + sal_Bool OStaticDataAccessTools::canUpdate(const Reference< XPropertySet>& _rxCursorSet) const + { + sal_Bool bRet = sal_False; + if ( ensureLoaded() ) + bRet = m_xDataAccessTools->canUpdate( _rxCursorSet ); + return bRet; + } + + //---------------------------------------------------------------- + sal_Bool OStaticDataAccessTools::canDelete(const Reference< XPropertySet>& _rxCursorSet) const + { + sal_Bool bRet = sal_False; + if ( ensureLoaded() ) + bRet = m_xDataAccessTools->canDelete( _rxCursorSet ); + return bRet; + } + + //---------------------------------------------------------------- + Reference< XNameAccess > OStaticDataAccessTools::getFieldsByCommandDescriptor( const Reference< XConnection >& _rxConnection, + const sal_Int32 _nCommandType, const ::rtl::OUString& _rCommand, + Reference< XComponent >& _rxKeepFieldsAlive, ::dbtools::SQLExceptionInfo* _pErrorInfo ) SAL_THROW( ( ) ) + { + Reference< XNameAccess > aFields; + if ( ensureLoaded() ) + aFields = m_xDataAccessTools->getFieldsByCommandDescriptor( _rxConnection, _nCommandType, + _rCommand, _rxKeepFieldsAlive, _pErrorInfo ); + + return aFields; + } + + //---------------------------------------------------------------- + Sequence< ::rtl::OUString > OStaticDataAccessTools::getFieldNamesByCommandDescriptor( + const Reference< XConnection >& _rxConnection, const sal_Int32 _nCommandType, + const ::rtl::OUString& _rCommand, ::dbtools::SQLExceptionInfo* _pErrorInfo ) SAL_THROW( ( ) ) + { + Sequence< ::rtl::OUString > aNames; + if ( ensureLoaded() ) + aNames = m_xDataAccessTools->getFieldNamesByCommandDescriptor( _rxConnection, _nCommandType, + _rCommand, _pErrorInfo ); + return aNames; + } + + //---------------------------------------------------------------- + bool OStaticDataAccessTools::isEmbeddedInDatabase( const Reference< XInterface >& _rxComponent, Reference< XConnection >& _rxActualConnection ) + { + bool bReturn = false; + if ( ensureLoaded() ) + bReturn = m_xDataAccessTools->isEmbeddedInDatabase( _rxComponent, _rxActualConnection ); + return bReturn; + } + + //---------------------------------------------------------------- + bool OStaticDataAccessTools::isEmbeddedInDatabase( const Reference< XInterface >& _rxComponent ) + { + bool bReturn = false; + if ( ensureLoaded() ) + { + Reference< XConnection > xDummy; + bReturn = m_xDataAccessTools->isEmbeddedInDatabase( _rxComponent, xDummy ); + } + return bReturn; + } + + //==================================================================== + //= DBToolsObjectFactory + //==================================================================== + //---------------------------------------------------------------- + DBToolsObjectFactory::DBToolsObjectFactory() + { + } + + //---------------------------------------------------------------- + DBToolsObjectFactory::~DBToolsObjectFactory() + { + } + + //---------------------------------------------------------------- + ::std::auto_ptr< ::dbtools::FormattedColumnValue > DBToolsObjectFactory::createFormattedColumnValue( + const ::comphelper::ComponentContext& _rContext, const Reference< XRowSet >& _rxRowSet, const Reference< XPropertySet >& _rxColumn ) + { + ::std::auto_ptr< ::dbtools::FormattedColumnValue > pValue; + if ( ensureLoaded() ) + pValue = getFactory()->createFormattedColumnValue( _rContext, _rxRowSet, _rxColumn ); + return pValue; + } + +//........................................................................ +} // namespace svxform +//........................................................................ + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/delayedevent.cxx b/svx/source/form/delayedevent.cxx new file mode 100644 index 000000000000..182e64788aed --- /dev/null +++ b/svx/source/form/delayedevent.cxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * +************************************************************************/ + +#include "precompiled_svx.hxx" + +#include "delayedevent.hxx" + +#include <osl/diagnose.h> +#include <vcl/svapp.hxx> + +//........................................................................ +namespace svxform +{ +//........................................................................ + + //==================================================================== + //= DelayedEvent + //==================================================================== + //-------------------------------------------------------------------- + void DelayedEvent::Call( void* _pArg ) + { + CancelPendingCall(); + OSL_POSTCOND( m_nEventId == 0, "DelayedEvent::Call: CancelPendingCall did not work!" ); + + m_nEventId = Application::PostUserEvent( LINK( this, DelayedEvent, OnCall ), _pArg ); + } + + //-------------------------------------------------------------------- + void DelayedEvent::CancelPendingCall() + { + if ( m_nEventId ) + Application::RemoveUserEvent( m_nEventId ); + m_nEventId = 0; + } + + //-------------------------------------------------------------------- + IMPL_LINK( DelayedEvent, OnCall, void*, _pArg ) + { + m_nEventId = 0; + return m_aHandler.Call( _pArg ); + } + +//........................................................................ +} // namespace svxform +//........................................................................ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/filtnav.cxx b/svx/source/form/filtnav.cxx new file mode 100644 index 000000000000..8c6bba3ace1f --- /dev/null +++ b/svx/source/form/filtnav.cxx @@ -0,0 +1,2064 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + + +#include "filtnav.hxx" +#include "fmexch.hxx" +#include "fmhelp.hrc" +#include "fmitems.hxx" +#include "fmprop.hrc" +#include "fmresids.hrc" + +/** === begin UNO includes === **/ +#include <com/sun/star/awt/XControlModel.hpp> +#include <com/sun/star/awt/XControl.hpp> +#include <com/sun/star/awt/XTextComponent.hpp> +#include <com/sun/star/form/runtime/XFormController.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/util/XNumberFormatter.hpp> +#include <com/sun/star/beans/XFastPropertySet.hpp> +/** === end UNO includes === **/ + +#include <comphelper/processfactory.hxx> +#include <svx/fmtools.hxx> +#include <comphelper/property.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/uno3.hxx> +#include <connectivity/dbtools.hxx> +#include <cppuhelper/implbase1.hxx> +#include <fmservs.hxx> +#include <fmshimp.hxx> +#include <rtl/logfile.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/objitem.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/request.hxx> +#include <svx/dialmgr.hxx> +#include <svx/fmshell.hxx> +#include <svx/svxids.hrc> +#include <tools/shl.hxx> +#include <vcl/wrkwin.hxx> +#include <tools/diagnose_ex.h> + +#include <functional> + +#define SYNC_DELAY 200 +#define DROP_ACTION_TIMER_INITIAL_TICKS 10 + // solange dauert es, bis das Scrollen anspringt +#define DROP_ACTION_TIMER_SCROLL_TICKS 3 + // in diesen Intervallen wird jeweils eine Zeile gescrollt +#define DROP_ACTION_TIMER_TICK_BASE 10 + // das ist die Basis, mit der beide Angaben multipliziert werden (in ms) + +using namespace ::svxform; +using namespace ::connectivity::simple; +using namespace ::connectivity; + + +//........................................................................ +namespace svxform +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::lang::XMultiServiceFactory; + using ::com::sun::star::awt::TextEvent; + using ::com::sun::star::container::XIndexAccess; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::form::runtime::XFormController; + using ::com::sun::star::form::runtime::XFilterController; + using ::com::sun::star::form::runtime::XFilterControllerListener; + using ::com::sun::star::form::runtime::FilterEvent; + using ::com::sun::star::lang::EventObject; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::form::XForm; + using ::com::sun::star::container::XChild; + using ::com::sun::star::awt::XControl; + using ::com::sun::star::sdbc::XConnection; + using ::com::sun::star::util::XNumberFormatsSupplier; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::util::XNumberFormatter; + using ::com::sun::star::sdbc::XRowSet; + using ::com::sun::star::lang::Locale; + using ::com::sun::star::sdb::SQLContext; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::awt::XTextComponent; + using ::com::sun::star::uno::Sequence; + /** === end UNO using === **/ + +//======================================================================== +OFilterItemExchange::OFilterItemExchange() +{ +} + +//------------------------------------------------------------------------ +void OFilterItemExchange::AddSupportedFormats() +{ + AddFormat(getFormatId()); +} + +//------------------------------------------------------------------------ +sal_uInt32 OFilterItemExchange::getFormatId() +{ + static sal_uInt32 s_nFormat = (sal_uInt32)-1; + if ((sal_uInt32)-1 == s_nFormat) + { + s_nFormat = SotExchange::RegisterFormatName(String::CreateFromAscii("application/x-openoffice;windows_formatname=\"form.FilterControlExchange\"")); + DBG_ASSERT((sal_uInt32)-1 != s_nFormat, "OFilterExchangeHelper::getFormatId: bad exchange id!"); + } + return s_nFormat; +} + +//------------------------------------------------------------------------ +OLocalExchange* OFilterExchangeHelper::createExchange() const +{ + return new OFilterItemExchange; +} + +//======================================================================== +TYPEINIT0(FmFilterData); +Image FmFilterData::GetImage( BmpColorMode /*_eMode*/ ) const +{ + return Image(); +} + +//======================================================================== +TYPEINIT1(FmParentData, FmFilterData); +//------------------------------------------------------------------------ +FmParentData::~FmParentData() +{ + for (::std::vector<FmFilterData*>::const_iterator i = m_aChildren.begin(); + i != m_aChildren.end(); i++) + delete (*i); +} + +//======================================================================== +TYPEINIT1(FmFormItem, FmParentData); +//------------------------------------------------------------------------ +Image FmFormItem::GetImage( BmpColorMode /* _eMode */) const +{ + static Image aImage; + + if (!aImage) + { + ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL ) ); + aImage = aNavigatorImages.GetImage( RID_SVXIMG_FORM ); + } + return aImage; +} + +//======================================================================== +TYPEINIT1(FmFilterItems, FmParentData); +//------------------------------------------------------------------------ +FmFilterItem* FmFilterItems::Find( const ::sal_Int32 _nFilterComponentIndex ) const +{ + for ( ::std::vector< FmFilterData* >::const_iterator i = m_aChildren.begin(); + i != m_aChildren.end(); + ++i + ) + { + FmFilterItem* pCondition = PTR_CAST( FmFilterItem, *i ); + DBG_ASSERT( pCondition, "FmFilterItems::Find: Wrong element in container!" ); + if ( _nFilterComponentIndex == pCondition->GetComponentIndex() ) + return pCondition; + } + return NULL; +} + +//------------------------------------------------------------------------ +Image FmFilterItems::GetImage( BmpColorMode /* _eMode */ ) const +{ + static Image aImage; + + if (!aImage) + { + ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL ) ); + aImage = aNavigatorImages.GetImage( RID_SVXIMG_FILTER ); + } + return aImage; +} + +//======================================================================== +TYPEINIT1(FmFilterItem, FmFilterData); +//------------------------------------------------------------------------ +FmFilterItem::FmFilterItem( const Reference< XMultiServiceFactory >& _rxFactory, + FmFilterItems* pParent, + const ::rtl::OUString& aFieldName, + const ::rtl::OUString& aText, + const sal_Int32 _nComponentIndex ) + :FmFilterData(_rxFactory,pParent, aText) + ,m_aFieldName(aFieldName) + ,m_nComponentIndex( _nComponentIndex ) +{ +} + +//------------------------------------------------------------------------ +Image FmFilterItem::GetImage( BmpColorMode /* _eMode */ ) const +{ + static Image aImage; + + if (!aImage) + { + ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL ) ); + aImage = aNavigatorImages.GetImage( RID_SVXIMG_FIELD ); + } + return aImage; +} + +//======================================================================== +// Hints for communicatition between model and view +//======================================================================== +class FmFilterHint : public SfxHint +{ + FmFilterData* m_pData; + +public: + TYPEINFO(); + FmFilterHint(FmFilterData* pData):m_pData(pData){} + FmFilterData* GetData() const { return m_pData; } +}; +TYPEINIT1( FmFilterHint, SfxHint ); + +//======================================================================== +class FmFilterInsertedHint : public FmFilterHint +{ + sal_Int32 m_nPos; // Position relative to the parent of the data + +public: + TYPEINFO(); + FmFilterInsertedHint(FmFilterData* pData, sal_Int32 nRelPos) + :FmFilterHint(pData) + ,m_nPos(nRelPos){} + + sal_Int32 GetPos() const { return m_nPos; } +}; +TYPEINIT1( FmFilterInsertedHint, FmFilterHint ); + +//======================================================================== +class FmFilterRemovedHint : public FmFilterHint +{ +public: + TYPEINFO(); + FmFilterRemovedHint(FmFilterData* pData) + :FmFilterHint(pData){} + +}; +TYPEINIT1( FmFilterRemovedHint, FmFilterHint ); + +//======================================================================== +class FmFilterTextChangedHint : public FmFilterHint +{ +public: + TYPEINFO(); + FmFilterTextChangedHint(FmFilterData* pData) + :FmFilterHint(pData){} + +}; +TYPEINIT1( FmFilterTextChangedHint, FmFilterHint ); + +//======================================================================== +class FilterClearingHint : public SfxHint +{ +public: + TYPEINFO(); + FilterClearingHint(){} +}; +TYPEINIT1( FilterClearingHint, SfxHint ); + +//======================================================================== +class FmFilterCurrentChangedHint : public SfxHint +{ +public: + TYPEINFO(); + FmFilterCurrentChangedHint(){} +}; +TYPEINIT1( FmFilterCurrentChangedHint, SfxHint ); + +//======================================================================== +// class FmFilterAdapter, Listener an den FilterControls +//======================================================================== +class FmFilterAdapter : public ::cppu::WeakImplHelper1< XFilterControllerListener > +{ + FmFilterModel* m_pModel; + Reference< XIndexAccess > m_xControllers; + +public: + FmFilterAdapter(FmFilterModel* pModel, const Reference< XIndexAccess >& xControllers); + +// XEventListener + virtual void SAL_CALL disposing(const EventObject& Source) throw( RuntimeException ); + +// XFilterControllerListener + virtual void SAL_CALL predicateExpressionChanged( const FilterEvent& _Event ) throw (RuntimeException); + virtual void SAL_CALL disjunctiveTermRemoved( const FilterEvent& _Event ) throw (RuntimeException); + virtual void SAL_CALL disjunctiveTermAdded( const FilterEvent& _Event ) throw (RuntimeException); + +// helpers + void dispose() throw( RuntimeException ); + + void AddOrRemoveListener( const Reference< XIndexAccess >& _rxControllers, const bool _bAdd ); + + void setText(sal_Int32 nPos, + const FmFilterItem* pFilterItem, + const ::rtl::OUString& rText); +}; + +//------------------------------------------------------------------------ +FmFilterAdapter::FmFilterAdapter(FmFilterModel* pModel, const Reference< XIndexAccess >& xControllers) + :m_pModel( pModel ) + ,m_xControllers( xControllers ) +{ + AddOrRemoveListener( m_xControllers, true ); +} + +//------------------------------------------------------------------------ +void FmFilterAdapter::dispose() throw( RuntimeException ) +{ + AddOrRemoveListener( m_xControllers, false ); +} + +//------------------------------------------------------------------------ +void FmFilterAdapter::AddOrRemoveListener( const Reference< XIndexAccess >& _rxControllers, const bool _bAdd ) +{ + for (sal_Int32 i = 0, nLen = _rxControllers->getCount(); i < nLen; ++i) + { + Reference< XIndexAccess > xElement( _rxControllers->getByIndex(i), UNO_QUERY ); + + // step down + AddOrRemoveListener( xElement, _bAdd ); + + // handle this particular controller + Reference< XFilterController > xController( xElement, UNO_QUERY ); + OSL_ENSURE( xController.is(), "FmFilterAdapter::InsertElements: no XFilterController, cannot sync data!" ); + if ( xController.is() ) + { + if ( _bAdd ) + xController->addFilterControllerListener( this ); + else + xController->removeFilterControllerListener( this ); + } + } +} + +//------------------------------------------------------------------------ +void FmFilterAdapter::setText(sal_Int32 nRowPos, + const FmFilterItem* pFilterItem, + const ::rtl::OUString& rText) +{ + FmFormItem* pFormItem = PTR_CAST( FmFormItem, pFilterItem->GetParent()->GetParent() ); + + try + { + Reference< XFilterController > xController( pFormItem->GetController(), UNO_QUERY_THROW ); + xController->setPredicateExpression( pFilterItem->GetComponentIndex(), nRowPos, rText ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + + +// XEventListener +//------------------------------------------------------------------------ +void SAL_CALL FmFilterAdapter::disposing(const EventObject& /*e*/) throw( RuntimeException ) +{ +} + +//------------------------------------------------------------------------ +namespace +{ + ::rtl::OUString lcl_getLabelName_nothrow( const Reference< XControl >& _rxControl ) + { + ::rtl::OUString sLabelName; + try + { + Reference< XControl > xControl( _rxControl, UNO_SET_THROW ); + Reference< XPropertySet > xModel( xControl->getModel(), UNO_QUERY_THROW ); + sLabelName = getLabelName( xModel ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return sLabelName; + } + + Reference< XPropertySet > lcl_getBoundField_nothrow( const Reference< XControl >& _rxControl ) + { + Reference< XPropertySet > xField; + try + { + Reference< XControl > xControl( _rxControl, UNO_SET_THROW ); + Reference< XPropertySet > xModelProps( xControl->getModel(), UNO_QUERY_THROW ); + xField.set( xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ), UNO_QUERY_THROW ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return xField; + } +} + +// XFilterControllerListener +//------------------------------------------------------------------------ +void FmFilterAdapter::predicateExpressionChanged( const FilterEvent& _Event ) throw( RuntimeException ) +{ + SolarMutexGuard aGuard; + + if ( !m_pModel ) + return; + + // the controller which sent the event + Reference< XFormController > xController( _Event.Source, UNO_QUERY_THROW ); + Reference< XFilterController > xFilterController( _Event.Source, UNO_QUERY_THROW ); + Reference< XForm > xForm( xController->getModel(), UNO_QUERY_THROW ); + + FmFormItem* pFormItem = m_pModel->Find( m_pModel->m_aChildren, xForm ); + OSL_ENSURE( pFormItem, "FmFilterAdapter::predicateExpressionChanged: don't know this form!" ); + if ( !pFormItem ) + return; + + const sal_Int32 nActiveTerm( xFilterController->getActiveTerm() ); + + FmFilterItems* pFilter = PTR_CAST( FmFilterItems, pFormItem->GetChildren()[ nActiveTerm ] ); + FmFilterItem* pFilterItem = pFilter->Find( _Event.FilterComponent ); + if ( pFilterItem ) + { + if ( _Event.PredicateExpression.getLength()) + { + pFilterItem->SetText( _Event.PredicateExpression ); + // UI benachrichtigen + FmFilterTextChangedHint aChangeHint(pFilterItem); + m_pModel->Broadcast( aChangeHint ); + } + else + { + // no text anymore so remove the condition + m_pModel->Remove(pFilterItem); + } + } + else + { + // searching the component by field name + ::rtl::OUString aFieldName( lcl_getLabelName_nothrow( xFilterController->getFilterComponent( _Event.FilterComponent ) ) ); + + pFilterItem = new FmFilterItem( m_pModel->getORB(), pFilter, aFieldName, _Event.PredicateExpression, _Event.FilterComponent ); + m_pModel->Insert(pFilter->GetChildren().end(), pFilterItem); + } + + // ensure there's one empty term in the filter, just in case the active term was previously empty + m_pModel->EnsureEmptyFilterRows( *pFormItem ); +} + +//------------------------------------------------------------------------ +void SAL_CALL FmFilterAdapter::disjunctiveTermRemoved( const FilterEvent& _Event ) throw (RuntimeException) +{ + SolarMutexGuard aGuard; + + Reference< XFormController > xController( _Event.Source, UNO_QUERY_THROW ); + Reference< XFilterController > xFilterController( _Event.Source, UNO_QUERY_THROW ); + Reference< XForm > xForm( xController->getModel(), UNO_QUERY_THROW ); + + FmFormItem* pFormItem = m_pModel->Find( m_pModel->m_aChildren, xForm ); + OSL_ENSURE( pFormItem, "FmFilterAdapter::disjunctiveTermRemoved: don't know this form!" ); + if ( !pFormItem ) + return; + + ::std::vector< FmFilterData* >& rTermItems = pFormItem->GetChildren(); + const bool bValidIndex = ( _Event.DisjunctiveTerm >= 0 ) && ( (size_t)_Event.DisjunctiveTerm < rTermItems.size() ); + OSL_ENSURE( bValidIndex, "FmFilterAdapter::disjunctiveTermRemoved: invalid term index!" ); + if ( !bValidIndex ) + return; + + // if the first term was removed, then the to-be first term needs its text updated + if ( _Event.DisjunctiveTerm == 0 ) + { + rTermItems[1]->SetText( String( SVX_RES( RID_STR_FILTER_FILTER_FOR ) ) ); + FmFilterTextChangedHint aChangeHint( rTermItems[1] ); + m_pModel->Broadcast( aChangeHint ); + } + + // finally remove the entry from the model + m_pModel->Remove( rTermItems.begin() + _Event.DisjunctiveTerm ); + + // ensure there's one empty term in the filter, just in case the currently removed one was the last empty one + m_pModel->EnsureEmptyFilterRows( *pFormItem ); +} + +//------------------------------------------------------------------------ +void SAL_CALL FmFilterAdapter::disjunctiveTermAdded( const FilterEvent& _Event ) throw (RuntimeException) +{ + SolarMutexGuard aGuard; + + Reference< XFormController > xController( _Event.Source, UNO_QUERY_THROW ); + Reference< XFilterController > xFilterController( _Event.Source, UNO_QUERY_THROW ); + Reference< XForm > xForm( xController->getModel(), UNO_QUERY_THROW ); + + FmFormItem* pFormItem = m_pModel->Find( m_pModel->m_aChildren, xForm ); + OSL_ENSURE( pFormItem, "FmFilterAdapter::disjunctiveTermAdded: don't know this form!" ); + if ( !pFormItem ) + return; + + const sal_Int32 nInsertPos = _Event.DisjunctiveTerm; + bool bValidIndex = ( nInsertPos >= 0 ) && ( (size_t)nInsertPos <= pFormItem->GetChildren().size() ); + if ( !bValidIndex ) + { + OSL_ENSURE( false, "FmFilterAdapter::disjunctiveTermAdded: invalid index!" ); + return; + } + + const ::std::vector< FmFilterData* >::iterator insertPos = pFormItem->GetChildren().begin() + nInsertPos; + + FmFilterItems* pFilterItems = new FmFilterItems( m_pModel->getORB(), pFormItem, String( SVX_RES( RID_STR_FILTER_FILTER_OR ) ) ); + m_pModel->Insert( insertPos, pFilterItems ); +} + +//======================================================================== +// class FmFilterModel +//======================================================================== +TYPEINIT1(FmFilterModel, FmParentData); +//------------------------------------------------------------------------ +FmFilterModel::FmFilterModel(const Reference< XMultiServiceFactory >& _rxFactory) + :FmParentData(_rxFactory,NULL, ::rtl::OUString()) + ,OSQLParserClient(_rxFactory) + ,m_xORB(_rxFactory) + ,m_pAdapter(NULL) + ,m_pCurrentItems(NULL) +{ +} + +//------------------------------------------------------------------------ +FmFilterModel::~FmFilterModel() +{ + Clear(); +} + +//------------------------------------------------------------------------ +void FmFilterModel::Clear() +{ + // notify + FilterClearingHint aClearedHint; + Broadcast( aClearedHint ); + + // loose endings + if (m_pAdapter) + { + m_pAdapter->dispose(); + m_pAdapter->release(); + m_pAdapter= NULL; + } + + m_pCurrentItems = NULL; + m_xController = NULL; + m_xControllers = NULL; + + for (::std::vector<FmFilterData*>::const_iterator i = m_aChildren.begin(); + i != m_aChildren.end(); i++) + delete (*i); + + m_aChildren.clear(); +} + +//------------------------------------------------------------------------ +void FmFilterModel::Update(const Reference< XIndexAccess > & xControllers, const Reference< XFormController > & xCurrent) +{ + if ( xCurrent == m_xController ) + return; + + if (!xControllers.is()) + { + Clear(); + return; + } + + // there is only a new current controller + if ( m_xControllers != xControllers ) + { + Clear(); + + m_xControllers = xControllers; + Update(m_xControllers, this); + + DBG_ASSERT(xCurrent.is(), "FmFilterModel::Update(...) no current controller"); + + // Listening for TextChanges + m_pAdapter = new FmFilterAdapter(this, xControllers); + m_pAdapter->acquire(); + + SetCurrentController(xCurrent); + EnsureEmptyFilterRows( *this ); + } + else + SetCurrentController(xCurrent); +} + +//------------------------------------------------------------------------ +void FmFilterModel::Update(const Reference< XIndexAccess > & xControllers, FmParentData* pParent) +{ + try + { + sal_Int32 nCount = xControllers->getCount(); + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + Reference< XFormController > xController( xControllers->getByIndex(i), UNO_QUERY_THROW ); + + Reference< XPropertySet > xFormProperties( xController->getModel(), UNO_QUERY_THROW ); + ::rtl::OUString aName; + OSL_VERIFY( xFormProperties->getPropertyValue( FM_PROP_NAME ) >>= aName ); + + // Insert a new item for the form + FmFormItem* pFormItem = new FmFormItem( m_xORB, pParent, xController, aName ); + Insert( pParent->GetChildren().end(), pFormItem ); + + Reference< XFilterController > xFilterController( pFormItem->GetFilterController(), UNO_SET_THROW ); + + // insert the existing filters for the form + String aTitle( SVX_RES( RID_STR_FILTER_FILTER_FOR ) ); + + Sequence< Sequence< ::rtl::OUString > > aExpressions = xFilterController->getPredicateExpressions(); + for ( const Sequence< ::rtl::OUString >* pConjunctionTerm = aExpressions.getConstArray(); + pConjunctionTerm != aExpressions.getConstArray() + aExpressions.getLength(); + ++pConjunctionTerm + ) + { + // we always display one row, even if there's no term to be displayed + FmFilterItems* pFilterItems = new FmFilterItems( m_xORB, pFormItem, aTitle ); + Insert( pFormItem->GetChildren().end(), pFilterItems ); + + const Sequence< ::rtl::OUString >& rDisjunction( *pConjunctionTerm ); + for ( const ::rtl::OUString* pDisjunctiveTerm = rDisjunction.getConstArray(); + pDisjunctiveTerm != rDisjunction.getConstArray() + rDisjunction.getLength(); + ++pDisjunctiveTerm + ) + { + if ( pDisjunctiveTerm->getLength() == 0 ) + // no condition for this particular component in this particular conjunction term + continue; + + const sal_Int32 nComponentIndex = pDisjunctiveTerm - rDisjunction.getConstArray(); + + // determine the display name of the control + const Reference< XControl > xFilterControl( xFilterController->getFilterComponent( nComponentIndex ) ); + const ::rtl::OUString sDisplayName( lcl_getLabelName_nothrow( xFilterControl ) ); + + // insert a new entry + FmFilterItem* pANDCondition = new FmFilterItem( m_xORB, pFilterItems, sDisplayName, *pDisjunctiveTerm, nComponentIndex ); + Insert( pFilterItems->GetChildren().end(), pANDCondition ); + } + + // title for the next conditions + aTitle = SVX_RES( RID_STR_FILTER_FILTER_OR ); + } + + // now add dependent controllers + Reference< XIndexAccess > xControllerAsIndex( xController, UNO_QUERY ); + Update( xControllerAsIndex, pFormItem ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +//------------------------------------------------------------------------ +FmFormItem* FmFilterModel::Find(const ::std::vector<FmFilterData*>& rItems, const Reference< XFormController > & xController) const +{ + for (::std::vector<FmFilterData*>::const_iterator i = rItems.begin(); + i != rItems.end(); i++) + { + FmFormItem* pForm = PTR_CAST(FmFormItem,*i); + if (pForm) + { + if ( xController == pForm->GetController() ) + return pForm; + else + { + pForm = Find(pForm->GetChildren(), xController); + if (pForm) + return pForm; + } + } + } + return NULL; +} + +//------------------------------------------------------------------------ +FmFormItem* FmFilterModel::Find(const ::std::vector<FmFilterData*>& rItems, const Reference< XForm >& xForm) const +{ + for (::std::vector<FmFilterData*>::const_iterator i = rItems.begin(); + i != rItems.end(); i++) + { + FmFormItem* pForm = PTR_CAST(FmFormItem,*i); + if (pForm) + { + if (xForm == pForm->GetController()->getModel()) + return pForm; + else + { + pForm = Find(pForm->GetChildren(), xForm); + if (pForm) + return pForm; + } + } + } + return NULL; +} + +//------------------------------------------------------------------------ +void FmFilterModel::SetCurrentController(const Reference< XFormController > & xCurrent) +{ + if ( xCurrent == m_xController ) + return; + + m_xController = xCurrent; + + FmFormItem* pItem = Find( m_aChildren, xCurrent ); + if ( !pItem ) + return; + + try + { + Reference< XFilterController > xFilterController( m_xController, UNO_QUERY_THROW ); + const sal_Int32 nActiveTerm( xFilterController->getActiveTerm() ); + if ( pItem->GetChildren().size() > (size_t)nActiveTerm ) + { + SetCurrentItems( static_cast< FmFilterItems* >( pItem->GetChildren()[ nActiveTerm ] ) ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +//------------------------------------------------------------------------ +void FmFilterModel::AppendFilterItems( FmFormItem& _rFormItem ) +{ + // insert the condition behind the last filter items + ::std::vector<FmFilterData*>::reverse_iterator iter; + for ( iter = _rFormItem.GetChildren().rbegin(); + iter != _rFormItem.GetChildren().rend(); + ++iter + ) + { + if ((*iter)->ISA(FmFilterItems)) + break; + } + + sal_Int32 nInsertPos = iter.base() - _rFormItem.GetChildren().begin(); + // delegate this to the FilterController, it will notify us, which will let us update our model + try + { + Reference< XFilterController > xFilterController( _rFormItem.GetFilterController(), UNO_SET_THROW ); + if ( nInsertPos >= xFilterController->getDisjunctiveTerms() ) + xFilterController->appendEmptyDisjunctiveTerm(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +//------------------------------------------------------------------------ +void FmFilterModel::Insert(const ::std::vector<FmFilterData*>::iterator& rPos, FmFilterData* pData) +{ + ::std::vector<FmFilterData*>& rItems = pData->GetParent()->GetChildren(); + sal_Int32 nPos = rPos == rItems.end() ? LIST_APPEND : rPos - rItems.begin(); + rItems.insert(rPos, pData); + + // UI benachrichtigen + FmFilterInsertedHint aInsertedHint(pData, nPos); + Broadcast( aInsertedHint ); +} + +//------------------------------------------------------------------------ +void FmFilterModel::Remove(FmFilterData* pData) +{ + FmParentData* pParent = pData->GetParent(); + ::std::vector<FmFilterData*>& rItems = pParent->GetChildren(); + + // erase the item from the model + ::std::vector<FmFilterData*>::iterator i = ::std::find(rItems.begin(), rItems.end(), pData); + DBG_ASSERT(i != rItems.end(), "FmFilterModel::Remove(): unknown Item"); + // position within the parent + sal_Int32 nPos = i - rItems.begin(); + if (pData->ISA(FmFilterItems)) + { + FmFormItem* pFormItem = (FmFormItem*)pParent; + + try + { + Reference< XFilterController > xFilterController( pFormItem->GetFilterController(), UNO_SET_THROW ); + + bool bEmptyLastTerm = ( ( nPos == 0 ) && xFilterController->getDisjunctiveTerms() == 1 ); + if ( bEmptyLastTerm ) + { + // remove all children (by setting an empty predicate expression) + ::std::vector< FmFilterData* >& rChildren = ((FmFilterItems*)pData)->GetChildren(); + while ( !rChildren.empty() ) + { + ::std::vector< FmFilterData* >::iterator removePos = rChildren.end() - 1; + FmFilterItem* pFilterItem = PTR_CAST( FmFilterItem, *removePos ); + m_pAdapter->setText( nPos, pFilterItem, ::rtl::OUString() ); + Remove( removePos ); + } + } + else + { + xFilterController->removeDisjunctiveTerm( nPos ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + else // FormItems can not be deleted + { + FmFilterItem* pFilterItem = PTR_CAST(FmFilterItem, pData); + + // if its the last condition remove the parent + if (rItems.size() == 1) + Remove(pFilterItem->GetParent()); + else + { + // find the position of the father within his father + ::std::vector<FmFilterData*>& rParentParentItems = pData->GetParent()->GetParent()->GetChildren(); + ::std::vector<FmFilterData*>::iterator j = ::std::find(rParentParentItems.begin(), rParentParentItems.end(), pFilterItem->GetParent()); + DBG_ASSERT(j != rParentParentItems.end(), "FmFilterModel::Remove(): unknown Item"); + sal_Int32 nParentPos = j - rParentParentItems.begin(); + + // EmptyText removes the filter + m_pAdapter->setText(nParentPos, pFilterItem, ::rtl::OUString()); + Remove( i ); + } + } +} + +//------------------------------------------------------------------------ +void FmFilterModel::Remove( const ::std::vector<FmFilterData*>::iterator& rPos ) +{ + // remove from parent's child list + FmFilterData* pData = *rPos; + pData->GetParent()->GetChildren().erase( rPos ); + + // notify the view, this will remove the actual SvLBoxEntry + FmFilterRemovedHint aRemoveHint( pData ); + Broadcast( aRemoveHint ); + + delete pData; +} + +//------------------------------------------------------------------------ +sal_Bool FmFilterModel::ValidateText(FmFilterItem* pItem, UniString& rText, UniString& rErrorMsg) const +{ + FmFormItem* pFormItem = PTR_CAST( FmFormItem, pItem->GetParent()->GetParent() ); + try + { + Reference< XFormController > xFormController( pFormItem->GetController() ); + // obtain the connection of the form belonging to the controller + OStaticDataAccessTools aStaticTools; + Reference< XRowSet > xRowSet( xFormController->getModel(), UNO_QUERY_THROW ); + Reference< XConnection > xConnection( aStaticTools.getRowSetConnection( xRowSet ) ); + + // obtain a number formatter for this connection + // TODO: shouldn't this be cached? + Reference< XNumberFormatsSupplier > xFormatSupplier = aStaticTools.getNumberFormats( xConnection, sal_True ); + Reference< XNumberFormatter > xFormatter( m_xORB->createInstance( FM_NUMBER_FORMATTER ), UNO_QUERY ); + xFormatter->attachNumberFormatsSupplier( xFormatSupplier ); + + // get the field (database column) which the item is responsible for + Reference< XFilterController > xFilterController( xFormController, UNO_QUERY_THROW ); + Reference< XPropertySet > xField( lcl_getBoundField_nothrow( xFilterController->getFilterComponent( pItem->GetComponentIndex() ) ), UNO_SET_THROW ); + + // parse the given text as filter predicate + ::rtl::OUString aErr, aTxt( rText ); + ::rtl::Reference< ISQLParseNode > xParseNode = predicateTree( aErr, aTxt, xFormatter, xField ); + rErrorMsg = aErr; + rText = aTxt; + if ( xParseNode.is() ) + { + ::rtl::OUString aPreparedText; + Locale aAppLocale = Application::GetSettings().GetUILocale(); + xParseNode->parseNodeToPredicateStr( + aPreparedText, xConnection, xFormatter, xField, aAppLocale, '.', getParseContext() ); + rText = aPreparedText; + return sal_True; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + return sal_False; +} + +//------------------------------------------------------------------------ +void FmFilterModel::Append(FmFilterItems* pItems, FmFilterItem* pFilterItem) +{ + Insert(pItems->GetChildren().end(), pFilterItem); +} + +//------------------------------------------------------------------------ +void FmFilterModel::SetTextForItem(FmFilterItem* pItem, const ::rtl::OUString& rText) +{ + ::std::vector<FmFilterData*>& rItems = pItem->GetParent()->GetParent()->GetChildren(); + ::std::vector<FmFilterData*>::iterator i = ::std::find(rItems.begin(), rItems.end(), pItem->GetParent()); + sal_Int32 nParentPos = i - rItems.begin(); + + m_pAdapter->setText(nParentPos, pItem, rText); + + if (!rText) + Remove(pItem); + else + { + // Change the text + pItem->SetText(rText); + FmFilterTextChangedHint aChangeHint(pItem); + Broadcast( aChangeHint ); + } +} + +//------------------------------------------------------------------------ +void FmFilterModel::SetCurrentItems(FmFilterItems* pCurrent) +{ + if (m_pCurrentItems == pCurrent) + return; + + // search for the condition + if (pCurrent) + { + FmFormItem* pFormItem = (FmFormItem*)pCurrent->GetParent(); + ::std::vector<FmFilterData*>& rItems = pFormItem->GetChildren(); + ::std::vector<FmFilterData*>::const_iterator i = ::std::find(rItems.begin(), rItems.end(), pCurrent); + + if (i != rItems.end()) + { + // determine the filter position + sal_Int32 nPos = i - rItems.begin(); + try + { + Reference< XFilterController > xFilterController( pFormItem->GetFilterController(), UNO_SET_THROW ); + xFilterController->setActiveTerm( nPos ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + if ( m_xController != pFormItem->GetController() ) + // calls SetCurrentItems again + SetCurrentController( pFormItem->GetController() ); + else + m_pCurrentItems = pCurrent; + } + else + m_pCurrentItems = NULL; + } + else + m_pCurrentItems = NULL; + + + // UI benachrichtigen + FmFilterCurrentChangedHint aHint; + Broadcast( aHint ); +} + +//------------------------------------------------------------------------ +void FmFilterModel::EnsureEmptyFilterRows( FmParentData& _rItem ) +{ + // checks whether for each form there's one free level for input + ::std::vector< FmFilterData* >& rChildren = _rItem.GetChildren(); + sal_Bool bAppendLevel = _rItem.ISA( FmFormItem ); + + for ( ::std::vector<FmFilterData*>::iterator i = rChildren.begin(); + i != rChildren.end(); + ++i + ) + { + FmFilterItems* pItems = PTR_CAST(FmFilterItems, *i); + if ( pItems && pItems->GetChildren().empty() ) + { + bAppendLevel = sal_False; + break; + } + + FmFormItem* pFormItem = PTR_CAST(FmFormItem, *i); + if (pFormItem) + { + EnsureEmptyFilterRows( *pFormItem ); + continue; + } + } + + if ( bAppendLevel ) + { + FmFormItem* pFormItem = PTR_CAST( FmFormItem, &_rItem ); + OSL_ENSURE( pFormItem, "FmFilterModel::EnsureEmptyFilterRows: no FmFormItem, but a FmFilterItems child?" ); + if ( pFormItem ) + AppendFilterItems( *pFormItem ); + } +} + +//======================================================================== +// class FmFilterItemsString +//======================================================================== +class FmFilterItemsString : public SvLBoxString +{ +public: + FmFilterItemsString( SvLBoxEntry* pEntry, sal_uInt16 nFlags, const XubString& rStr ) + :SvLBoxString(pEntry,nFlags,rStr){} + + virtual void Paint(const Point& rPos, SvLBox& rDev, sal_uInt16 nFlags, SvLBoxEntry* pEntry); + virtual void InitViewData( SvLBox* pView,SvLBoxEntry* pEntry, SvViewDataItem* pViewData); +}; + +const int nxDBmp = 12; +//------------------------------------------------------------------------ +void FmFilterItemsString::Paint(const Point& rPos, SvLBox& rDev, sal_uInt16 /*nFlags*/, SvLBoxEntry* pEntry ) +{ + FmFilterItems* pRow = (FmFilterItems*)pEntry->GetUserData(); + FmFormItem* pForm = (FmFormItem*)pRow->GetParent(); + + // current filter is significant painted + const bool bIsCurrentFilter = pForm->GetChildren()[ pForm->GetFilterController()->getActiveTerm() ] == pRow; + if ( bIsCurrentFilter ) + { + rDev.Push( PUSH_LINECOLOR ); + + rDev.SetLineColor( rDev.GetTextColor() ); + + Rectangle aRect( rPos, GetSize( &rDev, pEntry ) ); + Point aFirst( rPos.X(), aRect.Bottom() - 6 ); + Point aSecond(aFirst .X() + 2, aFirst.Y() + 3 ); + + rDev.DrawLine( aFirst, aSecond ); + + aFirst = aSecond; + aFirst.X() += 1; + aSecond.X() += 6; + aSecond.Y() -= 5; + + rDev.DrawLine( aFirst, aSecond ); + + rDev.Pop(); + } + + rDev.DrawText( Point(rPos.X() + nxDBmp, rPos.Y()), GetText() ); +} + +//------------------------------------------------------------------------ +void FmFilterItemsString::InitViewData( SvLBox* pView,SvLBoxEntry* pEntry, SvViewDataItem* pViewData) +{ + if( !pViewData ) + pViewData = pView->GetViewDataItem( pEntry, this ); + + Size aSize(pView->GetTextWidth(GetText()), pView->GetTextHeight()); + aSize.Width() += nxDBmp; + pViewData->aSize = aSize; +} + +//======================================================================== +// class FmFilterString +//======================================================================== +class FmFilterString : public SvLBoxString +{ + UniString m_aName; + +public: + FmFilterString( SvLBoxEntry* pEntry, sal_uInt16 nFlags, const XubString& rStr, const UniString& aName) + :SvLBoxString(pEntry,nFlags,rStr) + ,m_aName(aName) + { + m_aName.AppendAscii(": "); + } + + virtual void Paint(const Point& rPos, SvLBox& rDev, sal_uInt16 nFlags, SvLBoxEntry* pEntry); + virtual void InitViewData( SvLBox* pView,SvLBoxEntry* pEntry, SvViewDataItem* pViewData); +}; + +const int nxD = 4; + +//------------------------------------------------------------------------ +void FmFilterString::InitViewData( SvLBox* pView,SvLBoxEntry* pEntry, SvViewDataItem* pViewData) +{ + if( !pViewData ) + pViewData = pView->GetViewDataItem( pEntry, this ); + + Font aOldFont( pView->GetFont()); + Font aFont( aOldFont ); + aFont.SetWeight(WEIGHT_BOLD); + pView->SetFont( aFont ); + + Size aSize(pView->GetTextWidth(m_aName), pView->GetTextHeight()); + pView->SetFont( aOldFont ); + aSize.Width() += pView->GetTextWidth(GetText()) + nxD; + pViewData->aSize = aSize; +} + +//------------------------------------------------------------------------ +void FmFilterString::Paint(const Point& rPos, SvLBox& rDev, sal_uInt16 /*nFlags*/, SvLBoxEntry* /*pEntry*/ ) +{ + Font aOldFont( rDev.GetFont()); + Font aFont( aOldFont ); + aFont.SetWeight(WEIGHT_BOLD); + rDev.SetFont( aFont ); + + Point aPos(rPos); + rDev.DrawText( aPos, m_aName ); + + // position for the second text + aPos.X() += rDev.GetTextWidth(m_aName) + nxD; + rDev.SetFont( aOldFont ); + rDev.DrawText( aPos, GetText() ); +} + +//======================================================================== +// class FmFilterNavigator +//======================================================================== +FmFilterNavigator::FmFilterNavigator( Window* pParent ) + :SvTreeListBox( pParent, WB_HASBUTTONS|WB_HASLINES|WB_BORDER|WB_HASBUTTONSATROOT ) + ,m_pModel( NULL ) + ,m_pEditingCurrently( NULL ) + ,m_aControlExchange( this ) + ,m_aTimerCounter( 0 ) + ,m_aDropActionType( DA_SCROLLUP ) +{ + SetHelpId( HID_FILTER_NAVIGATOR ); + + { + ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL ) ); + SetNodeBitmaps( + aNavigatorImages.GetImage( RID_SVXIMG_COLLAPSEDNODE ), + aNavigatorImages.GetImage( RID_SVXIMG_EXPANDEDNODE ) + ); + } + + m_pModel = new FmFilterModel(comphelper::getProcessServiceFactory()); + StartListening( *m_pModel ); + + EnableInplaceEditing( sal_True ); + SetSelectionMode(MULTIPLE_SELECTION); + + SetDragDropMode(0xFFFF); + + m_aDropActionTimer.SetTimeoutHdl(LINK(this, FmFilterNavigator, OnDropActionTimer)); +} + +//------------------------------------------------------------------------ +FmFilterNavigator::~FmFilterNavigator() +{ + EndListening( *m_pModel ); + delete m_pModel; +} + +//------------------------------------------------------------------------ +void FmFilterNavigator::Clear() +{ + m_pModel->Clear(); +} + +//------------------------------------------------------------------------ +void FmFilterNavigator::UpdateContent(const Reference< XIndexAccess > & xControllers, const Reference< XFormController > & xCurrent) +{ + if (xCurrent == m_pModel->GetCurrentController()) + return; + + m_pModel->Update(xControllers, xCurrent); + + // expand the filters for the current controller + SvLBoxEntry* pEntry = FindEntry(m_pModel->GetCurrentForm()); + if (pEntry && !IsExpanded(pEntry)) + { + SelectAll(sal_False); + + if (!IsExpanded(pEntry)) + Expand(pEntry); + + pEntry = FindEntry(m_pModel->GetCurrentItems()); + if (pEntry) + { + if (!IsExpanded(pEntry)) + Expand(pEntry); + Select(pEntry, sal_True); + } + } +} + +//------------------------------------------------------------------------ +sal_Bool FmFilterNavigator::EditingEntry( SvLBoxEntry* pEntry, Selection& rSelection ) +{ + m_pEditingCurrently = pEntry; + if (!SvTreeListBox::EditingEntry( pEntry, rSelection )) + return sal_False; + + return pEntry && ((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItem); +} + +//------------------------------------------------------------------------ +sal_Bool FmFilterNavigator::EditedEntry( SvLBoxEntry* pEntry, const XubString& rNewText ) +{ + DBG_ASSERT(pEntry == m_pEditingCurrently, "FmFilterNavigator::EditedEntry: suspicious entry!"); + m_pEditingCurrently = NULL; + + if (EditingCanceled()) + return sal_True; + + DBG_ASSERT(((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItem), + "FmFilterNavigator::EditedEntry() wrong entry"); + + UniString aText(rNewText); + aText.EraseTrailingChars(); + aText.EraseLeadingChars(); + if (aText.Len() == 0) + { + // deleting the entry asynchron + ULONG nEvent; + PostUserEvent(nEvent, LINK(this, FmFilterNavigator, OnRemove), pEntry); + } + else + { + UniString aErrorMsg; + + if (m_pModel->ValidateText((FmFilterItem*)pEntry->GetUserData(), aText, aErrorMsg)) + { + GrabFocus(); + // this will set the text at the FmFilterItem, as well as update any filter controls + // which are connected to this particular entry + m_pModel->SetTextForItem( static_cast< FmFilterItem* >( pEntry->GetUserData() ), aText ); + + SetCursor( pEntry, sal_True ); + SetEntryText( pEntry, aText ); + } + else + { + // display the error and return sal_False + SQLContext aError; + aError.Message = String(SVX_RES(RID_STR_SYNTAXERROR)); + aError.Details = aErrorMsg; + displayException(aError, this); + + return sal_False; + } + } + return sal_True; +} + +//------------------------------------------------------------------------ +IMPL_LINK( FmFilterNavigator, OnRemove, SvLBoxEntry*, pEntry ) +{ + // now remove the entry + m_pModel->Remove((FmFilterData*) pEntry->GetUserData()); + return 0L; +} + +//------------------------------------------------------------------------ +IMPL_LINK( FmFilterNavigator, OnDropActionTimer, void*, EMPTYARG ) +{ + if (--m_aTimerCounter > 0) + return 0L; + + switch (m_aDropActionType) + { + case DA_SCROLLUP : + ScrollOutputArea(1); + m_aTimerCounter = DROP_ACTION_TIMER_SCROLL_TICKS; + break; + case DA_SCROLLDOWN : + ScrollOutputArea(-1); + m_aTimerCounter = DROP_ACTION_TIMER_SCROLL_TICKS; + break; + case DA_EXPANDNODE: + { + SvLBoxEntry* pToExpand = GetEntry(m_aTimerTriggered); + if (pToExpand && (GetChildCount(pToExpand) > 0) && !IsExpanded(pToExpand)) + // tja, eigentlich muesste ich noch testen, ob die Node nicht schon expandiert ist, aber ich + // habe dazu weder in den Basisklassen noch im Model eine Methode gefunden ... + // aber ich denke, die BK sollte es auch so vertragen + Expand(pToExpand); + + // nach dem Expand habe ich im Gegensatz zum Scrollen natuerlich nix mehr zu tun + m_aDropActionTimer.Stop(); + } + break; + } + return 0L; +} + + +//------------------------------------------------------------------------ +sal_Int8 FmFilterNavigator::AcceptDrop( const AcceptDropEvent& rEvt ) +{ + Point aDropPos = rEvt.maPosPixel; + + // kuemmern wir uns erst mal um moeglich DropActions (Scrollen und Aufklappen) + if (rEvt.mbLeaving) + { + if (m_aDropActionTimer.IsActive()) + m_aDropActionTimer.Stop(); + } + else + { + sal_Bool bNeedTrigger = sal_False; + // auf dem ersten Eintrag ? + if ((aDropPos.Y() >= 0) && (aDropPos.Y() < GetEntryHeight())) + { + m_aDropActionType = DA_SCROLLUP; + bNeedTrigger = sal_True; + } + else + { + // auf dem letzten (bzw. in dem Bereich, den ein Eintrag einnehmen wuerde, wenn er unten genau buendig + // abschliessen wuerde) ? + if ((aDropPos.Y() < GetSizePixel().Height()) && (aDropPos.Y() >= GetSizePixel().Height() - GetEntryHeight())) + { + m_aDropActionType = DA_SCROLLDOWN; + bNeedTrigger = sal_True; + } + else + { // is it an entry whith children, and not yet expanded? + SvLBoxEntry* pDropppedOn = GetEntry(aDropPos); + if (pDropppedOn && (GetChildCount(pDropppedOn) > 0) && !IsExpanded(pDropppedOn)) + { + // -> aufklappen + m_aDropActionType = DA_EXPANDNODE; + bNeedTrigger = sal_True; + } + } + } + if (bNeedTrigger && (m_aTimerTriggered != aDropPos)) + { + // neu anfangen zu zaehlen + m_aTimerCounter = DROP_ACTION_TIMER_INITIAL_TICKS; + // die Pos merken, da ich auch QueryDrops bekomme, wenn sich die Maus gar nicht bewegt hat + m_aTimerTriggered = aDropPos; + // und den Timer los + if (!m_aDropActionTimer.IsActive()) // gibt es den Timer schon ? + { + m_aDropActionTimer.SetTimeout(DROP_ACTION_TIMER_TICK_BASE); + m_aDropActionTimer.Start(); + } + } + else if (!bNeedTrigger) + m_aDropActionTimer.Stop(); + } + + + // Hat das Object das richtige Format? + if (!m_aControlExchange.isDragSource()) + return DND_ACTION_NONE; + + if (!m_aControlExchange->hasFormat(GetDataFlavorExVector())) + return DND_ACTION_NONE; + + // do we conain the formitem? + if (!FindEntry(m_aControlExchange->getFormItem())) + return DND_ACTION_NONE; + + SvLBoxEntry* pDropTarget = GetEntry(aDropPos); + if (!pDropTarget) + return DND_ACTION_NONE; + + FmFilterData* pData = (FmFilterData*)pDropTarget->GetUserData(); + FmFormItem* pForm = NULL; + if (pData->ISA(FmFilterItem)) + { + pForm = PTR_CAST(FmFormItem,pData->GetParent()->GetParent()); + if (pForm != m_aControlExchange->getFormItem()) + return DND_ACTION_NONE; + } + else if (pData->ISA(FmFilterItems)) + { + pForm = PTR_CAST(FmFormItem,pData->GetParent()); + if (pForm != m_aControlExchange->getFormItem()) + return DND_ACTION_NONE; + } + else + return DND_ACTION_NONE; + + return rEvt.mnAction; +} +// ----------------------------------------------------------------------------- +namespace +{ + FmFilterItems* getTargetItems(SvLBoxEntry* _pTarget) + { + FmFilterData* pData = static_cast<FmFilterData*>(_pTarget->GetUserData()); + FmFilterItems* pTargetItems = pData->ISA(FmFilterItems) + ? + PTR_CAST(FmFilterItems,pData) + : + PTR_CAST(FmFilterItems,pData->GetParent()); + return pTargetItems; + } +} +//------------------------------------------------------------------------ +sal_Int8 FmFilterNavigator::ExecuteDrop( const ExecuteDropEvent& rEvt ) +{ + // ware schlecht, wenn nach dem Droppen noch gescrollt wird ... + if (m_aDropActionTimer.IsActive()) + m_aDropActionTimer.Stop(); + + // Format-Ueberpruefung + if (!m_aControlExchange.isDragSource()) + return DND_ACTION_NONE; + + // das Ziel des Drop sowie einige Daten darueber + Point aDropPos = rEvt.maPosPixel; + SvLBoxEntry* pDropTarget = GetEntry( aDropPos ); + if (!pDropTarget) + return DND_ACTION_NONE; + + // search the container where to add the items + FmFilterItems* pTargetItems = getTargetItems(pDropTarget); + SelectAll(sal_False); + SvLBoxEntry* pEntry = FindEntry(pTargetItems); + Select(pEntry, sal_True); + SetCurEntry(pEntry); + + insertFilterItem(m_aControlExchange->getDraggedEntries(),pTargetItems,DND_ACTION_COPY == rEvt.mnAction); + + return sal_True; +} + +//------------------------------------------------------------------------ +void FmFilterNavigator::InitEntry(SvLBoxEntry* pEntry, + const XubString& rStr, + const Image& rImg1, + const Image& rImg2, + SvLBoxButtonKind eButtonKind) +{ + SvTreeListBox::InitEntry( pEntry, rStr, rImg1, rImg2, eButtonKind ); + SvLBoxString* pString = NULL; + + if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItem)) + pString = new FmFilterString(pEntry, 0, rStr, ((FmFilterItem*)pEntry->GetUserData())->GetFieldName()); + else if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItems)) + pString = new FmFilterItemsString(pEntry, 0, rStr ); + + if (pString) + pEntry->ReplaceItem( pString, 1 ); +} + +//------------------------------------------------------------------------ +sal_Bool FmFilterNavigator::Select( SvLBoxEntry* pEntry, sal_Bool bSelect ) +{ + if (bSelect == IsSelected(pEntry)) // das passiert manchmal, ich glaube, die Basisklasse geht zu sehr auf Nummer sicher ;) + return sal_True; + + if (SvTreeListBox::Select(pEntry, bSelect)) + { + if (bSelect) + { + FmFormItem* pFormItem = NULL; + if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItem)) + pFormItem = (FmFormItem*)((FmFilterItem*)pEntry->GetUserData())->GetParent()->GetParent(); + else if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItems)) + pFormItem = (FmFormItem*)((FmFilterItem*)pEntry->GetUserData())->GetParent()->GetParent(); + else if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFormItem)) + pFormItem = (FmFormItem*)pEntry->GetUserData(); + + if (pFormItem) + { + // will the controller be exchanged? + if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItem)) + m_pModel->SetCurrentItems((FmFilterItems*)((FmFilterItem*)pEntry->GetUserData())->GetParent()); + else if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFilterItems)) + m_pModel->SetCurrentItems((FmFilterItems*)pEntry->GetUserData()); + else if (((FmFilterData*)pEntry->GetUserData())->ISA(FmFormItem)) + m_pModel->SetCurrentController(((FmFormItem*)pEntry->GetUserData())->GetController()); + } + } + return sal_True; + } + else + return sal_False; +} + +//------------------------------------------------------------------------ +void FmFilterNavigator::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) +{ + if (rHint.ISA(FmFilterInsertedHint)) + { + FmFilterInsertedHint* pHint = (FmFilterInsertedHint*)&rHint; + Insert(pHint->GetData(), pHint->GetPos()); + } + else if( rHint.ISA(FilterClearingHint) ) + { + SvTreeListBox::Clear(); + } + else if( rHint.ISA(FmFilterRemovedHint) ) + { + FmFilterRemovedHint* pHint = (FmFilterRemovedHint*)&rHint; + Remove(pHint->GetData()); + } + else if( rHint.ISA(FmFilterTextChangedHint) ) + { + FmFilterTextChangedHint* pHint = (FmFilterTextChangedHint*)&rHint; + SvLBoxEntry* pEntry = FindEntry(pHint->GetData()); + if (pEntry) + SetEntryText( pEntry, pHint->GetData()->GetText()); + } + else if( rHint.ISA(FmFilterCurrentChangedHint) ) + { + // invalidate the entries + for (SvLBoxEntry* pEntry = First(); pEntry != NULL; + pEntry = Next(pEntry)) + GetModel()->InvalidateEntry( pEntry ); + } +} + +//------------------------------------------------------------------------ +SvLBoxEntry* FmFilterNavigator::FindEntry(const FmFilterData* pItem) const +{ + SvLBoxEntry* pEntry = NULL; + if (pItem) + { + for (pEntry = First(); pEntry != NULL; pEntry = Next( pEntry )) + { + FmFilterData* pEntryItem = (FmFilterData*)pEntry->GetUserData(); + if (pEntryItem == pItem) + break; + } + } + return pEntry; +} + +//------------------------------------------------------------------------ +void FmFilterNavigator::Insert(FmFilterData* pItem, sal_Int32 nPos) +{ + const FmParentData* pParent = pItem->GetParent() ? pItem->GetParent() : GetFilterModel(); + + // insert the item + SvLBoxEntry* pParentEntry = FindEntry( pParent ); + InsertEntry( pItem->GetText(), pItem->GetImage(), pItem->GetImage(), pParentEntry, sal_False, nPos, pItem ); + if ( pParentEntry ) + Expand( pParentEntry ); +} + +//------------------------------------------------------------------------ +void FmFilterNavigator::Remove(FmFilterData* pItem) +{ + // der Entry zu den Daten + SvLBoxEntry* pEntry = FindEntry(pItem); + + if (pEntry == m_pEditingCurrently) + // cancel editing + EndEditing(sal_True); + + if (pEntry) + GetModel()->Remove( pEntry ); +} +// ----------------------------------------------------------------------------- +FmFormItem* FmFilterNavigator::getSelectedFilterItems(::std::vector<FmFilterItem*>& _rItemList) +{ + // be sure that the data is only used within only one form! + FmFormItem* pFirstItem = NULL; + + sal_Bool bHandled = sal_True; + sal_Bool bFoundSomething = sal_False; + for (SvLBoxEntry* pEntry = FirstSelected(); + bHandled && pEntry != NULL; + pEntry = NextSelected(pEntry)) + { + FmFilterItem* pFilter = PTR_CAST(FmFilterItem, (FmFilterData*)pEntry->GetUserData()); + if (pFilter) + { + FmFormItem* pForm = PTR_CAST(FmFormItem,pFilter->GetParent()->GetParent()); + if (!pForm) + bHandled = sal_False; + else if (!pFirstItem) + pFirstItem = pForm; + else if (pFirstItem != pForm) + bHandled = sal_False; + + if (bHandled) + { + _rItemList.push_back(pFilter); + bFoundSomething = sal_True; + } + } + } + if ( !bHandled || !bFoundSomething ) + pFirstItem = NULL; + return pFirstItem; +} +// ----------------------------------------------------------------------------- +void FmFilterNavigator::insertFilterItem(const ::std::vector<FmFilterItem*>& _rFilterList,FmFilterItems* _pTargetItems,sal_Bool _bCopy) +{ + ::std::vector<FmFilterItem*>::const_iterator aEnd = _rFilterList.end(); + for ( ::std::vector< FmFilterItem* >::const_iterator i = _rFilterList.begin(); + i != aEnd; + ++i + ) + { + FmFilterItem* pLookupItem( *i ); + if ( pLookupItem->GetParent() == _pTargetItems ) + continue; + + FmFilterItem* pFilterItem = _pTargetItems->Find( pLookupItem->GetComponentIndex() ); + String aText = pLookupItem->GetText(); + if ( !pFilterItem ) + { + pFilterItem = new FmFilterItem( m_pModel->getORB(), _pTargetItems, pLookupItem->GetFieldName(), aText, pLookupItem->GetComponentIndex() ); + m_pModel->Append( _pTargetItems, pFilterItem ); + } + + if ( !_bCopy ) + m_pModel->Remove( pLookupItem ); + + // now set the text for the new dragged item + m_pModel->SetTextForItem( pFilterItem, aText ); + } + + m_pModel->EnsureEmptyFilterRows( *_pTargetItems->GetParent() ); +} + +//------------------------------------------------------------------------------ +void FmFilterNavigator::StartDrag( sal_Int8 /*_nAction*/, const Point& /*_rPosPixel*/ ) +{ + EndSelection(); + + // be sure that the data is only used within a only one form! + m_aControlExchange.prepareDrag(); + + ::std::vector<FmFilterItem*> aItemList; + if ( FmFormItem* pFirstItem = getSelectedFilterItems(aItemList) ) + { + m_aControlExchange->setDraggedEntries(aItemList); + m_aControlExchange->setFormItem(pFirstItem); + m_aControlExchange.startDrag( DND_ACTION_COPYMOVE ); + } +} + +//------------------------------------------------------------------------------ +void FmFilterNavigator::Command( const CommandEvent& rEvt ) +{ + sal_Bool bHandled = sal_False; + switch (rEvt.GetCommand()) + { + case COMMAND_CONTEXTMENU: + { + // die Stelle, an der geklickt wurde + Point aWhere; + SvLBoxEntry* pClicked = NULL; + if (rEvt.IsMouseEvent()) + { + aWhere = rEvt.GetMousePosPixel(); + pClicked = GetEntry(aWhere); + if (pClicked == NULL) + break; + + if (!IsSelected(pClicked)) + { + SelectAll(sal_False); + Select(pClicked, sal_True); + SetCurEntry(pClicked); + } + } + else + { + pClicked = GetCurEntry(); + if (!pClicked) + break; + aWhere = GetEntryPosition( pClicked ); + } + + ::std::vector<FmFilterData*> aSelectList; + for (SvLBoxEntry* pEntry = FirstSelected(); + pEntry != NULL; + pEntry = NextSelected(pEntry)) + { + // don't delete forms + FmFormItem* pForm = PTR_CAST(FmFormItem, (FmFilterData*)pEntry->GetUserData()); + if (!pForm) + aSelectList.push_back((FmFilterData*)pEntry->GetUserData()); + } + if (aSelectList.size() == 1) + { + // don't delete the only empty row of a form + FmFilterItems* pFilterItems = PTR_CAST(FmFilterItems, aSelectList[0]); + if (pFilterItems && pFilterItems->GetChildren().empty() + && pFilterItems->GetParent()->GetChildren().size() == 1) + aSelectList.clear(); + } + + PopupMenu aContextMenu(SVX_RES(RID_FM_FILTER_MENU)); + + // every condition could be deleted except the first one if its the only one + aContextMenu.EnableItem( SID_FM_DELETE, !aSelectList.empty() ); + + // + sal_Bool bEdit = PTR_CAST(FmFilterItem, (FmFilterData*)pClicked->GetUserData()) != NULL && + IsSelected(pClicked) && GetSelectionCount() == 1; + + aContextMenu.EnableItem( SID_FM_FILTER_EDIT, + bEdit ); + aContextMenu.EnableItem( SID_FM_FILTER_IS_NULL, + bEdit ); + aContextMenu.EnableItem( SID_FM_FILTER_IS_NOT_NULL, + bEdit ); + + aContextMenu.RemoveDisabledEntries(sal_True, sal_True); + sal_uInt16 nSlotId = aContextMenu.Execute( this, aWhere ); + switch( nSlotId ) + { + case SID_FM_FILTER_EDIT: + { + EditEntry( pClicked ); + } break; + case SID_FM_FILTER_IS_NULL: + case SID_FM_FILTER_IS_NOT_NULL: + { + UniString aErrorMsg; + UniString aText; + if (nSlotId == SID_FM_FILTER_IS_NULL) + aText.AssignAscii("IS NULL"); + else + aText.AssignAscii("IS NOT NULL"); + + m_pModel->ValidateText((FmFilterItem*)pClicked->GetUserData(), + aText, aErrorMsg); + m_pModel->SetTextForItem((FmFilterItem*)pClicked->GetUserData(), aText); + } break; + case SID_FM_DELETE: + { + DeleteSelection(); + } break; + } + bHandled = sal_True; + } break; + } + + if (!bHandled) + SvTreeListBox::Command( rEvt ); +} +// ----------------------------------------------------------------------------- +SvLBoxEntry* FmFilterNavigator::getNextEntry(SvLBoxEntry* _pStartWith) +{ + SvLBoxEntry* pEntry = _pStartWith ? _pStartWith : LastSelected(); + pEntry = Next(pEntry); + // we need the next filter entry + while( pEntry && GetChildCount( pEntry ) == 0 && pEntry != Last() ) + pEntry = Next(pEntry); + return pEntry; +} +// ----------------------------------------------------------------------------- +SvLBoxEntry* FmFilterNavigator::getPrevEntry(SvLBoxEntry* _pStartWith) +{ + SvLBoxEntry* pEntry = _pStartWith ? _pStartWith : FirstSelected(); + pEntry = Prev(pEntry); + // check if the previous entry is a filter, if so get the next prev + if ( pEntry && GetChildCount( pEntry ) != 0 ) + { + pEntry = Prev(pEntry); + // if the entry is still no leaf return + if ( pEntry && GetChildCount( pEntry ) != 0 ) + pEntry = NULL; + } + return pEntry; +} +//------------------------------------------------------------------------ +void FmFilterNavigator::KeyInput(const KeyEvent& rKEvt) +{ + const KeyCode& rKeyCode = rKEvt.GetKeyCode(); + + switch ( rKeyCode.GetCode() ) + { + case KEY_UP: + case KEY_DOWN: + { + if ( !rKeyCode.IsMod1() || !rKeyCode.IsMod2() || rKeyCode.IsShift() ) + break; + + ::std::vector<FmFilterItem*> aItemList; + if ( !getSelectedFilterItems( aItemList ) ) + break; + + ::std::mem_fun1_t<SvLBoxEntry*,FmFilterNavigator,SvLBoxEntry*> getter = ::std::mem_fun(&FmFilterNavigator::getNextEntry); + if ( rKeyCode.GetCode() == KEY_UP ) + getter = ::std::mem_fun(&FmFilterNavigator::getPrevEntry); + + SvLBoxEntry* pTarget = getter( this, NULL ); + if ( !pTarget ) + break; + + FmFilterItems* pTargetItems = getTargetItems( pTarget ); + if ( !pTargetItems ) + break; + + ::std::vector<FmFilterItem*>::const_iterator aEnd = aItemList.end(); + sal_Bool bNextTargetItem = sal_True; + while ( bNextTargetItem ) + { + ::std::vector<FmFilterItem*>::const_iterator i = aItemList.begin(); + for (; i != aEnd; ++i) + { + if ( (*i)->GetParent() == pTargetItems ) + { + pTarget = getter(this,pTarget); + if ( !pTarget ) + return; + pTargetItems = getTargetItems( pTarget ); + break; + } + else + { + FmFilterItem* pFilterItem = pTargetItems->Find( (*i)->GetComponentIndex() ); + // we found the text component so jump above + if ( pFilterItem ) + { + pTarget = getter( this, pTarget ); + if ( !pTarget ) + return; + + pTargetItems = getTargetItems( pTarget ); + break; + } + } + } + bNextTargetItem = i != aEnd && pTargetItems; + } + + if ( pTargetItems ) + { + insertFilterItem( aItemList, pTargetItems ); + return; + } + } + break; + + case KEY_DELETE: + { + if ( rKeyCode.GetModifier() ) + break; + + if ( !IsSelected( First() ) || GetEntryCount() > 1 ) + DeleteSelection(); + return; + } + } + + SvTreeListBox::KeyInput(rKEvt); +} + +//------------------------------------------------------------------------------ +void FmFilterNavigator::DeleteSelection() +{ + // to avoid the deletion of an entry twice (e.g. deletion of a parent and afterward + // the deletion of it's child, i have to shrink the selecton list + ::std::vector<SvLBoxEntry*> aEntryList; + for (SvLBoxEntry* pEntry = FirstSelected(); + pEntry != NULL; + pEntry = NextSelected(pEntry)) + { + FmFilterItem* pFilterItem = PTR_CAST(FmFilterItem, (FmFilterData*)pEntry->GetUserData()); + if (pFilterItem && IsSelected(GetParent(pEntry))) + continue; + + FmFormItem* pForm = PTR_CAST(FmFormItem, (FmFilterData*)pEntry->GetUserData()); + if (!pForm) + aEntryList.push_back(pEntry); + } + + // Remove the selection + SelectAll(FALSE); + + for (::std::vector<SvLBoxEntry*>::reverse_iterator i = aEntryList.rbegin(); + // link problems with operator == + i.base() != aEntryList.rend().base(); i++) + { + m_pModel->Remove((FmFilterData*)(*i)->GetUserData()); + } +} +// ----------------------------------------------------------------------------- + +//======================================================================== +// class FmFilterNavigatorWin +//======================================================================== +FmFilterNavigatorWin::FmFilterNavigatorWin( SfxBindings* _pBindings, SfxChildWindow* _pMgr, + Window* _pParent ) + :SfxDockingWindow( _pBindings, _pMgr, _pParent, WinBits(WB_STDMODELESS|WB_SIZEABLE|WB_ROLLABLE|WB_3DLOOK|WB_DOCKABLE) ) + ,SfxControllerItem( SID_FM_FILTER_NAVIGATOR_CONTROL, *_pBindings ) +{ + SetHelpId( HID_FILTER_NAVIGATOR_WIN ); + + m_pNavigator = new FmFilterNavigator( this ); + m_pNavigator->Show(); + SetText( SVX_RES(RID_STR_FILTER_NAVIGATOR) ); + SfxDockingWindow::SetFloatingSize( Size(200,200) ); +} + +//------------------------------------------------------------------------ +FmFilterNavigatorWin::~FmFilterNavigatorWin() +{ + delete m_pNavigator; +} + +//----------------------------------------------------------------------- +void FmFilterNavigatorWin::UpdateContent(FmFormShell* pFormShell) +{ + if (!pFormShell) + m_pNavigator->UpdateContent( NULL, NULL ); + else + { + Reference< XFormController > xController(pFormShell->GetImpl()->getActiveInternalController()); + Reference< XIndexAccess > xContainer; + if (xController.is()) + { + Reference< XChild > xChild(xController, UNO_QUERY); + for (Reference< XInterface > xParent(xChild->getParent()); + xParent.is(); + xParent = xChild.is() ? xChild->getParent() : Reference< XInterface > ()) + { + xContainer = Reference< XIndexAccess > (xParent, UNO_QUERY); + xChild = Reference< XChild > (xParent, UNO_QUERY); + } + } + m_pNavigator->UpdateContent(xContainer, xController); + } +} + +//----------------------------------------------------------------------- +void FmFilterNavigatorWin::StateChanged( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState ) +{ + if( !pState || SID_FM_FILTER_NAVIGATOR_CONTROL != nSID ) + return; + + if( eState >= SFX_ITEM_AVAILABLE ) + { + FmFormShell* pShell = PTR_CAST( FmFormShell,((SfxObjectItem*)pState)->GetShell() ); + UpdateContent( pShell ); + } + else + UpdateContent( NULL ); +} + +//----------------------------------------------------------------------- +sal_Bool FmFilterNavigatorWin::Close() +{ + if ( m_pNavigator && m_pNavigator->IsEditingActive() ) + m_pNavigator->EndEditing(); + + if ( m_pNavigator && m_pNavigator->IsEditingActive() ) + // the EndEditing was vetoed (perhaps of an syntax error or such) + return sal_False; + + UpdateContent( NULL ); + return SfxDockingWindow::Close(); +} + +//----------------------------------------------------------------------- +void FmFilterNavigatorWin::FillInfo( SfxChildWinInfo& rInfo ) const +{ + SfxDockingWindow::FillInfo( rInfo ); + rInfo.bVisible = sal_False; +} + +//----------------------------------------------------------------------- +Size FmFilterNavigatorWin::CalcDockingSize( SfxChildAlignment eAlign ) +{ + if ( ( eAlign == SFX_ALIGN_TOP ) || ( eAlign == SFX_ALIGN_BOTTOM ) ) + return Size(); + + return SfxDockingWindow::CalcDockingSize( eAlign ); +} + +//----------------------------------------------------------------------- +SfxChildAlignment FmFilterNavigatorWin::CheckAlignment( SfxChildAlignment eActAlign, SfxChildAlignment eAlign ) +{ + switch (eAlign) + { + case SFX_ALIGN_LEFT: + case SFX_ALIGN_RIGHT: + case SFX_ALIGN_NOALIGNMENT: + return (eAlign); + default: + break; + } + + return (eActAlign); +} + +//------------------------------------------------------------------------ +void FmFilterNavigatorWin::Resize() +{ + SfxDockingWindow::Resize(); + + Size aLogOutputSize = PixelToLogic( GetOutputSizePixel(), MAP_APPFONT ); + Size aLogExplSize = aLogOutputSize; + aLogExplSize.Width() -= 6; + aLogExplSize.Height() -= 6; + + Point aExplPos = LogicToPixel( Point(3,3), MAP_APPFONT ); + Size aExplSize = LogicToPixel( aLogExplSize, MAP_APPFONT ); + + m_pNavigator->SetPosSizePixel( aExplPos, aExplSize ); +} +// ----------------------------------------------------------------------------- +void FmFilterNavigatorWin::GetFocus() +{ + // oj #97405# + if ( m_pNavigator ) + m_pNavigator->GrabFocus(); +} +// ----------------------------------------------------------------------------- + + +//======================================================================== +// class FmFilterNavigatorWinMgr +//======================================================================== +SFX_IMPL_DOCKINGWINDOW( FmFilterNavigatorWinMgr, SID_FM_FILTER_NAVIGATOR ) + +//----------------------------------------------------------------------- +FmFilterNavigatorWinMgr::FmFilterNavigatorWinMgr( Window *_pParent, sal_uInt16 _nId, + SfxBindings *_pBindings, SfxChildWinInfo* _pInfo ) + :SfxChildWindow( _pParent, _nId ) +{ + pWindow = new FmFilterNavigatorWin( _pBindings, this, _pParent ); + eChildAlignment = SFX_ALIGN_NOALIGNMENT; + ((SfxDockingWindow*)pWindow)->Initialize( _pInfo ); +} + +//........................................................................ +} // namespace svxform +//........................................................................ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/filtnav.src b/svx/source/form/filtnav.src new file mode 100644 index 000000000000..82b74e84331c --- /dev/null +++ b/svx/source/form/filtnav.src @@ -0,0 +1,87 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <svx/svxids.hrc> +#include "fmresids.hrc" +Menu RID_FM_FILTER_MENU +{ + ItemList = + { + MenuItem + { + Identifier = SID_FM_DELETE ; + HelpID = SID_FM_DELETE ; + Text [ en-US ] = "~Delete" ; + }; + MenuItem + { + Identifier = SID_FM_FILTER_EDIT ; + HelpID = SID_FM_FILTER_EDIT ; + Text [ en-US ] = "~Edit" ; + }; + MenuItem + { + Identifier = SID_FM_FILTER_IS_NULL ; + HelpID = SID_FM_FILTER_IS_NULL ; + Text [ en-US ] = "~Is Null" ; + }; + MenuItem + { + Identifier = SID_FM_FILTER_IS_NOT_NULL ; + HelpID = SID_FM_FILTER_IS_NOT_NULL ; + Text [ en-US ] = "I~s not Null" ; + }; + }; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/svx/source/form/fmPropBrw.cxx b/svx/source/form/fmPropBrw.cxx new file mode 100644 index 000000000000..b146ae16d537 --- /dev/null +++ b/svx/source/form/fmPropBrw.cxx @@ -0,0 +1,727 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include <sal/macros.h> + +#include "fmhelp.hrc" +#include "fmprop.hrc" +#include "fmPropBrw.hxx" +#include "fmresids.hrc" +#include "fmservs.hxx" +#include "fmshimp.hxx" +#include "fmpgeimp.hxx" + +#include "svx/dialmgr.hxx" +#include "svx/fmpage.hxx" +#include "svx/fmshell.hxx" +#include "svx/sdrpagewindow.hxx" +#include "svx/svdpagv.hxx" +#include "svx/svxids.hrc" + +/** === begin UNO includes === **/ +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/awt/PosSize.hpp> +#include <com/sun/star/form/XForm.hpp> +#include <com/sun/star/form/FormComponentType.hpp> +#include <com/sun/star/awt/XLayoutConstrains.hpp> +#include <com/sun/star/awt/XControlContainer.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/awt/PosSize.hpp> +#include <com/sun/star/inspection/ObjectInspector.hpp> +#include <com/sun/star/inspection/ObjectInspectorModel.hpp> +#include <com/sun/star/form/inspection/DefaultFormComponentInspectorModel.hpp> +#include <com/sun/star/inspection/XObjectInspectorUI.hpp> +#include <com/sun/star/inspection/DefaultHelpProvider.hpp> +/** === end UNO includes === **/ + +#include <comphelper/processfactory.hxx> +#include <comphelper/property.hxx> +#include <cppuhelper/component_context.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/childwin.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/objitem.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/viewfrm.hxx> +#include <toolkit/unohlp.hxx> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <tools/shl.hxx> +#include <unotools/confignode.hxx> +#include <vcl/stdtext.hxx> + +#include <algorithm> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::inspection; +using namespace ::com::sun::star::form::inspection; +using ::com::sun::star::awt::XWindow; + +/*************************************************************************/ +//======================================================================== +//= FmPropBrwMgr +//======================================================================== +//----------------------------------------------------------------------- +SFX_IMPL_FLOATINGWINDOW(FmPropBrwMgr, SID_FM_SHOW_PROPERTIES) + +//----------------------------------------------------------------------- +FmPropBrwMgr::FmPropBrwMgr( Window* _pParent, sal_uInt16 _nId, + SfxBindings* _pBindings, SfxChildWinInfo* _pInfo) + :SfxChildWindow(_pParent, _nId) +{ + pWindow = new FmPropBrw( ::comphelper::getProcessServiceFactory(), _pBindings, this, _pParent, _pInfo ); + eChildAlignment = SFX_ALIGN_NOALIGNMENT; + ((SfxFloatingWindow*)pWindow)->Initialize( _pInfo ); +} + +//======================================================================== +//======================================================================== +const long STD_WIN_SIZE_X = 300; +const long STD_WIN_SIZE_Y = 350; + +const long STD_MIN_SIZE_X = 250; +const long STD_MIN_SIZE_Y = 250; + +const long STD_WIN_POS_X = 50; +const long STD_WIN_POS_Y = 50; +const long WIN_BORDER = 2; +const long MIN_WIN_SIZE_X = 50; +const long MIN_WIN_SIZE_Y = 50; + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::svxform; + +::rtl::OUString GetUIHeadlineName(sal_Int16 nClassId, const Any& aUnoObj) +{ + sal_uInt16 nClassNameResourceId = 0; + + switch ( nClassId ) + { + case FormComponentType::TEXTFIELD: + { + Reference< XInterface > xIFace; + aUnoObj >>= xIFace; + nClassNameResourceId = RID_STR_PROPTITLE_EDIT; + if (xIFace.is()) + { // we have a chance to check if it's a formatted field model + Reference< XServiceInfo > xInfo(xIFace, UNO_QUERY); + if (xInfo.is() && (xInfo->supportsService(FM_SUN_COMPONENT_FORMATTEDFIELD))) + nClassNameResourceId = RID_STR_PROPTITLE_FORMATTED; + else if (!xInfo.is()) + { + // couldn't distinguish between formatted and edit with the service name, so try with the properties + Reference< XPropertySet > xProps(xIFace, UNO_QUERY); + if (xProps.is()) + { + Reference< XPropertySetInfo > xPropsInfo = xProps->getPropertySetInfo(); + if (xPropsInfo.is() && xPropsInfo->hasPropertyByName(FM_PROP_FORMATSSUPPLIER)) + nClassNameResourceId = RID_STR_PROPTITLE_FORMATTED; + } + } + } + } + break; + + case FormComponentType::COMMANDBUTTON: + nClassNameResourceId = RID_STR_PROPTITLE_PUSHBUTTON; break; + case FormComponentType::RADIOBUTTON: + nClassNameResourceId = RID_STR_PROPTITLE_RADIOBUTTON; break; + case FormComponentType::CHECKBOX: + nClassNameResourceId = RID_STR_PROPTITLE_CHECKBOX; break; + case FormComponentType::LISTBOX: + nClassNameResourceId = RID_STR_PROPTITLE_LISTBOX; break; + case FormComponentType::COMBOBOX: + nClassNameResourceId = RID_STR_PROPTITLE_COMBOBOX; break; + case FormComponentType::GROUPBOX: + nClassNameResourceId = RID_STR_PROPTITLE_GROUPBOX; break; + case FormComponentType::IMAGEBUTTON: + nClassNameResourceId = RID_STR_PROPTITLE_IMAGEBUTTON; break; + case FormComponentType::FIXEDTEXT: + nClassNameResourceId = RID_STR_PROPTITLE_FIXEDTEXT; break; + case FormComponentType::GRIDCONTROL: + nClassNameResourceId = RID_STR_PROPTITLE_DBGRID; break; + case FormComponentType::FILECONTROL: + nClassNameResourceId = RID_STR_PROPTITLE_FILECONTROL; break; + case FormComponentType::DATEFIELD: + nClassNameResourceId = RID_STR_PROPTITLE_DATEFIELD; break; + case FormComponentType::TIMEFIELD: + nClassNameResourceId = RID_STR_PROPTITLE_TIMEFIELD; break; + case FormComponentType::NUMERICFIELD: + nClassNameResourceId = RID_STR_PROPTITLE_NUMERICFIELD; break; + case FormComponentType::CURRENCYFIELD: + nClassNameResourceId = RID_STR_PROPTITLE_CURRENCYFIELD; break; + case FormComponentType::PATTERNFIELD: + nClassNameResourceId = RID_STR_PROPTITLE_PATTERNFIELD; break; + case FormComponentType::IMAGECONTROL: + nClassNameResourceId = RID_STR_PROPTITLE_IMAGECONTROL; break; + case FormComponentType::HIDDENCONTROL: + nClassNameResourceId = RID_STR_PROPTITLE_HIDDEN; break; + case FormComponentType::SCROLLBAR: + nClassNameResourceId = RID_STR_PROPTITLE_SCROLLBAR; break; + case FormComponentType::SPINBUTTON: + nClassNameResourceId = RID_STR_PROPTITLE_SPINBUTTON; break; + case FormComponentType::NAVIGATIONBAR: + nClassNameResourceId = RID_STR_PROPTITLE_NAVBAR; break; + case FormComponentType::CONTROL: + default: + nClassNameResourceId = RID_STR_CONTROL; break; + } + + if ( !nClassNameResourceId ) + return ::rtl::OUString(); + + return ::rtl::OUString( String( SVX_RES( nClassNameResourceId ) ) ); +} + +//======================================================================== +// class FmPropBrw +//======================================================================== +DBG_NAME(FmPropBrw); +//------------------------------------------------------------------------ +FmPropBrw::FmPropBrw( const Reference< XMultiServiceFactory >& _xORB, SfxBindings* _pBindings, + SfxChildWindow* _pMgr, Window* _pParent, const SfxChildWinInfo* _pInfo ) + :SfxFloatingWindow(_pBindings, _pMgr, _pParent, WinBits(WB_STDMODELESS|WB_SIZEABLE|WB_3DLOOK|WB_ROLLABLE) ) + ,SfxControllerItem(SID_FM_PROPERTY_CONTROL, *_pBindings) + ,m_bInitialStateChange(sal_True) + ,m_bInStateChange( false ) + ,m_xORB(_xORB) +{ + DBG_CTOR(FmPropBrw,NULL); + + ::Size aPropWinSize(STD_WIN_SIZE_X,STD_WIN_SIZE_Y); + SetMinOutputSizePixel(::Size(STD_MIN_SIZE_X,STD_MIN_SIZE_Y)); + SetOutputSizePixel(aPropWinSize); + SetUniqueId(UID_FORMPROPBROWSER_FRAME); + + try + { + // create a frame wrapper for myself + m_xMeAsFrame = Reference< XFrame >(m_xORB->createInstance(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Frame")) ), UNO_QUERY); + if (m_xMeAsFrame.is()) + { + // create an intermediate window, which is to be the container window of the frame + // Do *not* use |this| as container window for the frame, this would result in undefined + // responsiblity for this window (as soon as we initialize a frame with a window, the frame + // is responsible for it's life time, but |this| is controlled by the belonging SfxChildWindow) + // #i34249# - 2004-09-27 - fs@openoffice.org + Window* pContainerWindow = new Window( this ); + pContainerWindow->Show(); + m_xFrameContainerWindow = VCLUnoHelper::GetInterface ( pContainerWindow ); + + m_xMeAsFrame->initialize( m_xFrameContainerWindow ); + m_xMeAsFrame->setName(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("form property browser")) ); + if ( _pBindings->GetDispatcher() ) + { + ::com::sun::star::uno::Reference < ::com::sun::star::frame::XFramesSupplier > + xSupp ( _pBindings->GetDispatcher()->GetFrame()->GetFrame().GetFrameInterface(), ::com::sun::star::uno::UNO_QUERY ); +// if ( xSupp.is() ) +// xSupp->getFrames()->append( m_xMeAsFrame ); + // Don't append frame to frame hierachy to prevent UI_DEACTIVATE messages + // #i31834# - 2004-07-27 - cd@openoffice.org + } + } + } + catch (Exception&) + { + DBG_ERROR("FmPropBrw::FmPropBrw: could not create/initialize my frame!"); + m_xMeAsFrame.clear(); + } + + if (m_xMeAsFrame.is()) + _pMgr->SetFrame( m_xMeAsFrame ); + + + if ( m_xBrowserComponentWindow.is() ) + m_xBrowserComponentWindow->setVisible( sal_True ); + + if ( _pInfo ) + m_sLastActivePage = _pInfo->aExtraString; +} + +//------------------------------------------------------------------------ +void FmPropBrw::Resize() +{ + SfxFloatingWindow::Resize(); + + if ( m_xFrameContainerWindow.is() ) + { + try + { + ::Size aOutputSize( GetOutputSizePixel() ); + m_xFrameContainerWindow->setPosSize( 0, 0, aOutputSize.Width(), aOutputSize.Height(), awt::PosSize::POSSIZE ); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FmPropBrw::Resize: caught an exception!" ); + } + } +} + +//------------------------------------------------------------------------ +FmPropBrw::~FmPropBrw() +{ + if (m_xBrowserController.is()) + implDetachController(); + try + { + // remove our own properties from the component context. We cannot ensure that the component context + // is freed (there might be refcount problems :-\), so at least ensure the context itself + // does hold the objects anymore + Reference<XNameContainer> xName(m_xInspectorContext,uno::UNO_QUERY); + if ( xName.is() ) + { + const ::rtl::OUString pProps[] = { ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ContextDocument" ) ) + , ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DialogParentWindow" ) ) + , ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ControlContext" ) ) + , ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ControlShapeAccess" ) ) }; + for ( size_t i = 0; i < SAL_N_ELEMENTS(pProps); ++i ) + xName->removeByName( pProps[i] ); + } + } + catch (const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + DBG_DTOR(FmPropBrw,NULL); +} + +//----------------------------------------------------------------------- +::rtl::OUString FmPropBrw::getCurrentPage() const +{ + ::rtl::OUString sCurrentPage; + try + { + if ( m_xBrowserController.is() ) + { + OSL_VERIFY( m_xBrowserController->getViewData() >>= sCurrentPage ); + } + + if ( !sCurrentPage.getLength() ) + sCurrentPage = m_sLastActivePage; + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FmPropBrw::getCurrentPage: caught an exception while retrieving the current page!" ); + } + return sCurrentPage; +} + +//----------------------------------------------------------------------- +void FmPropBrw::implDetachController() +{ + m_sLastActivePage = getCurrentPage(); + + implSetNewSelection( InterfaceBag() ); + + if ( m_xMeAsFrame.is() ) + { + try + { + m_xMeAsFrame->setComponent(NULL, NULL); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FmPropBrw::implDetachController: caught an exception while resetting the component!" ); + } + } + + // we attached a frame to the controller manually, so we need to manually tell it that it's detached, too + // 96068 - 09.01.2002 - fs@openoffice.org + if ( m_xBrowserController.is() ) + m_xBrowserController->attachFrame( NULL ); + + m_xBrowserController.clear(); + m_xInspectorModel.clear(); + m_xMeAsFrame.clear(); +} + +//----------------------------------------------------------------------- +sal_Bool FmPropBrw::Close() +{ + // suspend the controller (it is allowed to veto) + if ( m_xMeAsFrame.is() ) + { + try + { + Reference< XController > xController( m_xMeAsFrame->getController() ); + if ( xController.is() && !xController->suspend( sal_True ) ) + return sal_False; + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FmPropBrw::Close: caught an exception while asking the controller!" ); + } + } + + implDetachController(); + + if( IsRollUp() ) + RollDown(); + + // remember our bindings: while we're closed, we're deleted, too, so accessing the bindings after this + // would be deadly + // 10/19/00 - 79321 - FS + SfxBindings& rBindings = SfxControllerItem::GetBindings(); + + sal_Bool bClose = SfxFloatingWindow::Close(); + + if (bClose) + { + rBindings.Invalidate(SID_FM_CTL_PROPERTIES); + rBindings.Invalidate(SID_FM_PROPERTIES); + } + + return bClose; +} + +//----------------------------------------------------------------------- +bool FmPropBrw::implIsReadOnlyModel() const +{ + try + { + if ( m_xInspectorModel.is() ) + return m_xInspectorModel->getIsReadOnly(); + return false; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return true; +} + +//----------------------------------------------------------------------- +void FmPropBrw::implSetNewSelection( const InterfaceBag& _rSelection ) +{ + if ( m_xBrowserController.is() ) + { + try + { + Reference< XObjectInspector > xInspector( m_xBrowserController, UNO_QUERY_THROW ); + + // tell it the objects to inspect + Sequence< Reference< XInterface > > aSelection( _rSelection.size() ); + ::std::copy( _rSelection.begin(), _rSelection.end(), aSelection.getArray() ); + + xInspector->inspect( aSelection ); + } + catch( const VetoException& ) + { + return; + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FmPropBrw::implSetNewSelection: caught an unexpected exception!" ); + return; + } + + // set the new title according to the selected object + String sTitle; + + if ( _rSelection.empty() ) + { + sTitle = String( SVX_RES( RID_STR_NO_PROPERTIES ) ); + } + else if ( _rSelection.size() > 1 ) + { + // no form component and (no form or no name) -> Multiselection + sTitle = String( SVX_RES( RID_STR_PROPERTIES_CONTROL ) ); + sTitle += String( SVX_RES( RID_STR_PROPTITLE_MULTISELECT ) ); + } + else + { + Reference< XPropertySet > xSingleSelection( *_rSelection.begin(), UNO_QUERY); + if ( ::comphelper::hasProperty( FM_PROP_CLASSID, xSingleSelection ) ) + { + sal_Int16 nClassID = FormComponentType::CONTROL; + xSingleSelection->getPropertyValue( FM_PROP_CLASSID ) >>= nClassID; + + sTitle = String( SVX_RES( RID_STR_PROPERTIES_CONTROL ) ); + sTitle += String( GetUIHeadlineName( nClassID, makeAny( xSingleSelection ) ) ); + } + else if ( Reference< XForm >( xSingleSelection, UNO_QUERY ).is() ) + sTitle = String( SVX_RES( RID_STR_PROPERTIES_FORM ) ); + } + + if ( implIsReadOnlyModel() ) + sTitle += String( SVX_RES( RID_STR_READONLY_VIEW ) ); + + SetText( sTitle ); + + // #95343# --------------------------------- + Reference< ::com::sun::star::awt::XLayoutConstrains > xLayoutConstrains( m_xBrowserController, UNO_QUERY ); + if( xLayoutConstrains.is() ) + { + ::Size aConstrainedSize; + ::com::sun::star::awt::Size aMinSize = xLayoutConstrains->getMinimumSize(); + + sal_Int32 nLeft(0), nTop(0), nRight(0), nBottom(0); + GetBorder( nLeft, nTop, nRight, nBottom ); + aMinSize.Width += nLeft + nRight + 8; + aMinSize.Height += nTop + nBottom + 8; + + aConstrainedSize.setHeight( aMinSize.Height ); + aConstrainedSize.setWidth( aMinSize.Width ); + SetMinOutputSizePixel( aConstrainedSize ); + aConstrainedSize = GetOutputSizePixel(); + sal_Bool bResize = sal_False; + if( aConstrainedSize.Width() < aMinSize.Width ) + { + aConstrainedSize.setWidth( aMinSize.Width ); + bResize = sal_True; + } + if( aConstrainedSize.Height() < aMinSize.Height ) + { + aConstrainedSize.setHeight( aMinSize.Height ); + bResize = sal_True; + } + if( bResize ) + SetOutputSizePixel( aConstrainedSize ); + } + } +} + +//----------------------------------------------------------------------- +void FmPropBrw::FillInfo( SfxChildWinInfo& rInfo ) const +{ + rInfo.bVisible = sal_False; + rInfo.aExtraString = getCurrentPage(); +} + +//----------------------------------------------------------------------- +IMPL_LINK( FmPropBrw, OnAsyncGetFocus, void*, /*NOTINTERESTEDIN*/ ) +{ + if (m_xBrowserComponentWindow.is()) + m_xBrowserComponentWindow->setFocus(); + return 0L; +} + +//----------------------------------------------------------------------- +namespace +{ + static bool lcl_shouldEnableHelpSection( const Reference< XMultiServiceFactory >& _rxFactory ) + { + const ::rtl::OUString sConfigName( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.Common/Forms/PropertyBrowser/" ) ); + const ::rtl::OUString sPropertyName( RTL_CONSTASCII_USTRINGPARAM( "DirectHelp" ) ); + + ::utl::OConfigurationTreeRoot aConfiguration( + ::utl::OConfigurationTreeRoot::createWithServiceFactory( _rxFactory, sConfigName ) ); + + bool bEnabled = false; + OSL_VERIFY( aConfiguration.getNodeValue( sPropertyName ) >>= bEnabled ); + return bEnabled; + } +} +//----------------------------------------------------------------------- +void FmPropBrw::impl_createPropertyBrowser_throw( FmFormShell* _pFormShell ) +{ + // the document in which we live + Reference< XInterface > xDocument; + if ( _pFormShell && _pFormShell->GetObjectShell() ) + xDocument = _pFormShell->GetObjectShell()->GetModel(); + + // the context of the controls in our document + Reference< awt::XControlContainer > xControlContext; + if ( _pFormShell && _pFormShell->GetFormView() ) + { + SdrPageView* pPageView = _pFormShell->GetFormView()->GetSdrPageView(); + + if(pPageView) + { + SdrPageWindow* pPageWindow = pPageView->GetPageWindow(0L); + + if(pPageWindow) + { + xControlContext = pPageWindow->GetControlContainer(); + } + } + } + + // the default parent window for message boxes + Reference< XWindow > xParentWindow( VCLUnoHelper::GetInterface ( this ) ); + + // the mapping from control models to control shapes + Reference< XMap > xControlMap; + FmFormPage* pFormPage = _pFormShell ? _pFormShell->GetCurPage() : NULL; + if ( pFormPage ) + xControlMap = pFormPage->GetImpl().getControlToShapeMap(); + + // our own component context + Reference< XPropertySet > xFactoryProperties( m_xORB, UNO_QUERY_THROW ); + Reference< XComponentContext > xOwnContext( + xFactoryProperties->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) ) ), + UNO_QUERY_THROW ); + + // a ComponentContext for the + ::cppu::ContextEntry_Init aHandlerContextInfo[] = + { + ::cppu::ContextEntry_Init( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ContextDocument" ) ), makeAny( xDocument ) ), + ::cppu::ContextEntry_Init( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DialogParentWindow" ) ), makeAny( xParentWindow ) ), + ::cppu::ContextEntry_Init( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ControlContext" ) ), makeAny( xControlContext ) ), + ::cppu::ContextEntry_Init( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ControlShapeAccess" ) ), makeAny( xControlMap ) ) + }; + m_xInspectorContext.set( + ::cppu::createComponentContext( aHandlerContextInfo, SAL_N_ELEMENTS( aHandlerContextInfo ), + xOwnContext ) ); + + bool bEnableHelpSection = lcl_shouldEnableHelpSection( m_xORB ); + + // an object inspector model + m_xInspectorModel = + bEnableHelpSection + ? DefaultFormComponentInspectorModel::createWithHelpSection( m_xInspectorContext, 3, 5 ) + : DefaultFormComponentInspectorModel::createDefault( m_xInspectorContext ); + + // an object inspector + m_xBrowserController = m_xBrowserController.query( + ObjectInspector::createWithModel( + m_xInspectorContext, m_xInspectorModel + ) ); + + if ( !m_xBrowserController.is() ) + { + ::rtl::OUString sServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.inspection.ObjectInspector" ) ); + ShowServiceNotAvailableError( GetParent(), sServiceName, sal_True ); + } + else + { + m_xBrowserController->attachFrame( m_xMeAsFrame ); + m_xBrowserComponentWindow = m_xMeAsFrame->getComponentWindow(); + DBG_ASSERT( m_xBrowserComponentWindow.is(), "FmPropBrw::impl_createPropertyBrowser_throw: attached the controller, but have no component window!" ); + } + + if ( bEnableHelpSection ) + { + Reference< XObjectInspector > xInspector( m_xBrowserController, UNO_QUERY_THROW ); + Reference< XObjectInspectorUI > xInspectorUI( xInspector->getInspectorUI() ); + Reference< XInterface > xDefaultHelpProvider( DefaultHelpProvider::create( m_xInspectorContext, xInspectorUI ) ); + } +} + +//----------------------------------------------------------------------- +void FmPropBrw::impl_ensurePropertyBrowser_nothrow( FmFormShell* _pFormShell ) +{ + // the document in which we live + Reference< XInterface > xDocument; + SfxObjectShell* pObjectShell = _pFormShell ? _pFormShell->GetObjectShell() : NULL; + if ( pObjectShell ) + xDocument = pObjectShell->GetModel(); + if ( ( xDocument == m_xLastKnownDocument ) && m_xBrowserController.is() ) + // nothing to do + return; + + try + { + // clean up any previous instances of the object inspector + if ( m_xMeAsFrame.is() ) + m_xMeAsFrame->setComponent( NULL, NULL ); + else + ::comphelper::disposeComponent( m_xBrowserController ); + m_xBrowserController.clear(); + m_xInspectorModel.clear(); + m_xBrowserComponentWindow.clear(); + + // and create a new one + impl_createPropertyBrowser_throw( _pFormShell ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + m_xLastKnownDocument = xDocument; +} + +//----------------------------------------------------------------------- +void FmPropBrw::StateChanged(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState) +{ + if (!pState || SID_FM_PROPERTY_CONTROL != nSID) + return; + + m_bInStateChange = true; + try + { + if (eState >= SFX_ITEM_AVAILABLE) + { + FmFormShell* pShell = PTR_CAST(FmFormShell,((SfxObjectItem*)pState)->GetShell()); + InterfaceBag aSelection; + if ( pShell ) + pShell->GetImpl()->getCurrentSelection( aSelection ); + + impl_ensurePropertyBrowser_nothrow( pShell ); + + // set the new object to inspect + implSetNewSelection( aSelection ); + + // if this is the first time we're here, some additional things need to be done ... + if ( m_bInitialStateChange ) + { + // if we're just newly created, we want to have the focus + PostUserEvent( LINK( this, FmPropBrw, OnAsyncGetFocus ) ); + + // and additionally, we want to show the page which was active during + // our previous incarnation + if ( m_sLastActivePage.getLength() ) + { + try + { + if ( m_xBrowserController.is() ) + m_xBrowserController->restoreViewData( makeAny( m_sLastActivePage ) ); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FmPropBrw::StateChanged: caught an exception while setting the initial page!" ); + } + } + + m_bInitialStateChange = sal_False; + } + + } + else + { + implSetNewSelection( InterfaceBag() ); + } + } + catch (Exception&) + { + DBG_ERROR("FmPropBrw::StateChanged: Exception occurred!"); + } + m_bInStateChange = false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmcontrolbordermanager.cxx b/svx/source/form/fmcontrolbordermanager.cxx new file mode 100644 index 000000000000..e5120ab60266 --- /dev/null +++ b/svx/source/form/fmcontrolbordermanager.cxx @@ -0,0 +1,443 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include "fmcontrolbordermanager.hxx" + +#include "fmprop.hrc" + +/** === begin UNO includes === **/ +#include <com/sun/star/form/validation/XValidatableFormComponent.hpp> +#include <com/sun/star/awt/XTextComponent.hpp> +#include <com/sun/star/awt/XListBox.hpp> +/** === end UNO includes === **/ +#include <tools/debug.hxx> + +//........................................................................ +namespace svxform +{ +//........................................................................ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::form::validation; + + //==================================================================== + //= helper + //==================================================================== + //-------------------------------------------------------------------- + static void setUnderline( const Reference< XVclWindowPeer >& _rxPeer, const UnderlineDescriptor& _rUnderline ) + { + OSL_ENSURE( _rxPeer.is(), "setUnderline: invalid peer!" ); + + // the underline type is an aspect of the font + FontDescriptor aFont; + OSL_VERIFY( _rxPeer->getProperty( FM_PROP_FONT ) >>= aFont ); + aFont.Underline = _rUnderline.nUnderlineType; + _rxPeer->setProperty( FM_PROP_FONT, makeAny( aFont ) ); + // the underline color is a separate property + _rxPeer->setProperty( FM_PROP_TEXTLINECOLOR, makeAny( _rUnderline.nUnderlineColor ) ); + } + + //-------------------------------------------------------------------- + static void getUnderline( const Reference< XVclWindowPeer >& _rxPeer, UnderlineDescriptor& _rUnderline ) + { + OSL_ENSURE( _rxPeer.is(), "getUnderline: invalid peer!" ); + + FontDescriptor aFont; + OSL_VERIFY( _rxPeer->getProperty( FM_PROP_FONT ) >>= aFont ); + _rUnderline.nUnderlineType = aFont.Underline; + + OSL_VERIFY( _rxPeer->getProperty( FM_PROP_TEXTLINECOLOR ) >>= _rUnderline.nUnderlineColor ); + } + + //-------------------------------------------------------------------- + static void getBorder( const Reference< XVclWindowPeer >& _rxPeer, BorderDescriptor& _rBoder ) + { + OSL_ENSURE( _rxPeer.is(), "getBorder: invalid peer!" ); + + OSL_VERIFY( _rxPeer->getProperty( FM_PROP_BORDER ) >>= _rBoder.nBorderType ); + OSL_VERIFY( _rxPeer->getProperty( FM_PROP_BORDERCOLOR ) >>= _rBoder.nBorderColor ); + } + + //-------------------------------------------------------------------- + static void setBorder( const Reference< XVclWindowPeer >& _rxPeer, const BorderDescriptor& _rBoder ) + { + OSL_ENSURE( _rxPeer.is(), "setBorder: invalid peer!" ); + + _rxPeer->setProperty( FM_PROP_BORDER, makeAny( _rBoder.nBorderType ) ); + _rxPeer->setProperty( FM_PROP_BORDERCOLOR, makeAny( _rBoder.nBorderColor ) ); + } + + //==================================================================== + //= ControlBorderManager + //==================================================================== + //-------------------------------------------------------------------- + ControlBorderManager::ControlBorderManager() + :m_nFocusColor ( 0x000000FF ) + ,m_nMouseHoveColor( 0x007098BE ) + ,m_nInvalidColor ( 0x00FF0000 ) + ,m_bDynamicBorderColors( false ) + { + } + + //-------------------------------------------------------------------- + ControlBorderManager::~ControlBorderManager() + { + } + + //-------------------------------------------------------------------- + bool ControlBorderManager::canColorBorder( const Reference< XVclWindowPeer >& _rxPeer ) + { + OSL_PRECOND( _rxPeer.is(), "ControlBorderManager::canColorBorder: invalid peer!" ); + + PeerBag::const_iterator aPos = m_aColorableControls.find( _rxPeer ); + if ( aPos != m_aColorableControls.end() ) + return true; + + aPos = m_aNonColorableControls.find( _rxPeer ); + if ( aPos != m_aNonColorableControls.end() ) + return false; + + // this peer is not yet known + + // no border coloring for controls which are not for text input + // #i37434# / 2004-11-19 / frank.schoenheit@sun.com + Reference< XTextComponent > xText( _rxPeer, UNO_QUERY ); + Reference< XListBox > xListBox( _rxPeer, UNO_QUERY ); + if ( xText.is() || xListBox.is() ) + { + sal_Int16 nBorderStyle = VisualEffect::NONE; + OSL_VERIFY( _rxPeer->getProperty( FM_PROP_BORDER ) >>= nBorderStyle ); + if ( nBorderStyle == VisualEffect::FLAT ) + // if you change this to also accept LOOK3D, then this would also work, but look ugly + { + m_aColorableControls.insert( _rxPeer ); + return true; + } + } + + m_aNonColorableControls.insert( _rxPeer ); + return false; + } + + //-------------------------------------------------------------------- + ControlStatus ControlBorderManager::getControlStatus( const Reference< XControl >& _rxControl ) SAL_THROW(()) + { + ControlStatus nStatus = CONTROL_STATUS_NONE; + + if ( _rxControl.get() == m_aFocusControl.xControl.get() ) + nStatus |= CONTROL_STATUS_FOCUSED; + + if ( _rxControl.get() == m_aMouseHoverControl.xControl.get() ) + nStatus |= CONTROL_STATUS_MOUSE_HOVER; + + if ( m_aInvalidControls.find( ControlData( _rxControl ) ) != m_aInvalidControls.end() ) + nStatus |= CONTROL_STATUS_INVALID; + + return nStatus; + } + + //-------------------------------------------------------------------- + sal_Int32 ControlBorderManager::getControlColorByStatus( ControlStatus _nStatus ) + { + // "invalid" is ranked highest + if ( _nStatus & CONTROL_STATUS_INVALID ) + return m_nInvalidColor; + + // then, "focused" is more important than ... + if ( _nStatus & CONTROL_STATUS_FOCUSED ) + return m_nFocusColor; + + // ... "mouse over" + if ( _nStatus & CONTROL_STATUS_MOUSE_HOVER ) + return m_nMouseHoveColor; + + OSL_ENSURE( sal_False, "ControlBorderManager::getControlColorByStatus: invalid status!" ); + return 0x00000000; + } + + //-------------------------------------------------------------------- + void ControlBorderManager::updateBorderStyle( const Reference< XControl >& _rxControl, const Reference< XVclWindowPeer >& _rxPeer, const BorderDescriptor& _rFallback ) SAL_THROW(()) + { + OSL_PRECOND( _rxControl.is() && _rxPeer.is(), "ControlBorderManager::updateBorderStyle: invalid parameters!" ); + + ControlStatus nStatus = getControlStatus( _rxControl ); + BorderDescriptor aBorder; + aBorder.nBorderType = ( nStatus == CONTROL_STATUS_NONE ) + ? _rFallback.nBorderType + : VisualEffect::FLAT; + aBorder.nBorderColor = ( nStatus == CONTROL_STATUS_NONE ) + ? _rFallback.nBorderColor + : getControlColorByStatus( nStatus ); + setBorder( _rxPeer, aBorder ); + } + + //-------------------------------------------------------------------- + void ControlBorderManager::determineOriginalBorderStyle( const Reference< XControl >& _rxControl, BorderDescriptor& _rData ) const + { + _rData = ControlData(); + if ( m_aFocusControl.xControl.get() == _rxControl.get() ) + { + _rData = m_aFocusControl; + } + else if ( m_aMouseHoverControl.xControl.get() == _rxControl.get() ) + { + _rData = m_aMouseHoverControl; + } + else + { + ControlBag::const_iterator aPos = m_aInvalidControls.find( _rxControl ); + if ( aPos != m_aInvalidControls.end() ) + { + _rData = *aPos; + } + else + { + Reference< XVclWindowPeer > xPeer( _rxControl->getPeer(), UNO_QUERY ); + getBorder( xPeer, _rData ); + } + } + } + + //-------------------------------------------------------------------- + void ControlBorderManager::controlStatusGained( const Reference< XInterface >& _rxControl, ControlData& _rControlData ) SAL_THROW(()) + { + if ( _rxControl == _rControlData.xControl ) + // nothing to do - though suspicious + return; + + Reference< XControl > xAsControl( _rxControl, UNO_QUERY ); + DBG_ASSERT( xAsControl.is(), "ControlBorderManager::controlStatusGained: invalid control!" ); + if ( !xAsControl.is() ) + return; + + try + { + Reference< XVclWindowPeer > xPeer( xAsControl->getPeer(), UNO_QUERY ); + if ( xPeer.is() && canColorBorder( xPeer ) ) + { + // remember the control and it's current border color + _rControlData.xControl.clear(); // so determineOriginalBorderStyle doesn't get confused + + determineOriginalBorderStyle( xAsControl, _rControlData ); + + _rControlData.xControl = xAsControl; + + updateBorderStyle( xAsControl, xPeer, _rControlData ); + } + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "ControlBorderManager::controlStatusGained: caught an exception!" ); + } + } + + //-------------------------------------------------------------------- + void ControlBorderManager::controlStatusLost( const Reference< XInterface >& _rxControl, ControlData& _rControlData ) SAL_THROW(()) + { + if ( _rxControl != _rControlData.xControl ) + // nothing to do + return; + + OSL_PRECOND( _rControlData.xControl.is(), "ControlBorderManager::controlStatusLost: invalid control data - this will crash!" ); + try + { + Reference< XVclWindowPeer > xPeer( _rControlData.xControl->getPeer(), UNO_QUERY ); + if ( xPeer.is() && canColorBorder( xPeer ) ) + { + ControlData aPreviousStatus( _rControlData ); + _rControlData = ControlData(); + updateBorderStyle( aPreviousStatus.xControl, xPeer, aPreviousStatus ); + } + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "ControlBorderManager::controlStatusLost: caught an exception!" ); + } + } + + //-------------------------------------------------------------------- + void ControlBorderManager::enableDynamicBorderColor( ) + { + m_bDynamicBorderColors = true; + } + + //-------------------------------------------------------------------- + void ControlBorderManager::disableDynamicBorderColor( ) + { + m_bDynamicBorderColors = false; + restoreAll(); + } + + //-------------------------------------------------------------------- + void ControlBorderManager::setStatusColor( ControlStatus _nStatus, sal_Int32 _nColor ) + { + switch ( _nStatus ) + { + case CONTROL_STATUS_FOCUSED: + m_nFocusColor = _nColor; + break; + case CONTROL_STATUS_MOUSE_HOVER: + m_nMouseHoveColor = _nColor; + break; + case CONTROL_STATUS_INVALID: + m_nInvalidColor = _nColor; + break; + default: + OSL_ENSURE( sal_False, "ControlBorderManager::setStatusColor: invalid status!" ); + } + } + + //-------------------------------------------------------------------- + void ControlBorderManager::restoreAll() + { + if ( m_aFocusControl.xControl.is() ) + controlStatusLost( m_aFocusControl.xControl, m_aFocusControl ); + if ( m_aMouseHoverControl.xControl.is() ) + controlStatusLost( m_aMouseHoverControl.xControl, m_aMouseHoverControl ); + + ControlBag aInvalidControls; + m_aInvalidControls.swap( aInvalidControls ); + + for ( ControlBag::const_iterator loop = aInvalidControls.begin(); + loop != aInvalidControls.end(); + ++loop + ) + { + Reference< XVclWindowPeer > xPeer( loop->xControl->getPeer(), UNO_QUERY ); + if ( xPeer.is() ) + { + updateBorderStyle( loop->xControl, xPeer, *loop ); + xPeer->setProperty( FM_PROP_HELPTEXT, makeAny( loop->sOriginalHelpText ) ); + setUnderline( xPeer, *loop ); + } + } + } + + //-------------------------------------------------------------------- + void ControlBorderManager::focusGained( const Reference< XInterface >& _rxControl ) SAL_THROW(()) + { + if ( m_bDynamicBorderColors ) + controlStatusGained( _rxControl, m_aFocusControl ); + } + + //-------------------------------------------------------------------- + void ControlBorderManager::focusLost( const Reference< XInterface >& _rxControl ) SAL_THROW(()) + { + if ( m_bDynamicBorderColors ) + controlStatusLost( _rxControl, m_aFocusControl ); + } + + //-------------------------------------------------------------------- + void ControlBorderManager::mouseEntered( const Reference< XInterface >& _rxControl ) SAL_THROW(()) + { + if ( m_bDynamicBorderColors ) + controlStatusGained( _rxControl, m_aMouseHoverControl ); + } + + //-------------------------------------------------------------------- + void ControlBorderManager::mouseExited( const Reference< XInterface >& _rxControl ) SAL_THROW(()) + { + if ( m_bDynamicBorderColors ) + controlStatusLost( _rxControl, m_aMouseHoverControl ); + } + + //-------------------------------------------------------------------- + void ControlBorderManager::validityChanged( const Reference< XControl >& _rxControl, const Reference< XValidatableFormComponent >& _rxValidatable ) SAL_THROW(()) + { + try + { + OSL_ENSURE( _rxControl.is(), "ControlBorderManager::validityChanged: invalid control!" ); + OSL_ENSURE( _rxValidatable.is(), "ControlBorderManager::validityChanged: invalid validatable!" ); + + Reference< XVclWindowPeer > xPeer( _rxControl.is() ? _rxControl->getPeer() : Reference< XWindowPeer >(), UNO_QUERY ); + if ( !xPeer.is() || !_rxValidatable.is() ) + return; + + ControlData aData( _rxControl ); + + if ( _rxValidatable->isValid() ) + { + ControlBag::iterator aPos = m_aInvalidControls.find( aData ); + if ( aPos != m_aInvalidControls.end() ) + { // invalid before, valid now + ControlData aOriginalLayout( *aPos ); + m_aInvalidControls.erase( aPos ); + + // restore all the things we used to indicate invalidity + if ( m_bDynamicBorderColors ) + updateBorderStyle( _rxControl, xPeer, aOriginalLayout ); + xPeer->setProperty( FM_PROP_HELPTEXT, makeAny( aOriginalLayout.sOriginalHelpText ) ); + setUnderline( xPeer, aOriginalLayout ); + } + return; + } + + // we're here in the INVALID case + if ( m_aInvalidControls.find( _rxControl ) == m_aInvalidControls.end() ) + { // valid before, invalid now + + // remember the current border + determineOriginalBorderStyle( _rxControl, aData ); + // and tool tip + xPeer->getProperty( FM_PROP_HELPTEXT ) >>= aData.sOriginalHelpText; + // and font + getUnderline( xPeer, aData ); + + m_aInvalidControls.insert( aData ); + + // update the border to the new invalidity + if ( m_bDynamicBorderColors && canColorBorder( xPeer ) ) + updateBorderStyle( _rxControl, xPeer, aData ); + else + { + // and also the new font + setUnderline( xPeer, UnderlineDescriptor( com::sun::star::awt::FontUnderline::WAVE, m_nInvalidColor ) ); + } + } + + // update the explanation for invalidity (this is always done, even if the validity did not change) + Reference< XValidator > xValidator = _rxValidatable->getValidator(); + OSL_ENSURE( xValidator.is(), "ControlBorderManager::validityChanged: invalid, but no validator?" ); + ::rtl::OUString sExplainInvalidity = xValidator.is() ? xValidator->explainInvalid( _rxValidatable->getCurrentValue() ) : ::rtl::OUString(); + xPeer->setProperty( FM_PROP_HELPTEXT, makeAny( sExplainInvalidity ) ); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "ControlBorderManager::validityChanged: caught an exception!" ); + } + } + +//........................................................................ +} // namespace svxform +//........................................................................ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmcontrollayout.cxx b/svx/source/form/fmcontrollayout.cxx new file mode 100644 index 000000000000..5c590448b789 --- /dev/null +++ b/svx/source/form/fmcontrollayout.cxx @@ -0,0 +1,331 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include "fmcontrollayout.hxx" +#include "fmprop.hrc" + +/** === begin UNO includes === **/ +#include <com/sun/star/form/FormComponentType.hpp> +#include <com/sun/star/awt/VisualEffect.hpp> +#include <com/sun/star/i18n/ScriptType.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/awt/FontDescriptor.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/container/XChild.hpp> +/** === end UNO includes === **/ + +#include <comphelper/processfactory.hxx> +#include <i18npool/mslangid.hxx> +#include <unotools/syslocale.hxx> + +#include <toolkit/helper/vclunohelper.hxx> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/outdev.hxx> + +//........................................................................ +namespace svxform +{ +//........................................................................ + + using namespace ::utl; + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::makeAny; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Type; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::beans::XPropertySetInfo; + using ::com::sun::star::lang::Locale; + using ::com::sun::star::awt::FontDescriptor; + using ::com::sun::star::style::XStyleFamiliesSupplier; + using ::com::sun::star::lang::XServiceInfo; + using ::com::sun::star::container::XNameAccess; + using ::com::sun::star::container::XChild; + /** === end UNO using === **/ + namespace FormComponentType = ::com::sun::star::form::FormComponentType; + namespace VisualEffect = ::com::sun::star::awt::VisualEffect; + namespace ScriptType = ::com::sun::star::i18n::ScriptType; + + //-------------------------------------------------------------------- + namespace + { + //.................................................................... + template< class INTERFACE_TYPE > + Reference< INTERFACE_TYPE > getTypedModelNode( const Reference< XInterface >& _rxModelNode ) + { + Reference< INTERFACE_TYPE > xTypedNode( _rxModelNode, UNO_QUERY ); + if ( xTypedNode.is() ) + return xTypedNode; + else + { + Reference< XChild > xChild( _rxModelNode, UNO_QUERY ); + if ( xChild.is() ) + return getTypedModelNode< INTERFACE_TYPE >( xChild->getParent() ); + else + return NULL; + } + } + + //.................................................................... + static bool lcl_getDocumentDefaultStyleAndFamily( const Reference< XInterface >& _rxDocument, ::rtl::OUString& _rFamilyName, ::rtl::OUString& _rStyleName ) SAL_THROW(( Exception )) + { + bool bSuccess = true; + Reference< XServiceInfo > xDocumentSI( _rxDocument, UNO_QUERY ); + if ( xDocumentSI.is() ) + { + if ( xDocumentSI->supportsService( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.text.TextDocument" ) ) ) + || xDocumentSI->supportsService( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.text.WebDocument" ) ) ) + ) + { + _rFamilyName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ParagraphStyles" ) ); + _rStyleName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Standard" ) ); + } + else if ( xDocumentSI->supportsService( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sheet.SpreadsheetDocument" ) ) ) ) + { + _rFamilyName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CellStyles" ) ); + _rStyleName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Default" ) ); + } + else if ( xDocumentSI->supportsService( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.drawing.DrawingDocument" ) ) ) + || xDocumentSI->supportsService( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.presentation.PresentationDocument" ) ) ) + ) + { + _rFamilyName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "graphics" ) ); + _rStyleName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "standard" ) ); + } + else + bSuccess = false; + } + return bSuccess; + } + + //.................................................................... + static void lcl_initializeControlFont( const Reference< XPropertySet >& _rxModel ) + { + try + { + Reference< XPropertySet > xStyle( ControlLayouter::getDefaultDocumentTextStyle( _rxModel ), UNO_SET_THROW ); + Reference< XPropertySetInfo > xStylePSI( xStyle->getPropertySetInfo(), UNO_SET_THROW ); + + // determine the script type associated with the system locale + const SvtSysLocale aSysLocale; + const LocaleDataWrapper& rSysLocaleData = aSysLocale.GetLocaleData(); + const sal_Int16 eSysLocaleScriptType = MsLangId::getScriptType( MsLangId::convertLocaleToLanguage( rSysLocaleData.getLocale() ) ); + + // depending on this script type, use the right property from the document's style which controls the + // default locale for document content + const sal_Char* pCharLocalePropertyName = "CharLocale"; + switch ( eSysLocaleScriptType ) + { + case ScriptType::LATIN: + // already defaulted above + break; + case ScriptType::ASIAN: + pCharLocalePropertyName = "CharLocaleAsian"; + break; + case ScriptType::COMPLEX: + pCharLocalePropertyName = "CharLocaleComplex"; + break; + default: + OSL_ENSURE( false, "lcl_initializeControlFont: unexpected script type for system locale!" ); + break; + } + + ::rtl::OUString sCharLocalePropertyName = ::rtl::OUString::createFromAscii( pCharLocalePropertyName ); + Locale aDocumentCharLocale; + if ( xStylePSI->hasPropertyByName( sCharLocalePropertyName ) ) + { + OSL_VERIFY( xStyle->getPropertyValue( sCharLocalePropertyName ) >>= aDocumentCharLocale ); + } + // fall back to CharLocale property at the style + if ( !aDocumentCharLocale.Language.getLength() ) + { + sCharLocalePropertyName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CharLocale" ) ); + if ( xStylePSI->hasPropertyByName( sCharLocalePropertyName ) ) + { + OSL_VERIFY( xStyle->getPropertyValue( sCharLocalePropertyName ) >>= aDocumentCharLocale ); + } + } + // fall back to the system locale + if ( !aDocumentCharLocale.Language.getLength() ) + { + aDocumentCharLocale = rSysLocaleData.getLocale(); + } + + // retrieve a default font for this locale, and set it at the control + Font aFont = OutputDevice::GetDefaultFont( DEFAULTFONT_SANS, MsLangId::convertLocaleToLanguage( aDocumentCharLocale ), DEFAULTFONT_FLAGS_ONLYONE ); + FontDescriptor aFontDesc = VCLUnoHelper::CreateFontDescriptor( aFont ); + _rxModel->setPropertyValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FontDescriptor" ) ), + makeAny( aFontDesc ) + ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + } + + //==================================================================== + //= ControlLayouter + //==================================================================== + //-------------------------------------------------------------------- + Reference< XPropertySet > ControlLayouter::getDefaultDocumentTextStyle( const Reference< XPropertySet >& _rxModel ) + { + // the style family collection + Reference< XStyleFamiliesSupplier > xSuppStyleFamilies( getTypedModelNode< XStyleFamiliesSupplier >( _rxModel.get() ), UNO_SET_THROW ); + Reference< XNameAccess > xStyleFamilies( xSuppStyleFamilies->getStyleFamilies(), UNO_SET_THROW ); + + // the names of the family, and the style - depends on the document type we live in + ::rtl::OUString sFamilyName, sStyleName; + if ( !lcl_getDocumentDefaultStyleAndFamily( xSuppStyleFamilies.get(), sFamilyName, sStyleName ) ) + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "unknown document type!" ) ), NULL ); + + // the concrete style + Reference< XNameAccess > xStyleFamily( xStyleFamilies->getByName( sFamilyName ), UNO_QUERY_THROW ); + return Reference< XPropertySet >( xStyleFamily->getByName( sStyleName ), UNO_QUERY_THROW ); + } + + //-------------------------------------------------------------------- + void ControlLayouter::initializeControlLayout( const Reference< XPropertySet >& _rxControlModel, DocumentType _eDocType ) + { + DBG_ASSERT( _rxControlModel.is(), "ControlLayouter::initializeControlLayout: invalid model!" ); + if ( !_rxControlModel.is() ) + return; + + try + { + Reference< XPropertySetInfo > xPSI( _rxControlModel->getPropertySetInfo(), UNO_SET_THROW ); + + // the control type + sal_Int16 nClassId = FormComponentType::CONTROL; + _rxControlModel->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId; + + // the document type + if ( _eDocType == eUnknownDocumentType ) + _eDocType = DocumentClassification::classifyHostDocument( _rxControlModel.get() ); + + // let's see what the configuration says about the visual effect + OConfigurationNode aConfig = getLayoutSettings( _eDocType ); + Any aVisualEffect = aConfig.getNodeValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VisualEffect" ) ) ); + if ( aVisualEffect.hasValue() ) + { + ::rtl::OUString sVisualEffect; + OSL_VERIFY( aVisualEffect >>= sVisualEffect ); + + sal_Int16 nVisualEffect = VisualEffect::NONE; + if ( sVisualEffect.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "flat" ) ) ) + nVisualEffect = VisualEffect::FLAT; + else if ( sVisualEffect.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "3D" ) ) ) + nVisualEffect = VisualEffect::LOOK3D; + + if ( xPSI->hasPropertyByName( FM_PROP_BORDER ) ) + { + if ( ( nClassId != FormComponentType::COMMANDBUTTON ) + && ( nClassId != FormComponentType::RADIOBUTTON ) + && ( nClassId != FormComponentType::CHECKBOX ) + && ( nClassId != FormComponentType::GROUPBOX ) + && ( nClassId != FormComponentType::FIXEDTEXT ) + && ( nClassId != FormComponentType::SCROLLBAR ) + && ( nClassId != FormComponentType::SPINBUTTON ) + ) + { + _rxControlModel->setPropertyValue( FM_PROP_BORDER, makeAny( nVisualEffect ) ); + if ( ( nVisualEffect == VisualEffect::FLAT ) + && ( xPSI->hasPropertyByName( FM_PROP_BORDERCOLOR ) ) + ) + // light gray flat border + _rxControlModel->setPropertyValue( FM_PROP_BORDERCOLOR, makeAny( (sal_Int32)0x00C0C0C0 ) ); + } + } + if ( xPSI->hasPropertyByName( FM_PROP_VISUALEFFECT ) ) + _rxControlModel->setPropertyValue( FM_PROP_VISUALEFFECT, makeAny( nVisualEffect ) ); + } + + // the font (only if we use the document's ref devices for rendering control text, otherwise, the + // default font of VCL controls is assumed to be fine) + if ( useDocumentReferenceDevice( _eDocType ) + && xPSI->hasPropertyByName( FM_PROP_FONT ) + ) + lcl_initializeControlFont( _rxControlModel ); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "ControlLayouter::initializeControlLayout: caught an exception!" ); + } + } + + //-------------------------------------------------------------------- + ::utl::OConfigurationNode ControlLayouter::getLayoutSettings( DocumentType _eDocType ) + { + ::rtl::OUString sConfigName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.Common/Forms/ControlLayout/" ) ); + sConfigName += DocumentClassification::getModuleIdentifierForDocumentType( _eDocType ); + return OConfigurationTreeRoot::createWithServiceFactory( + ::comphelper::getProcessServiceFactory(), // TODO + sConfigName ); + } + + //-------------------------------------------------------------------- + bool ControlLayouter::useDynamicBorderColor( DocumentType _eDocType ) + { + OConfigurationNode aConfig = getLayoutSettings( _eDocType ); + Any aDynamicBorderColor = aConfig.getNodeValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DynamicBorderColors" ) ) ); + bool bDynamicBorderColor = false; + OSL_VERIFY( aDynamicBorderColor >>= bDynamicBorderColor ); + return bDynamicBorderColor; + } + + //-------------------------------------------------------------------- + bool ControlLayouter::useDocumentReferenceDevice( DocumentType _eDocType ) + { + if ( _eDocType == eUnknownDocumentType ) + return false; + OConfigurationNode aConfig = getLayoutSettings( _eDocType ); + Any aUseRefDevice = aConfig.getNodeValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UseDocumentTextMetrics" ) ) ); + bool bUseRefDevice = false; + OSL_VERIFY( aUseRefDevice >>= bUseRefDevice ); + return bUseRefDevice; + } + +//........................................................................ +} // namespace svxform +//........................................................................ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmdmod.cxx b/svx/source/form/fmdmod.cxx new file mode 100644 index 000000000000..807919e60a2f --- /dev/null +++ b/svx/source/form/fmdmod.cxx @@ -0,0 +1,134 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include <sal/macros.h> +#include <svx/fmdmod.hxx> +#include "fmservs.hxx" +#include <fmobj.hxx> +#include <svx/unoshape.hxx> +#include <comphelper/processfactory.hxx> +#include <svx/fmglob.hxx> + +using namespace ::svxform; + +//----------------------------------------------------------------------------- +::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL SvxFmMSFactory::createInstance(const ::rtl::OUString& ServiceSpecifier) throw( ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException ) +{ + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xRet; + if ( ServiceSpecifier.indexOf( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.form.component.")) ) == 0 ) + { + xRet = ::comphelper::getProcessServiceFactory()->createInstance(ServiceSpecifier); + } + else if ( ServiceSpecifier == ::rtl::OUString( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.drawing.ControlShape")) ) ) + { + SdrObject* pObj = new FmFormObj(OBJ_FM_CONTROL); + xRet = *new SvxShapeControl(pObj); + } + if (!xRet.is()) + xRet = SvxUnoDrawMSFactory::createInstance(ServiceSpecifier); + return xRet; +} + +//----------------------------------------------------------------------------- +::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL SvxFmMSFactory::createInstanceWithArguments(const ::rtl::OUString& ServiceSpecifier, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& Arguments) throw( ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException ) +{ + return SvxUnoDrawMSFactory::createInstanceWithArguments(ServiceSpecifier, Arguments ); +} + +//----------------------------------------------------------------------------- +::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL SvxFmMSFactory::getAvailableServiceNames(void) throw( ::com::sun::star::uno::RuntimeException ) +{ + static const ::rtl::OUString aSvxComponentServiceNameList[] = + { + FM_SUN_COMPONENT_TEXTFIELD, + FM_SUN_COMPONENT_FORM, + FM_SUN_COMPONENT_LISTBOX, + FM_SUN_COMPONENT_COMBOBOX, + FM_SUN_COMPONENT_RADIOBUTTON, + FM_SUN_COMPONENT_GROUPBOX, + FM_SUN_COMPONENT_FIXEDTEXT, + FM_SUN_COMPONENT_COMMANDBUTTON, + FM_SUN_COMPONENT_CHECKBOX, + FM_SUN_COMPONENT_GRIDCONTROL, + FM_SUN_COMPONENT_IMAGEBUTTON, + FM_SUN_COMPONENT_FILECONTROL, + FM_SUN_COMPONENT_TIMEFIELD, + FM_SUN_COMPONENT_DATEFIELD, + FM_SUN_COMPONENT_NUMERICFIELD, + FM_SUN_COMPONENT_CURRENCYFIELD, + FM_SUN_COMPONENT_PATTERNFIELD, + FM_SUN_COMPONENT_HIDDENCONTROL, + FM_SUN_COMPONENT_IMAGECONTROL + }; + + static const sal_uInt16 nSvxComponentServiceNameListCount = SAL_N_ELEMENTS(aSvxComponentServiceNameList); + + ::com::sun::star::uno::Sequence< ::rtl::OUString > aSeq( nSvxComponentServiceNameListCount ); + ::rtl::OUString* pStrings = aSeq.getArray(); + for( sal_uInt16 nIdx = 0; nIdx < nSvxComponentServiceNameListCount; nIdx++ ) + pStrings[nIdx] = aSvxComponentServiceNameList[nIdx]; + + ::com::sun::star::uno::Sequence< ::rtl::OUString > aParentSeq( SvxUnoDrawMSFactory::getAvailableServiceNames() ); + return concatServiceNames( aParentSeq, aSeq ); +} + +/* +// XServiceManager +::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SvxFmDrawModel::createInstance(const ::rtl::OUString& ServiceName) + const throw( ::com::sun::star::lang::ServiceNotRegisteredException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException ) +{ + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xRet; + sal_uInt16 nTokenCount = ServiceName.getTokenCount('.'); + if (nTokenCount == 5 && + ServiceName.getToken( 0, '.' ) == ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("stardiv")) && + ServiceName.getToken( 1, '.' ) == ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("one")) && + ServiceName.getToken( 2, '.' ) == ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("form")) && + ServiceName.getToken( 3, '.' ) == ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("component")) ) + { + xRet = ::comphelper::getProcessServiceFactory()->createInstance(ServiceName); + } + else + if (nTokenCount == 4 && + ServiceName.getToken( 0, '.' ) == ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("stardiv")) && + ServiceName.getToken( 1, '.' ) == ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("one")) && + ServiceName.getToken( 2, '.' ) == ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("drawing")) && + ServiceName.getToken( 3, '.' ) == ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ControlShape")) ) + { + SdrObject* pObj = new FmFormObj(); + xRet = *new SvxShapeControl(pObj); + } + if (!xRet.is()) + xRet = SvxUnoDrawModel::createInstance(ServiceName); + return xRet; +} +*/ + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmdocumentclassification.cxx b/svx/source/form/fmdocumentclassification.cxx new file mode 100644 index 000000000000..34083dae5108 --- /dev/null +++ b/svx/source/form/fmdocumentclassification.cxx @@ -0,0 +1,214 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include "fmdocumentclassification.hxx" +#include "svx/dbtoolsclient.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/xforms/XFormsSupplier.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/frame/XModule.hpp> +/** === end UNO includes === **/ + +#include <tools/diagnose_ex.h> + +//........................................................................ +namespace svxform +{ +//........................................................................ + + namespace + { + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::container::XChild; + using ::com::sun::star::frame::XModel; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::frame::XModule; + + //.................................................................... + template< class TYPE > + Reference< TYPE > getTypedModelNode( const Reference< XInterface >& _rxModelNode ) + { + Reference< TYPE > xTypedNode( _rxModelNode, UNO_QUERY ); + if ( xTypedNode.is() ) + return xTypedNode; + else + { + Reference< XChild > xChild( _rxModelNode, UNO_QUERY ); + if ( xChild.is() ) + return getTypedModelNode< TYPE >( xChild->getParent() ); + else + return Reference< TYPE >(); + } + } + + //.................................................................... + Reference< XModel > getDocument( const Reference< XInterface >& _rxModelNode ) + { + return getTypedModelNode< XModel >( _rxModelNode ); + } + } + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::xforms; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::sdbc; + + //==================================================================== + //==================================================================== + namespace + { + //---------------------------------------------------------------- + struct ModuleInfo + { + const sal_Char* pAsciiModuleOrServiceName; + DocumentType eType; + }; + + //---------------------------------------------------------------- + const ModuleInfo* lcl_getModuleInfo() + { + static const ModuleInfo aModuleInfo[] = + { + { "com.sun.star.text.TextDocument", eTextDocument }, + { "com.sun.star.text.WebDocument", eWebDocument }, + { "com.sun.star.sheet.SpreadsheetDocument", eSpreadsheetDocument }, + { "com.sun.star.drawing.DrawingDocument", eDrawingDocument }, + { "com.sun.star.presentation.PresentationDocument", ePresentationDocument }, + { "com.sun.star.xforms.XMLFormDocument", eEnhancedForm }, + { "com.sun.star.sdb.FormDesign", eDatabaseForm }, + { "com.sun.star.sdb.TextReportDesign", eDatabaseReport }, + { "com.sun.star.text.GlobalDocument", eTextDocument }, + { NULL, eUnknownDocumentType } + }; + return aModuleInfo; + } + } + + //==================================================================== + //= DocumentClassification + //==================================================================== + //-------------------------------------------------------------------- + DocumentType DocumentClassification::classifyDocument( const Reference< XModel >& _rxDocumentModel ) SAL_THROW(()) + { + DocumentType eType( eUnknownDocumentType ); + + OSL_ENSURE( _rxDocumentModel.is(), "DocumentClassification::classifyDocument: invalid document!" ); + if ( !_rxDocumentModel.is() ) + return eType; + + try + { + // first, check whether the document has a ModuleIdentifier which we know + ::rtl::OUString sModuleIdentifier; + Reference< XModule > xModule( _rxDocumentModel, UNO_QUERY ); + if ( xModule.is() ) + eType = getDocumentTypeForModuleIdentifier( xModule->getIdentifier() ); + if ( eType != eUnknownDocumentType ) + return eType; + + // second, check whether it supports one of the services we know + Reference< XServiceInfo > xSI( _rxDocumentModel, UNO_QUERY_THROW ); + const ModuleInfo* pModuleInfo = lcl_getModuleInfo(); + while ( pModuleInfo->pAsciiModuleOrServiceName ) + { + if ( xSI->supportsService( ::rtl::OUString::createFromAscii( pModuleInfo->pAsciiModuleOrServiceName ) ) ) + return pModuleInfo->eType; + ++pModuleInfo; + } + + // last: uhm, there is no last resort + OSL_ENSURE( false, "DocumentClassification::classifyDocument: unknown document!" ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + return eType; + } + + //-------------------------------------------------------------------- + DocumentType DocumentClassification::classifyHostDocument( const Reference< XInterface >& _rxFormComponent ) SAL_THROW(()) + { + DocumentType eType( eUnknownDocumentType ); + + try + { + Reference< XModel > xDocument( getDocument( _rxFormComponent.get() ) ); + if ( !xDocument.is() ) + return eUnknownDocumentType; + eType = classifyDocument( xDocument ); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "DocumentClassification::classifyHostDocument: caught an exception!" ); + } + + return eType; + } + + //-------------------------------------------------------------------- + DocumentType DocumentClassification::getDocumentTypeForModuleIdentifier( const ::rtl::OUString& _rModuleIdentifier ) + { + const ModuleInfo* pModuleInfo = lcl_getModuleInfo(); + while ( pModuleInfo->pAsciiModuleOrServiceName ) + { + if ( _rModuleIdentifier.equalsAscii( pModuleInfo->pAsciiModuleOrServiceName ) ) + return pModuleInfo->eType; + ++pModuleInfo; + } + return eUnknownDocumentType; + } + + //-------------------------------------------------------------------- + ::rtl::OUString DocumentClassification::getModuleIdentifierForDocumentType( DocumentType _eType ) + { + const ModuleInfo* pModuleInfo = lcl_getModuleInfo(); + while ( pModuleInfo->pAsciiModuleOrServiceName ) + { + if ( pModuleInfo->eType == _eType ) + return ::rtl::OUString::createFromAscii( pModuleInfo->pAsciiModuleOrServiceName ); + ++pModuleInfo; + } + return ::rtl::OUString(); + } + +//........................................................................ +} // namespace svxform +//........................................................................ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmdpage.cxx b/svx/source/form/fmdpage.cxx new file mode 100644 index 000000000000..1581576f7657 --- /dev/null +++ b/svx/source/form/fmdpage.cxx @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include <svx/fmpage.hxx> +#include "fmobj.hxx" +#include <svx/fmglob.hxx> +#include <svx/fmdpage.hxx> +#include <svx/unoshape.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/typeprovider.hxx> + +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::RuntimeException; +using ::com::sun::star::form::XFormsSupplier2; + +DBG_NAME(SvxFmDrawPage) +SvxFmDrawPage::SvxFmDrawPage( SdrPage* pInPage ) : + SvxDrawPage( pInPage ) +{ + DBG_CTOR(SvxFmDrawPage,NULL); +} + +SvxFmDrawPage::~SvxFmDrawPage() throw () +{ + DBG_DTOR(SvxFmDrawPage,NULL); +} + +::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL SvxFmDrawPage::getImplementationId() throw(::com::sun::star::uno::RuntimeException) +{ + static ::cppu::OImplementationId* pId = 0; + if (! pId) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if (! pId) + { + static ::cppu::OImplementationId aId; + pId = &aId; + } + } + return pId->getImplementationId(); +} + +Any SAL_CALL SvxFmDrawPage::queryAggregation( const ::com::sun::star::uno::Type& _rType ) throw(RuntimeException) +{ + Any aRet = ::cppu::queryInterface ( _rType + , static_cast< XFormsSupplier2* >( this ) + , static_cast< XFormsSupplier* >( this ) + ); + if ( !aRet.hasValue() ) + aRet = SvxDrawPage::queryAggregation( _rType ); + + return aRet; +} + +/*********************************************************************** +* * +***********************************************************************/ +::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL SvxFmDrawPage::getTypes( ) throw(::com::sun::star::uno::RuntimeException) +{ + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > aTypes(SvxDrawPage::getTypes()); + aTypes.realloc(aTypes.getLength() + 1); + ::com::sun::star::uno::Type* pTypes = aTypes.getArray(); + + pTypes[aTypes.getLength()-1] = ::getCppuType((const ::com::sun::star::uno::Reference< ::com::sun::star::form::XFormsSupplier>*)0); + return aTypes; +} + +SdrObject *SvxFmDrawPage::_CreateSdrObject( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > & xDescr ) throw () +{ + ::rtl::OUString aShapeType( xDescr->getShapeType() ); + + if ( aShapeType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "com.sun.star.drawing.ShapeControl" ) ) // compatibility + || aShapeType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "com.sun.star.drawing.ControlShape" ) ) + ) + return new FmFormObj( OBJ_FM_CONTROL ); + else + return SvxDrawPage::_CreateSdrObject( xDescr ); + +} + +::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > SvxFmDrawPage::_CreateShape( SdrObject *pObj ) const throw () +{ + if( FmFormInventor == pObj->GetObjInventor() ) + { + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > xShape = (SvxShape*)new SvxShapeControl( pObj ); + return xShape; + } + else + return SvxDrawPage::_CreateShape( pObj ); +} + +// XFormsSupplier +::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer > SAL_CALL SvxFmDrawPage::getForms(void) throw( ::com::sun::star::uno::RuntimeException ) +{ + ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer > xForms; + + FmFormPage *pFmPage = PTR_CAST( FmFormPage, GetSdrPage() ); + if( pFmPage ) + xForms = pFmPage->GetForms(); + + return xForms; +} + +// XFormsSupplier2 +sal_Bool SAL_CALL SvxFmDrawPage::hasForms(void) throw( ::com::sun::star::uno::RuntimeException ) +{ + sal_Bool bHas = sal_False; + FmFormPage* pFormPage = PTR_CAST( FmFormPage, GetSdrPage() ); + if ( pFormPage ) + bHas = pFormPage->GetForms( false ).is(); + return bHas; +} + +// ::com::sun::star::lang::XServiceInfo +::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL SvxFmDrawPage::getSupportedServiceNames(void) throw( ::com::sun::star::uno::RuntimeException ) +{ + return SvxDrawPage::getSupportedServiceNames(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmexch.cxx b/svx/source/form/fmexch.cxx new file mode 100644 index 000000000000..3f52a854c850 --- /dev/null +++ b/svx/source/form/fmexch.cxx @@ -0,0 +1,443 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include "fmexch.hxx" + +#include <sot/storage.hxx> +#include <svl/itempool.hxx> + +#include <dbexch.hrc> +#include <sot/formats.hxx> +#include <svtools/svtreebx.hxx> +#include <tools/diagnose_ex.h> + +#define _SVSTDARR_ULONGS +#include <svl/svstdarr.hxx> + +//........................................................................ +namespace svxform +{ +//........................................................................ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::datatransfer; + + //==================================================================== + //= OLocalExchange + //==================================================================== + //-------------------------------------------------------------------- + OLocalExchange::OLocalExchange( ) + :m_bDragging( sal_False ) + ,m_bClipboardOwner( sal_False ) + { + } + + //-------------------------------------------------------------------- + void OLocalExchange::copyToClipboard( Window* _pWindow, const GrantAccess& ) + { + if ( m_bClipboardOwner ) + { // simulate a lostOwnership to notify parties interested in + if ( m_aClipboardListener.IsSet() ) + m_aClipboardListener.Call( this ); + } + + m_bClipboardOwner = sal_True; + CopyToClipboard( _pWindow ); + } + + //-------------------------------------------------------------------- + void OLocalExchange::clear() + { + if ( isClipboardOwner() ) + { + try + { + Reference< clipboard::XClipboard > xClipBoard( getOwnClipboard() ); + if ( xClipBoard.is() ) + xClipBoard->setContents( NULL, NULL ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + m_bClipboardOwner = sal_False; + } + } + + //-------------------------------------------------------------------- + void SAL_CALL OLocalExchange::lostOwnership( const Reference< clipboard::XClipboard >& _rxClipboard, const Reference< XTransferable >& _rxTrans ) throw(RuntimeException) + { + TransferableHelper::implCallOwnLostOwnership( _rxClipboard, _rxTrans ); + m_bClipboardOwner = sal_False; + + if ( m_aClipboardListener.IsSet() ) + m_aClipboardListener.Call( this ); + } + + //-------------------------------------------------------------------- + void OLocalExchange::startDrag( Window* _pWindow, sal_Int8 _nDragSourceActions, const GrantAccess& ) + { + m_bDragging = sal_True; + StartDrag( _pWindow, _nDragSourceActions ); + } + + //-------------------------------------------------------------------- + void OLocalExchange::DragFinished( sal_Int8 nDropAction ) + { + TransferableHelper::DragFinished( nDropAction ); + m_bDragging = sal_False; + } + + //-------------------------------------------------------------------- + sal_Bool OLocalExchange::hasFormat( const DataFlavorExVector& _rFormats, sal_uInt32 _nFormatId ) + { + DataFlavorExVector::const_iterator aSearch; + + for ( aSearch = _rFormats.begin(); aSearch != _rFormats.end(); ++aSearch ) + if ( aSearch->mnSotId == _nFormatId ) + break; + + return aSearch != _rFormats.end(); + } + + //-------------------------------------------------------------------- + sal_Bool OLocalExchange::GetData( const ::com::sun::star::datatransfer::DataFlavor& /*_rFlavor*/ ) + { + return sal_False; // do not have any formats by default + } + + //==================================================================== + //= OControlTransferData + //==================================================================== + //-------------------------------------------------------------------- + OControlTransferData::OControlTransferData( ) + :m_pFocusEntry( NULL ) + { + } + + //-------------------------------------------------------------------- + OControlTransferData::OControlTransferData( const Reference< XTransferable >& _rxTransferable ) + :m_pFocusEntry( NULL ) + { + TransferableDataHelper aExchangedData( _rxTransferable ); + + // try the formats we know + if ( OControlExchange::hasControlPathFormat( aExchangedData.GetDataFlavorExVector() ) ) + { // paths to the controls, relative to a root + Sequence< Any > aControlPathData; + if ( aExchangedData.GetAny( OControlExchange::getControlPathFormatId() ) >>= aControlPathData ) + { + DBG_ASSERT( aControlPathData.getLength() >= 2, "OControlTransferData::OControlTransferData: invalid data for the control path format!" ); + if ( aControlPathData.getLength() >= 2 ) + { + aControlPathData[0] >>= m_xFormsRoot; + aControlPathData[1] >>= m_aControlPaths; + } + } + else + { + DBG_ERROR( "OControlTransferData::OControlTransferData: invalid data for the control path format (2)!" ); + } + } + if ( OControlExchange::hasHiddenControlModelsFormat( aExchangedData.GetDataFlavorExVector() ) ) + { // sequence of models of hidden controls + aExchangedData.GetAny( OControlExchange::getHiddenControlModelsFormatId() ) >>= m_aHiddenControlModels; + } + + updateFormats( ); + } + + //-------------------------------------------------------------------- + static sal_Bool lcl_fillDataFlavorEx( SotFormatStringId nId, DataFlavorEx& _rFlavor ) + { + _rFlavor.mnSotId = nId; + return SotExchange::GetFormatDataFlavor( _rFlavor.mnSotId, _rFlavor ); + } + + //-------------------------------------------------------------------- + void OControlTransferData::updateFormats( ) + { + m_aCurrentFormats.clear(); + m_aCurrentFormats.reserve( 3 ); + + DataFlavorEx aFlavor; + + if ( m_aHiddenControlModels.getLength() ) + { + if ( lcl_fillDataFlavorEx( OControlExchange::getHiddenControlModelsFormatId(), aFlavor ) ) + m_aCurrentFormats.push_back( aFlavor ); + } + + if ( m_xFormsRoot.is() && m_aControlPaths.getLength() ) + { + if ( lcl_fillDataFlavorEx( OControlExchange::getControlPathFormatId(), aFlavor ) ) + m_aCurrentFormats.push_back( aFlavor ); + } + + if ( !m_aSelectedEntries.empty() ) + { + if ( lcl_fillDataFlavorEx( OControlExchange::getFieldExchangeFormatId(), aFlavor ) ) + m_aCurrentFormats.push_back( aFlavor ); + } + } + + //-------------------------------------------------------------------- + size_t OControlTransferData::onEntryRemoved( SvLBoxEntry* _pEntry ) + { + m_aSelectedEntries.erase( _pEntry ); + return m_aSelectedEntries.size(); + } + + //-------------------------------------------------------------------- + void OControlTransferData::addSelectedEntry( SvLBoxEntry* _pEntry ) + { + m_aSelectedEntries.insert( _pEntry ); + } + + //-------------------------------------------------------------------- + void OControlTransferData::setFocusEntry( SvLBoxEntry* _pFocusEntry ) + { + m_pFocusEntry = _pFocusEntry; + } + + //------------------------------------------------------------------------ + void OControlTransferData::addHiddenControlsFormat(const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > > seqInterfaces) + { + m_aHiddenControlModels = seqInterfaces; + } + + //------------------------------------------------------------------------ + void OControlTransferData::buildPathFormat(SvTreeListBox* pTreeBox, SvLBoxEntry* pRoot) + { + m_aControlPaths.realloc(0); + + sal_Int32 nEntryCount = m_aSelectedEntries.size(); + if (nEntryCount == 0) + return; + + m_aControlPaths.realloc(nEntryCount); + ::com::sun::star::uno::Sequence<sal_uInt32>* pAllPaths = m_aControlPaths.getArray(); + for ( ListBoxEntrySet::const_iterator loop = m_aSelectedEntries.begin(); + loop != m_aSelectedEntries.end(); + ++loop, ++pAllPaths + ) + { + // erst mal sammeln wir den Pfad in einem Array ein + ::std::vector< sal_uInt32 > aCurrentPath; + SvLBoxEntry* pCurrentEntry = *loop; + + SvLBoxEntry* pLoop = pCurrentEntry; + while (pLoop != pRoot) + { + aCurrentPath.push_back(pLoop->GetChildListPos()); + pLoop = pTreeBox->GetParent(pLoop); + DBG_ASSERT((pLoop != NULL) || (pRoot == 0), "OControlTransferData::buildPathFormat: invalid root or entry !"); + // pLoop == NULL heisst, dass ich am oberen Ende angelangt bin, dann sollte das Ganze abbrechen, was nur bei pRoot == NULL der Fall sein wird + } + + // dann koennen wir ihn in die ::com::sun::star::uno::Sequence uebertragen + Sequence<sal_uInt32>& rCurrentPath = *pAllPaths; + sal_Int32 nDepth = aCurrentPath.size(); + + rCurrentPath.realloc(nDepth); + sal_uInt32* pSeq = rCurrentPath.getArray(); + sal_Int32 j,k; + for (j = nDepth - 1, k = 0; k<nDepth; --j, ++k) + pSeq[j] = aCurrentPath[k]; + } + } + + //------------------------------------------------------------------------ + void OControlTransferData::buildListFromPath(SvTreeListBox* pTreeBox, SvLBoxEntry* pRoot) + { + ListBoxEntrySet aEmpty; + m_aSelectedEntries.swap( aEmpty ); + + sal_Int32 nControls = m_aControlPaths.getLength(); + const ::com::sun::star::uno::Sequence<sal_uInt32>* pPaths = m_aControlPaths.getConstArray(); + for (sal_Int32 i=0; i<nControls; ++i) + { + sal_Int32 nThisPatLength = pPaths[i].getLength(); + const sal_uInt32* pThisPath = pPaths[i].getConstArray(); + SvLBoxEntry* pSearch = pRoot; + for (sal_Int32 j=0; j<nThisPatLength; ++j) + pSearch = pTreeBox->GetEntry(pSearch, pThisPath[j]); + + m_aSelectedEntries.insert( pSearch ); + } + } + + //==================================================================== + //= OControlExchange + //==================================================================== + //-------------------------------------------------------------------- + OControlExchange::OControlExchange( ) + { + } + + //-------------------------------------------------------------------- + sal_Bool OControlExchange::GetData( const DataFlavor& _rFlavor ) + { + const sal_uInt32 nFormatId = SotExchange::GetFormat( _rFlavor ); + + if ( getControlPathFormatId( ) == nFormatId ) + { + // ugly. We have to pack all the info into one object + Sequence< Any > aCompleteInfo( 2 ); + OSL_ENSURE( m_xFormsRoot.is(), "OLocalExchange::GetData: invalid forms root for this format!" ); + aCompleteInfo.getArray()[ 0 ] <<= m_xFormsRoot; + aCompleteInfo.getArray()[ 1 ] <<= m_aControlPaths; + + SetAny( makeAny( aCompleteInfo ), _rFlavor ); + } + else if ( getHiddenControlModelsFormatId() == nFormatId ) + { + // just need to transfer the models + SetAny( makeAny( m_aHiddenControlModels ), _rFlavor ); + } + else + return OLocalExchange::GetData( _rFlavor ); + + return sal_True; + } + + //-------------------------------------------------------------------- + void OControlExchange::AddSupportedFormats() + { + if (m_pFocusEntry && !m_aSelectedEntries.empty()) + AddFormat(getFieldExchangeFormatId()); + + if (m_aControlPaths.getLength()) + AddFormat(getControlPathFormatId()); + + if (m_aHiddenControlModels.getLength()) + AddFormat(getHiddenControlModelsFormatId()); + } + + //-------------------------------------------------------------------- + sal_uInt32 OControlExchange::getControlPathFormatId() + { + static sal_uInt32 s_nFormat = (sal_uInt32)-1; + if ((sal_uInt32)-1 == s_nFormat) + { + s_nFormat = SotExchange::RegisterFormatName(String::CreateFromAscii("application/x-openoffice;windows_formatname=\"svxform.ControlPathExchange\"")); + DBG_ASSERT((sal_uInt32)-1 != s_nFormat, "OControlExchange::getControlPathFormatId: bad exchange id!"); + } + return s_nFormat; + } + + //-------------------------------------------------------------------- + sal_uInt32 OControlExchange::getHiddenControlModelsFormatId() + { + static sal_uInt32 s_nFormat = (sal_uInt32)-1; + if ((sal_uInt32)-1 == s_nFormat) + { + s_nFormat = SotExchange::RegisterFormatName(String::CreateFromAscii("application/x-openoffice;windows_formatname=\"svxform.HiddenControlModelsExchange\"")); + DBG_ASSERT((sal_uInt32)-1 != s_nFormat, "OControlExchange::getHiddenControlModelsFormatId: bad exchange id!"); + } + return s_nFormat; + } + + //-------------------------------------------------------------------- + sal_uInt32 OControlExchange::getFieldExchangeFormatId() + { + static sal_uInt32 s_nFormat = (sal_uInt32)-1; + if ((sal_uInt32)-1 == s_nFormat) + { + s_nFormat = SotExchange::RegisterFormatName(String::CreateFromAscii("application/x-openoffice;windows_formatname=\"svxform.FieldNameExchange\"")); + DBG_ASSERT((sal_uInt32)-1 != s_nFormat, "OControlExchange::getFieldExchangeFormatId: bad exchange id!"); + } + return s_nFormat; + } + + //==================================================================== + //= OControlExchangeHelper + //==================================================================== + OLocalExchange* OControlExchangeHelper::createExchange() const + { + return new OControlExchange; + } + + //==================================================================== + //= OLocalExchangeHelper + //==================================================================== + //-------------------------------------------------------------------- + OLocalExchangeHelper::OLocalExchangeHelper(Window* _pDragSource) + :m_pDragSource(_pDragSource) + ,m_pTransferable(NULL) + { + } + + //-------------------------------------------------------------------- + OLocalExchangeHelper::~OLocalExchangeHelper() + { + implReset(); + } + + //-------------------------------------------------------------------- + void OLocalExchangeHelper::startDrag( sal_Int8 nDragSourceActions ) + { + DBG_ASSERT(m_pTransferable, "OLocalExchangeHelper::startDrag: not prepared!"); + m_pTransferable->startDrag( m_pDragSource, nDragSourceActions, OLocalExchange::GrantAccess() ); + } + + //-------------------------------------------------------------------- + void OLocalExchangeHelper::copyToClipboard( ) const + { + DBG_ASSERT( m_pTransferable, "OLocalExchangeHelper::copyToClipboard: not prepared!" ); + m_pTransferable->copyToClipboard( m_pDragSource, OLocalExchange::GrantAccess() ); + } + + //-------------------------------------------------------------------- + void OLocalExchangeHelper::implReset() + { + if (m_pTransferable) + { + m_pTransferable->setClipboardListener( Link() ); + m_pTransferable->release(); + m_pTransferable = NULL; + } + } + + //-------------------------------------------------------------------- + void OLocalExchangeHelper::prepareDrag( ) + { + DBG_ASSERT(!m_pTransferable || !m_pTransferable->isDragging(), "OLocalExchangeHelper::prepareDrag: recursive DnD?"); + + implReset(); + m_pTransferable = createExchange(); + m_pTransferable->acquire(); + } + +//........................................................................ +} +//........................................................................ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmexpl.cxx b/svx/source/form/fmexpl.cxx new file mode 100644 index 000000000000..59c39f21a8b8 --- /dev/null +++ b/svx/source/form/fmexpl.cxx @@ -0,0 +1,736 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include "fmresids.hrc" +#include "fmexpl.hrc" +#include "fmexpl.hxx" + +#include "fmhelp.hrc" +#include <svx/fmglob.hxx> +#include "fmservs.hxx" +#include <svx/fmmodel.hxx> +#include "fmexch.hxx" +#include "fmundo.hxx" +#include "fmpgeimp.hxx" + +#include <svx/svxids.hrc> + +#include "fmprop.hrc" +#include <svx/dialmgr.hxx> +#include "svditer.hxx" +#include <svx/svdouno.hxx> +#include <fmundo.hxx> +#include <svx/svdobj.hxx> +#include <vcl/msgbox.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/viewsh.hxx> +#include <sfx2/viewfrm.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/form/FormComponentType.hpp> +#include <com/sun/star/awt/XTabControllerModel.hpp> +#include <vcl/menu.hxx> +#include <sfx2/objitem.hxx> +#include <sfx2/request.hxx> +#include <tools/shl.hxx> + +#include <vcl/wrkwin.hxx> +#include <vcl/sound.hxx> +#include <svx/fmshell.hxx> +#include "fmshimp.hxx" +#include <svx/fmpage.hxx> +#include <com/sun/star/io/XPersistObject.hpp> +#include <com/sun/star/script/XEventAttacherManager.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <comphelper/property.hxx> +#include <comphelper/processfactory.hxx> +#include <osl/diagnose.h> +#include <rtl/logfile.hxx> + +using namespace ::svxform; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; + +//======================================================================== + +SV_IMPL_PTRARR_SORT( FmEntryDataArray, FmEntryDataPtr ) +SV_IMPL_PTRARR_SORT( SvLBoxEntrySortedArray, SvLBoxEntryPtr ) + +//======================================================================== +// class FmNavInsertedHint +//======================================================================== +TYPEINIT1( FmNavInsertedHint, SfxHint ); +DBG_NAME(FmNavInsertedHint); +//------------------------------------------------------------------------ +FmNavInsertedHint::FmNavInsertedHint( FmEntryData* pInsertedEntryData, sal_uInt32 nRelPos ) + :pEntryData( pInsertedEntryData ) + ,nPos( nRelPos ) + +{ + DBG_CTOR(FmNavInsertedHint,NULL); +} + +//------------------------------------------------------------------------ +FmNavInsertedHint::~FmNavInsertedHint() +{ + DBG_DTOR(FmNavInsertedHint,NULL); +} + + +//======================================================================== +// class FmNavInsertedHint +//======================================================================== +TYPEINIT1( FmNavModelReplacedHint, SfxHint ); +DBG_NAME(FmNavModelReplacedHint); +//------------------------------------------------------------------------ +FmNavModelReplacedHint::FmNavModelReplacedHint( FmEntryData* pAffectedEntryData ) + :pEntryData( pAffectedEntryData ) +{ + DBG_CTOR(FmNavModelReplacedHint,NULL); +} + +//------------------------------------------------------------------------ +FmNavModelReplacedHint::~FmNavModelReplacedHint() +{ + DBG_DTOR(FmNavModelReplacedHint,NULL); +} + +//======================================================================== +// class FmNavRemovedHint +//======================================================================== +TYPEINIT1( FmNavRemovedHint, SfxHint ); +DBG_NAME(FmNavRemovedHint); +//------------------------------------------------------------------------ +FmNavRemovedHint::FmNavRemovedHint( FmEntryData* pRemovedEntryData ) + :pEntryData( pRemovedEntryData ) +{ + DBG_CTOR(FmNavRemovedHint,NULL); +} + +//------------------------------------------------------------------------ +FmNavRemovedHint::~FmNavRemovedHint() +{ + DBG_DTOR(FmNavRemovedHint,NULL); +} + + +//======================================================================== +// class FmNavNameChangedHint +//======================================================================== +TYPEINIT1( FmNavNameChangedHint, SfxHint ); +DBG_NAME(FmNavNameChangedHint); +//------------------------------------------------------------------------ +FmNavNameChangedHint::FmNavNameChangedHint( FmEntryData* pData, const ::rtl::OUString& rNewName ) + :pEntryData( pData ) + ,aNewName( rNewName ) +{ + DBG_CTOR(FmNavNameChangedHint,NULL); +} + +//------------------------------------------------------------------------ +FmNavNameChangedHint::~FmNavNameChangedHint() +{ + DBG_DTOR(FmNavNameChangedHint,NULL); +} + +//======================================================================== +// class FmNavClearedHint +//======================================================================== +TYPEINIT1( FmNavClearedHint, SfxHint ); +DBG_NAME(FmNavClearedHint); +//------------------------------------------------------------------------ +FmNavClearedHint::FmNavClearedHint() +{ + DBG_CTOR(FmNavClearedHint,NULL); +} + +//------------------------------------------------------------------------ +FmNavClearedHint::~FmNavClearedHint() +{ + DBG_DTOR(FmNavClearedHint,NULL); +} + +//======================================================================== +// class FmNavRequestSelectHint +//======================================================================== +TYPEINIT1(FmNavRequestSelectHint, SfxHint); + +//======================================================================== +// class FmNavViewMarksChanged +//======================================================================== +TYPEINIT1(FmNavViewMarksChanged, SfxHint); + +//======================================================================== +// class FmEntryDataList +//======================================================================== +DBG_NAME(FmEntryDataList); +//------------------------------------------------------------------------ +FmEntryDataList::FmEntryDataList() +{ + DBG_CTOR(FmEntryDataList,NULL); +} + +//------------------------------------------------------------------------ +FmEntryDataList::~FmEntryDataList() +{ + DBG_DTOR(FmEntryDataList,NULL); +} + +//------------------------------------------------------------------------ +FmEntryData* FmEntryDataList::remove( FmEntryData* pItem ) +{ + for ( FmEntryDataBaseList::iterator it = maEntryDataList.begin(); + it < maEntryDataList.end(); + ++it + ) + { + if ( *it == pItem ) + { + maEntryDataList.erase( it ); + break; + } + } + return pItem; +} + +//------------------------------------------------------------------------ +void FmEntryDataList::insert( FmEntryData* pItem, size_t Index ) +{ + if ( Index < maEntryDataList.size() ) + { + FmEntryDataBaseList::iterator it = maEntryDataList.begin(); + ::std::advance( it, Index ); + maEntryDataList.insert( it, pItem ); + } + else + maEntryDataList.push_back( pItem ); +} + +//------------------------------------------------------------------------ +void FmEntryDataList::clear() +{ + for ( size_t i = 0, n = maEntryDataList.size(); i < n; ++i ) + delete maEntryDataList[ i ]; + maEntryDataList.clear(); +} + +//======================================================================== +// class FmEntryData +//======================================================================== +TYPEINIT0( FmEntryData ); +DBG_NAME(FmEntryData); +//------------------------------------------------------------------------ +FmEntryData::FmEntryData( FmEntryData* pParentData, const Reference< XInterface >& _rxIFace ) + :pParent( pParentData ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmEntryData::FmEntryData" ); + DBG_CTOR(FmEntryData,NULL); + pChildList = new FmEntryDataList(); + + newObject( _rxIFace ); +} + +//------------------------------------------------------------------------ +FmEntryData::~FmEntryData() +{ + Clear(); + delete pChildList; + DBG_DTOR(FmEntryData,NULL); +} + +//------------------------------------------------------------------------ +void FmEntryData::newObject( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxIFace ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmEntryData::newObject" ); + // do not just copy, normalize it + m_xNormalizedIFace = Reference< XInterface >( _rxIFace, UNO_QUERY ); + m_xProperties = m_xProperties.query( m_xNormalizedIFace ); + m_xChild = m_xChild.query( m_xNormalizedIFace ); +} + +//------------------------------------------------------------------------ +FmEntryData::FmEntryData( const FmEntryData& rEntryData ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmEntryData::FmEntryData" ); + pChildList = new FmEntryDataList(); + aText = rEntryData.GetText(); + m_aNormalImage = rEntryData.GetNormalImage(); + pParent = rEntryData.GetParent(); + + FmEntryData* pChildData; + size_t nEntryCount = rEntryData.GetChildList()->size(); + for( size_t i = 0; i < nEntryCount; i++ ) + { + pChildData = rEntryData.GetChildList()->at( i ); + FmEntryData* pNewChildData = pChildData->Clone(); + pChildList->insert( pNewChildData, size_t(-1) ); + } + + m_xNormalizedIFace = rEntryData.m_xNormalizedIFace; + m_xProperties = rEntryData.m_xProperties; + m_xChild = rEntryData.m_xChild; +} + +//------------------------------------------------------------------------ +void FmEntryData::Clear() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmEntryData::Clear" ); + GetChildList()->clear(); +} + +//------------------------------------------------------------------------ +sal_Bool FmEntryData::IsEqualWithoutChilds( FmEntryData* pEntryData ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmEntryData::IsEqualWithoutChilds" ); + if(this == pEntryData) + return sal_True; + + if( !pEntryData ) + return sal_False; + + if( !aText.equals(pEntryData->GetText())) + return sal_False; + + if( !pEntryData->GetParent() && pParent ) + return sal_False; + + if( pEntryData->GetParent() && !pParent ) + return sal_False; + + if( !pEntryData->GetParent() && !pParent ) + return sal_True; + + if( !pParent->IsEqualWithoutChilds(pEntryData->GetParent()) ) + return sal_False; + + return sal_True; +} + + +//======================================================================== +// class FmFormData +//======================================================================== +TYPEINIT1( FmFormData, FmEntryData ); +DBG_NAME(FmFormData); +//------------------------------------------------------------------------ +FmFormData::FmFormData( + const Reference< XForm >& _rxForm, + const ImageList& _rNormalImages, + FmFormData* _pParent +) +: FmEntryData( _pParent, _rxForm ), + m_xForm( _rxForm ) +{ + DBG_CTOR(FmEntryData,NULL); + ////////////////////////////////////////////////////////////////////// + // Images setzen + + m_aNormalImage = _rNormalImages.GetImage( RID_SVXIMG_FORM ); + + ////////////////////////////////////////////////////////////////////// + // Titel setzen + if (m_xForm.is()) + { + Reference< XPropertySet > xSet(m_xForm, UNO_QUERY); + if (xSet.is()) + { + ::rtl::OUString aEntryName(::comphelper::getString(xSet->getPropertyValue( FM_PROP_NAME ))); + SetText(aEntryName); + } + } + else + SetText( ::rtl::OUString() ); +} + +//------------------------------------------------------------------------ +FmFormData::~FmFormData() +{ + DBG_DTOR(FmEntryData,NULL); +} + +//------------------------------------------------------------------------ +FmFormData::FmFormData( const FmFormData& rFormData ) + :FmEntryData( rFormData ) +{ + DBG_CTOR(FmEntryData,NULL); + m_xForm = rFormData.GetFormIface(); +} + +//------------------------------------------------------------------------ +FmEntryData* FmFormData::Clone() +{ + return new FmFormData( *this ); +} + +//------------------------------------------------------------------------ +sal_Bool FmFormData::IsEqualWithoutChilds( FmEntryData* pEntryData ) +{ + if(this == pEntryData) + return sal_True; + if( !pEntryData->ISA(FmFormData) ) + return sal_False; + FmFormData* pFormData = (FmFormData*)pEntryData; + if( (XForm*)m_xForm.get() != (XForm*)pFormData->GetFormIface().get() ) + return sal_False; + + return FmEntryData::IsEqualWithoutChilds( pFormData ); +} + + +//======================================================================== +// class FmControlData +//======================================================================== +TYPEINIT1( FmControlData, FmEntryData ); +DBG_NAME(FmControlData); +//------------------------------------------------------------------------ +FmControlData::FmControlData( + const Reference< XFormComponent >& _rxComponent, + const ImageList& _rNormalImages, + FmFormData* _pParent +) +: FmEntryData( _pParent, _rxComponent ), + m_xFormComponent( _rxComponent ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmControlData::FmControlData" ); + DBG_CTOR(FmControlData,NULL); + ////////////////////////////////////////////////////////////////////// + // Images setzen + m_aNormalImage = GetImage( _rNormalImages ); + + ////////////////////////////////////////////////////////////////////// + // Titel setzen + Reference< XPropertySet > xSet(m_xFormComponent, UNO_QUERY); + if( xSet.is() ) + { +#ifdef DBG_UTIL + ::rtl::OUString aEntryName = ::comphelper::getString(xSet->getPropertyValue( FM_PROP_NAME )); +#endif + SetText( ::comphelper::getString(xSet->getPropertyValue( FM_PROP_NAME ))); + } +} + +//------------------------------------------------------------------------ +FmControlData::~FmControlData() +{ + DBG_DTOR(FmControlData,NULL); +} + +//------------------------------------------------------------------------ +FmControlData::FmControlData( const FmControlData& rControlData ) + :FmEntryData( rControlData ) +{ + DBG_CTOR(FmControlData,NULL); + m_xFormComponent = rControlData.GetFormComponent(); +} + +//------------------------------------------------------------------------ +FmEntryData* FmControlData::Clone() +{ + return new FmControlData( *this ); +} + +//------------------------------------------------------------------------ +Image FmControlData::GetImage(const ImageList& ilNavigatorImages) const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmControlData::FmControlData" ); + ////////////////////////////////////////////////////////////////////// + // Default-Image + Image aImage = ilNavigatorImages.GetImage( RID_SVXIMG_CONTROL ); + + Reference< XServiceInfo > xInfo( m_xFormComponent, UNO_QUERY ); + if (!m_xFormComponent.is()) + return aImage; + + ////////////////////////////////////////////////////////////////////// + // Spezielle Control-Images + sal_Int16 nObjectType = getControlTypeByObject(xInfo); + switch (nObjectType) + { + case OBJ_FM_BUTTON: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_BUTTON ); + break; + + case OBJ_FM_FIXEDTEXT: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_FIXEDTEXT ); + break; + + case OBJ_FM_EDIT: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_EDIT ); + break; + + case OBJ_FM_RADIOBUTTON: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_RADIOBUTTON ); + break; + + case OBJ_FM_CHECKBOX: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_CHECKBOX ); + break; + + case OBJ_FM_LISTBOX: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_LISTBOX ); + break; + + case OBJ_FM_COMBOBOX: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_COMBOBOX ); + break; + + case OBJ_FM_NAVIGATIONBAR: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_NAVIGATIONBAR ); + break; + + case OBJ_FM_GROUPBOX: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_GROUPBOX ); + break; + + case OBJ_FM_IMAGEBUTTON: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_IMAGEBUTTON ); + break; + + case OBJ_FM_FILECONTROL: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_FILECONTROL ); + break; + + case OBJ_FM_HIDDEN: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_HIDDEN ); + break; + + case OBJ_FM_DATEFIELD: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_DATEFIELD ); + break; + + case OBJ_FM_TIMEFIELD: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_TIMEFIELD ); + break; + + case OBJ_FM_NUMERICFIELD: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_NUMERICFIELD ); + break; + + case OBJ_FM_CURRENCYFIELD: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_CURRENCYFIELD ); + break; + + case OBJ_FM_PATTERNFIELD: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_PATTERNFIELD ); + break; + + case OBJ_FM_IMAGECONTROL: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_IMAGECONTROL ); + break; + + case OBJ_FM_FORMATTEDFIELD: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_FORMATTEDFIELD ); + break; + + case OBJ_FM_GRID: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_GRID ); + break; + + case OBJ_FM_SCROLLBAR: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_SCROLLBAR ); + break; + + case OBJ_FM_SPINBUTTON: + aImage = ilNavigatorImages.GetImage( RID_SVXIMG_SPINBUTTON); + break; + } + + return aImage; +} + +//------------------------------------------------------------------------ +sal_Bool FmControlData::IsEqualWithoutChilds( FmEntryData* pEntryData ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmControlData::IsEqualWithoutChilds" ); + if(this == pEntryData) + return sal_True; + + if( !pEntryData->ISA(FmControlData) ) + return sal_False; + FmControlData* pControlData = (FmControlData*)pEntryData; + + if( (XFormComponent*)m_xFormComponent.get() != (XFormComponent*)pControlData->GetFormComponent().get() ) + return sal_False; + + return FmEntryData::IsEqualWithoutChilds( pControlData ); +} + +//------------------------------------------------------------------------ +void FmControlData::ModelReplaced( + const Reference< XFormComponent >& _rxNew, + const ImageList& _rNormalImages +) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmControlData::ModelReplaced" ); + m_xFormComponent = _rxNew; + newObject( m_xFormComponent ); + + // Images neu setzen + m_aNormalImage = GetImage( _rNormalImages ); +} + +//............................................................................ +namespace svxform +{ +//............................................................................ + + //======================================================================== + // class NavigatorFrame + //======================================================================== + DBG_NAME(NavigatorFrame) + //------------------------------------------------------------------------ + NavigatorFrame::NavigatorFrame( SfxBindings* _pBindings, SfxChildWindow* _pMgr, + Window* _pParent ) + :SfxDockingWindow( _pBindings, _pMgr, _pParent, WinBits(WB_STDMODELESS|WB_SIZEABLE|WB_ROLLABLE|WB_3DLOOK|WB_DOCKABLE) ) + ,SfxControllerItem( SID_FM_FMEXPLORER_CONTROL, *_pBindings ) + { + DBG_CTOR(NavigatorFrame,NULL); + SetHelpId( HID_FORM_NAVIGATOR_WIN ); + + m_pNavigatorTree = new NavigatorTree(comphelper::getProcessServiceFactory(), this ); + m_pNavigatorTree->Show(); + SetText( SVX_RES(RID_STR_FMEXPLORER) ); + SfxDockingWindow::SetFloatingSize( Size(200,200) ); + } + + //------------------------------------------------------------------------ + NavigatorFrame::~NavigatorFrame() + { + delete m_pNavigatorTree; + DBG_DTOR(NavigatorFrame,NULL); + } + + //----------------------------------------------------------------------- + void NavigatorFrame::UpdateContent( FmFormShell* pFormShell ) + { + m_pNavigatorTree->UpdateContent( pFormShell ); + } + + //----------------------------------------------------------------------- + void NavigatorFrame::StateChanged( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState ) + { + if( !pState || SID_FM_FMEXPLORER_CONTROL != nSID ) + return; + + if( eState >= SFX_ITEM_AVAILABLE ) + { + FmFormShell* pShell = PTR_CAST( FmFormShell,((SfxObjectItem*)pState)->GetShell() ); + UpdateContent( pShell ); + } + else + UpdateContent( NULL ); + } + + //----------------------------------------------------------------------- + void NavigatorFrame::GetFocus() + { + if ( m_pNavigatorTree ) + m_pNavigatorTree->GrabFocus(); + else + SfxDockingWindow::GetFocus(); + } + + //----------------------------------------------------------------------- + sal_Bool NavigatorFrame::Close() + { + UpdateContent( NULL ); + return SfxDockingWindow::Close(); + } + + //----------------------------------------------------------------------- + void NavigatorFrame::FillInfo( SfxChildWinInfo& rInfo ) const + { + SfxDockingWindow::FillInfo( rInfo ); + rInfo.bVisible = sal_False; + } + + //----------------------------------------------------------------------- + Size NavigatorFrame::CalcDockingSize( SfxChildAlignment eAlign ) + { + if ( ( eAlign == SFX_ALIGN_TOP ) || ( eAlign == SFX_ALIGN_BOTTOM ) ) + return Size(); + + return SfxDockingWindow::CalcDockingSize( eAlign ); + } + + //----------------------------------------------------------------------- + SfxChildAlignment NavigatorFrame::CheckAlignment( SfxChildAlignment _eActAlign, SfxChildAlignment _eAlign ) + { + if ( ( _eAlign == SFX_ALIGN_LEFT ) || ( _eAlign == SFX_ALIGN_RIGHT ) || ( _eAlign == SFX_ALIGN_NOALIGNMENT ) ) + return _eAlign; + return _eActAlign; + } + + //------------------------------------------------------------------------ + void NavigatorFrame::Resize() + { + SfxDockingWindow::Resize(); + + Size aLogOutputSize = PixelToLogic( GetOutputSizePixel(), MAP_APPFONT ); + Size aLogExplSize = aLogOutputSize; + aLogExplSize.Width() -= 6; + aLogExplSize.Height() -= 6; + + Point aExplPos = LogicToPixel( Point(3,3), MAP_APPFONT ); + Size aExplSize = LogicToPixel( aLogExplSize, MAP_APPFONT ); + + m_pNavigatorTree->SetPosSizePixel( aExplPos, aExplSize ); + } + + + //======================================================================== + // class NavigatorFrameManager + //======================================================================== + + //----------------------------------------------------------------------- + SFX_IMPL_DOCKINGWINDOW( NavigatorFrameManager, SID_FM_SHOW_FMEXPLORER ) + + //----------------------------------------------------------------------- + NavigatorFrameManager::NavigatorFrameManager( Window* _pParent, sal_uInt16 _nId, + SfxBindings* _pBindings, SfxChildWinInfo* _pInfo ) + :SfxChildWindow( _pParent, _nId ) + { + pWindow = new NavigatorFrame( _pBindings, this, _pParent ); + eChildAlignment = SFX_ALIGN_NOALIGNMENT; + ((SfxDockingWindow*)pWindow)->Initialize( _pInfo ); + } + +//............................................................................ +} // namespace svxform +//............................................................................ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmexpl.src b/svx/source/form/fmexpl.src new file mode 100644 index 000000000000..fb7ea13d9984 --- /dev/null +++ b/svx/source/form/fmexpl.src @@ -0,0 +1,371 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <svx/svxids.hrc> +#include "fmresids.hrc" +#include "fmexpl.hrc" +#include "globlmn.hrc" +Menu RID_FMEXPLORER_POPUPMENU +{ + ItemList = + { + MenuItem + { + Identifier = SID_FM_NEW ; + HelpID = SID_FM_NEW ; + Text [ en-US ] = "~New" ; + SubMenu = Menu + { + ItemList = + { + MenuItem + { + Identifier = SID_FM_NEW_FORM ; + HelpID = SID_FM_NEW_FORM ; + Text [ en-US ] = "Form" ; + }; + MenuItem + { + Identifier = SID_FM_NEW_HIDDEN ; + HelpID = SID_FM_NEW_HIDDEN ; + Text [ en-US ] = "Hidden Control" ; + }; + }; + }; + }; + MenuItem + { + Identifier = SID_FM_CHANGECONTROLTYPE ; + HelpID = SID_FM_CHANGECONTROLTYPE ; + Text [ en-US ] = "Replace with"; + }; + MenuItem { ITEM_EDIT_CUT }; + MenuItem { ITEM_EDIT_COPY }; + MenuItem { ITEM_EDIT_PASTE }; + MenuItem + { + Identifier = SID_FM_DELETE ; + HelpID = SID_FM_DELETE ; + Text [ en-US ] = "~Delete" ; + }; + MenuItem + { + Identifier = SID_FM_TAB_DIALOG ; + HelpID = SID_FM_TAB_DIALOG ; + Text [ en-US ] = "Tab Order..." ; + }; + MenuItem + { + Identifier = SID_FM_RENAME_OBJECT ; + HelpID = SID_FM_RENAME_OBJECT ; + Text [ en-US ] = "~Rename" ; + }; + MenuItem + { + Identifier = SID_FM_SHOW_PROPERTY_BROWSER ; + HelpID = SID_FM_SHOW_PROPERTY_BROWSER ; + Text [ en-US ] = "Propert~ies" ; + }; + MenuItem + { + Identifier = SID_FM_OPEN_READONLY ; + HelpID = SID_FM_OPEN_READONLY ; + Text [ en-US ] = "Open in Design Mode" ; + }; + MenuItem + { + Identifier = SID_FM_AUTOCONTROLFOCUS ; + HelpID = SID_FM_AUTOCONTROLFOCUS ; + Text [ en-US ] = "Automatic Control Focus"; + }; + }; +}; + +Menu RID_FMSHELL_CONVERSIONMENU +{ + ItemList = + { + MenuItem + { + Identifier = SID_FM_CONVERTTO_EDIT ; + HelpID = SID_FM_CONVERTTO_EDIT ; + Command = ".uno:ConvertToEdit" ; + Text [ en-US ] = "~Text Box"; + }; + MenuItem + { + Identifier = SID_FM_CONVERTTO_BUTTON ; + HelpID = SID_FM_CONVERTTO_BUTTON ; + Command = ".uno:ConvertToButton" ; + Text [ en-US ] = "~Button"; + }; + MenuItem + { + Identifier = SID_FM_CONVERTTO_FIXEDTEXT ; + HelpID = SID_FM_CONVERTTO_FIXEDTEXT ; + Command = ".uno:ConvertToFixed" ; + Text [ en-US ] = "La~bel field"; + }; + MenuItem + { + Identifier = SID_FM_CONVERTTO_GROUPBOX ; + HelpID = SID_FM_CONVERTTO_GROUPBOX ; + Command = ".uno:ConvertToGroup" ; + Text [ en-US ] = "G~roup Box"; + }; + MenuItem + { + Identifier = SID_FM_CONVERTTO_LISTBOX ; + HelpID = SID_FM_CONVERTTO_LISTBOX ; + Command = ".uno:ConvertToList" ; + Text [ en-US ] = "L~ist Box"; + }; + MenuItem + { + Identifier = SID_FM_CONVERTTO_CHECKBOX ; + HelpID = SID_FM_CONVERTTO_CHECKBOX ; + Command = ".uno:ConvertToCheckBox" ; + Text [ en-US ] = "~Check Box"; + }; + MenuItem + { + Identifier = SID_FM_CONVERTTO_RADIOBUTTON ; + HelpID = SID_FM_CONVERTTO_RADIOBUTTON ; + Command = ".uno:ConvertToRadio" ; + Text [ en-US ] = "~Radio Button"; + }; + MenuItem + { + Identifier = SID_FM_CONVERTTO_COMBOBOX ; + HelpID = SID_FM_CONVERTTO_COMBOBOX ; + Command = ".uno:ConvertToCombo" ; + Text [ en-US ] = "Combo Bo~x"; + }; + MenuItem + { + Identifier = SID_FM_CONVERTTO_IMAGEBUTTON ; + HelpID = SID_FM_CONVERTTO_IMAGEBUTTON ; + Command = ".uno:ConvertToImageBtn" ; + Text [ en-US ] = "I~mage Button"; + }; + MenuItem + { + Identifier = SID_FM_CONVERTTO_FILECONTROL ; + HelpID = SID_FM_CONVERTTO_FILECONTROL ; + Command = ".uno:ConvertToFileControl" ; + Text [ en-US ] = "~File Selection"; + }; + MenuItem + { + Identifier = SID_FM_CONVERTTO_DATE ; + HelpID = SID_FM_CONVERTTO_DATE ; + Command = ".uno:ConvertToDate" ; + Text [ en-US ] = "~Date Field"; + }; + MenuItem + { + Identifier = SID_FM_CONVERTTO_TIME ; + HelpID = SID_FM_CONVERTTO_TIME ; + Command = ".uno:ConvertToTime" ; + Text [ en-US ] = "Tim~e Field"; + }; + MenuItem + { + Identifier = SID_FM_CONVERTTO_NUMERIC ; + HelpID = SID_FM_CONVERTTO_NUMERIC ; + Command = ".uno:ConvertToNumeric" ; + Text [ en-US ] = "~Numerical Field"; + }; + MenuItem + { + Identifier = SID_FM_CONVERTTO_CURRENCY ; + HelpID = SID_FM_CONVERTTO_CURRENCY ; + Command = ".uno:ConvertToCurrency" ; + Text [ en-US ] = "C~urrency Field"; + }; + MenuItem + { + Identifier = SID_FM_CONVERTTO_PATTERN ; + HelpID = SID_FM_CONVERTTO_PATTERN ; + Command = ".uno:ConvertToPattern" ; + Text [ en-US ] = "~Pattern Field"; + }; + MenuItem + { + Identifier = SID_FM_CONVERTTO_IMAGECONTROL ; + HelpID = SID_FM_CONVERTTO_IMAGECONTROL ; + Command = ".uno:ConvertToImageControl" ; + Text [ en-US ] = "Ima~ge Control"; + }; + MenuItem + { + Identifier = SID_FM_CONVERTTO_FORMATTED ; + HelpID = SID_FM_CONVERTTO_FORMATTED ; + Command = ".uno:ConvertToFormatted" ; + Text [ en-US ] = "Fo~rmatted Field"; + }; + MenuItem + { + Identifier = SID_FM_CONVERTTO_SCROLLBAR ; + HelpID = SID_FM_CONVERTTO_SCROLLBAR ; + Command = ".uno:ConvertToScrollBar" ; + Text [ en-US ] = "Scroll bar"; + }; + MenuItem + { + Identifier = SID_FM_CONVERTTO_SPINBUTTON; + HelpID = SID_FM_CONVERTTO_SPINBUTTON; + Command = ".uno:ConvertToSpinButton" ; + Text [ en-US ] = "Spin Button"; + }; + MenuItem + { + Identifier = SID_FM_CONVERTTO_NAVIGATIONBAR; + HelpID = SID_FM_CONVERTTO_NAVIGATIONBAR; + Command = ".uno:ConvertToNavigationBar" ; + Text [ en-US ] = "Navigation Bar" ; + }; + }; +}; + +#define NAVIGATOR_IMAGEIDS \ + IdList = \ + { \ + RID_SVXIMG_BUTTON ; \ + RID_SVXIMG_RADIOBUTTON ; \ + RID_SVXIMG_CHECKBOX ; \ + RID_SVXIMG_FIXEDTEXT ; \ + RID_SVXIMG_GROUPBOX ; \ + RID_SVXIMG_EDIT ; \ + RID_SVXIMG_LISTBOX ; \ + RID_SVXIMG_COMBOBOX ; \ + RID_SVXIMG_NAVIGATIONBAR ; \ + RID_SVXIMG_CONTROL ; \ + RID_SVXIMG_FORM ; \ + RID_SVXIMG_FORMS ; \ + RID_SVXIMG_COLLAPSEDNODE ; \ + RID_SVXIMG_EXPANDEDNODE ; \ + RID_SVXIMG_IMAGEBUTTON ; \ + RID_SVXIMG_FILECONTROL ; \ + RID_SVXIMG_DATEFIELD ; \ + RID_SVXIMG_TIMEFIELD ; \ + RID_SVXIMG_NUMERICFIELD ; \ + RID_SVXIMG_CURRENCYFIELD ; \ + RID_SVXIMG_PATTERNFIELD ; \ + RID_SVXIMG_HIDDEN ; \ + RID_SVXIMG_IMAGECONTROL ; \ + RID_SVXIMG_GRID ; \ + RID_SVXIMG_FILTER ; \ + RID_SVXIMG_FORMATTEDFIELD ; \ + RID_SVXIMG_DATE_N_TIME_FIELDS ; \ + RID_SVXIMG_FIELD ; \ + RID_SVXIMG_SCROLLBAR; \ + RID_SVXIMG_SPINBUTTON; \ + }; \ + IdCount = 30 + +ImageList RID_SVXIMGLIST_FMEXPL +{ + Prefix = "sx"; + MaskColor = Color { Red = 0xff00 ; Green = 0x0000 ; Blue = 0xff00 ; }; + NAVIGATOR_IMAGEIDS; +}; + +ModalDialog RID_SVXDLG_SETFORM +{ + OutputSize = TRUE ; + SVLook = TRUE ; + Size = MAP_APPFONT ( 200 , 200 ) ; + Moveable = TRUE ; + Closeable = TRUE ; + GroupBox GB_PATH + { + Pos = MAP_APPFONT ( 6 , 149 ) ; + Size = MAP_APPFONT ( 188 , 25 ) ; + Text [ en-US ] = "Path" ; + }; + FixedText FT_PATH + { + Pos = MAP_APPFONT ( 12 , 155 ) ; + Size = MAP_APPFONT ( 156 , 15 ) ; + }; + OKButton PB_OK + { + Pos = MAP_APPFONT ( 6 , 180 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + }; + CancelButton PB_CANCEL + { + Pos = MAP_APPFONT ( 59 , 180 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + }; + HelpButton PB_HELP + { + Pos = MAP_APPFONT ( 123 , 180 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + }; + Text [ en-US ] = "Select form" ; +}; +DockingWindow RID_SVX_FMEXPLORER +{ + OutputSize = TRUE ; + SVLook = TRUE ; + Size = MAP_APPFONT ( 200 , 200 ) ; + Moveable = TRUE ; + Closeable = TRUE ; + Text [ en-US ] = "Form Navigator" ; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/svx/source/form/fmitems.cxx b/svx/source/form/fmitems.cxx new file mode 100644 index 000000000000..0b388cdb52c4 --- /dev/null +++ b/svx/source/form/fmitems.cxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include "fmitems.hxx" + +#include <svx/svxids.hrc> +#include <tools/stream.hxx> + +//======================================================================== +// class FmInterfaceItem +//======================================================================== +TYPEINIT1(FmInterfaceItem, SfxPoolItem); + +//------------------------------------------------------------------------------ +int FmInterfaceItem::operator==( const SfxPoolItem& rAttr ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" ); + return( xInterface == ((FmInterfaceItem&)rAttr).GetInterface() ); +} + +//------------------------------------------------------------------------------ +SfxPoolItem* FmInterfaceItem::Clone( SfxItemPool* ) const +{ + return new FmInterfaceItem( *this ); +} + +//------------------------------------------------------------------------------ +SvStream& FmInterfaceItem::Store( SvStream& rStrm , sal_uInt16 /*nItemVersion*/ ) const +{ + DBG_ERROR( "FmInterfaceItem::Store: not implemented!" ); + return rStrm; +} + +//------------------------------------------------------------------------------ +SfxPoolItem* FmInterfaceItem::Create( SvStream& /*rStrm*/, sal_uInt16 ) const +{ + DBG_ERROR( "FmInterfaceItem::Create: not implemented!" ); + return new FmInterfaceItem( *this ); +} + + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmmodel.cxx b/svx/source/form/fmmodel.cxx new file mode 100644 index 000000000000..751706c4509a --- /dev/null +++ b/svx/source/form/fmmodel.cxx @@ -0,0 +1,372 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include "fmundo.hxx" +#include "fmdocumentclassification.hxx" +#include "fmcontrollayout.hxx" + +#include <svx/fmmodel.hxx> +#include <svx/fmpage.hxx> +#include <svx/svdobj.hxx> +#include <tools/debug.hxx> + +#ifndef SVX_LIGHT +#include <sfx2/objsh.hxx> +#else +class SfxObjectShell; +#endif + +#include <boost/optional.hpp> + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::container::XNameContainer; +using namespace svxform; + +TYPEINIT1(FmFormModel, SdrModel); + +struct FmFormModelImplData +{ + FmXUndoEnvironment* pUndoEnv; + sal_Bool bOpenInDesignIsDefaulted; + sal_Bool bMovingPage; + ::boost::optional< sal_Bool > + aControlsUseRefDevice; + + FmFormModelImplData() + :pUndoEnv( NULL ) + ,bOpenInDesignIsDefaulted( sal_True ) + ,bMovingPage( sal_False ) + ,aControlsUseRefDevice() + { + } +}; + +/************************************************************************* +|* +|* Ctor +|* +\************************************************************************/ +FmFormModel::FmFormModel(SfxItemPool* pPool, SfxObjectShell* pPers) + :SdrModel(pPool, pPers, LOADREFCOUNTS) + ,m_pImpl(NULL) + ,m_pObjShell(0) + ,m_bOpenInDesignMode(sal_False) + ,m_bAutoControlFocus(sal_False) +{ +#ifndef SVX_LIGHT + m_pImpl = new FmFormModelImplData; + m_pImpl->pUndoEnv = new FmXUndoEnvironment(*this); + m_pImpl->pUndoEnv->acquire(); +#endif +} + +/************************************************************************* +|* +|* Ctor +|* +\************************************************************************/ +FmFormModel::FmFormModel(const XubString& rPath, SfxItemPool* pPool, SfxObjectShell* pPers) + :SdrModel(rPath, pPool, pPers) + ,m_pImpl(NULL) + ,m_pObjShell(0) + ,m_bOpenInDesignMode(sal_False) + ,m_bAutoControlFocus(sal_False) +{ +#ifndef SVX_LIGHT + m_pImpl = new FmFormModelImplData; + m_pImpl->pUndoEnv = new FmXUndoEnvironment(*this); + m_pImpl->pUndoEnv->acquire(); +#endif +} + +/************************************************************************* +|* +|* Ctor +|* +\************************************************************************/ +FmFormModel::FmFormModel(SfxItemPool* pPool, SfxObjectShell* pPers, + bool bUseExtColorTable + ) + :SdrModel(pPool, pPers, bUseExtColorTable, LOADREFCOUNTS) + ,m_pImpl(NULL) + ,m_pObjShell(0) + ,m_bOpenInDesignMode(sal_False) + ,m_bAutoControlFocus(sal_False) +{ +#ifndef SVX_LIGHT + m_pImpl = new FmFormModelImplData; + m_pImpl->pUndoEnv = new FmXUndoEnvironment(*this); + m_pImpl->pUndoEnv->acquire(); +#endif +} + +/************************************************************************* +|* +|* Ctor +|* +\************************************************************************/ +FmFormModel::FmFormModel(const XubString& rPath, SfxItemPool* pPool, SfxObjectShell* pPers, + bool bUseExtColorTable) + :SdrModel(rPath, pPool, pPers, bUseExtColorTable, LOADREFCOUNTS) + ,m_pImpl( NULL ) + ,m_pObjShell(0) + ,m_bOpenInDesignMode(sal_False) + ,m_bAutoControlFocus(sal_False) +{ +#ifndef SVX_LIGHT + m_pImpl = new FmFormModelImplData; + m_pImpl->pUndoEnv = new FmXUndoEnvironment(*this); + m_pImpl->pUndoEnv->acquire(); +#endif +} + +/************************************************************************* +|* +|* Dtor +|* +\************************************************************************/ +FmFormModel::~FmFormModel() +{ +#ifndef SVX_LIGHT + if (m_pObjShell && m_pImpl->pUndoEnv->IsListening(*m_pObjShell)) + SetObjectShell(NULL); + + ClearUndoBuffer(); + // minimale grenze fuer undos + SetMaxUndoActionCount(1); + + m_pImpl->pUndoEnv->release(); + delete m_pImpl; + +#endif +} + +/************************************************************************* +|* +|* Erzeugt eine neue Seite +|* +\************************************************************************/ +SdrPage* FmFormModel::AllocPage(bool bMasterPage) +{ + return new FmFormPage(*this, NULL, bMasterPage); +} + +/************************************************************************* +|* +|* InsertPage +|* +\************************************************************************/ +void FmFormModel::InsertPage(SdrPage* pPage, sal_uInt16 nPos) +{ +#ifndef SVX_LIGHT + // hack solange Methode intern + if (m_pObjShell && !m_pImpl->pUndoEnv->IsListening( *m_pObjShell )) + SetObjectShell(m_pObjShell); +#endif + + SdrModel::InsertPage( pPage, nPos ); +} + +/************************************************************************* +|* +|* MovePage +|* +\************************************************************************/ +void FmFormModel::MovePage( USHORT nPgNum, USHORT nNewPos ) +{ +#ifndef SVX_LIGHT + m_pImpl->bMovingPage = sal_True; + // see InsertPage for this +#endif + + SdrModel::MovePage( nPgNum, nNewPos ); + +#ifndef SVX_LIGHT + m_pImpl->bMovingPage = sal_False; +#endif +} + +/************************************************************************* +|* +|* RemovePage +|* +\************************************************************************/ +SdrPage* FmFormModel::RemovePage(sal_uInt16 nPgNum) +{ + FmFormPage* pToBeRemovedPage = dynamic_cast< FmFormPage* >( GetPage( nPgNum ) ); + OSL_ENSURE( pToBeRemovedPage, "FmFormModel::RemovePage: *which page*?" ); + +#ifndef SVX_LIGHT + if ( pToBeRemovedPage ) + { + Reference< XNameContainer > xForms( pToBeRemovedPage->GetForms( false ) ); + if ( xForms.is() ) + m_pImpl->pUndoEnv->RemoveForms( xForms ); + } +#endif + + FmFormPage* pRemovedPage = (FmFormPage*)SdrModel::RemovePage(nPgNum); + OSL_ENSURE( pRemovedPage == pToBeRemovedPage, "FmFormModel::RemovePage: inconsistency!" ); + return pRemovedPage; +} + +/************************************************************************* +|* +|* InsertMasterPage +|* +\************************************************************************/ +void FmFormModel::InsertMasterPage(SdrPage* pPage, sal_uInt16 nPos) +{ +#ifndef SVX_LIGHT + // hack solange Methode intern + if (m_pObjShell && !m_pImpl->pUndoEnv->IsListening( *m_pObjShell )) + SetObjectShell(m_pObjShell); +#endif + + SdrModel::InsertMasterPage(pPage, nPos); +} + +/************************************************************************* +|* +|* RemoveMasterPage +|* +\************************************************************************/ +SdrPage* FmFormModel::RemoveMasterPage(sal_uInt16 nPgNum) +{ + FmFormPage* pPage = (FmFormPage*)SdrModel::RemoveMasterPage(nPgNum); + +#ifndef SVX_LIGHT + if ( pPage ) + { + Reference< XNameContainer > xForms( pPage->GetForms( false ) ); + if ( xForms.is() ) + m_pImpl->pUndoEnv->RemoveForms( xForms ); + } +#endif + + return pPage; +} + +//------------------------------------------------------------------------ +SdrLayerID FmFormModel::GetControlExportLayerId( const SdrObject& rObj ) const +{ + return rObj.GetLayer(); +} + +//------------------------------------------------------------------------ +void FmFormModel::implSetOpenInDesignMode( sal_Bool _bOpenDesignMode, sal_Bool _bForce ) +{ + if( ( _bOpenDesignMode != m_bOpenInDesignMode ) || _bForce ) + { + m_bOpenInDesignMode = _bOpenDesignMode; + + if ( m_pObjShell ) + m_pObjShell->SetModified( sal_True ); + } + // no matter if we really did it or not - from now on, it does not count as defaulted anymore + m_pImpl->bOpenInDesignIsDefaulted = sal_False; +} + +//------------------------------------------------------------------------ +void FmFormModel::SetOpenInDesignMode( sal_Bool bOpenDesignMode ) +{ +#ifndef SVX_LIGHT + implSetOpenInDesignMode( bOpenDesignMode, sal_False ); +#endif +} + +#ifndef SVX_LIGHT +//------------------------------------------------------------------------ +sal_Bool FmFormModel::OpenInDesignModeIsDefaulted( ) +{ + return m_pImpl->bOpenInDesignIsDefaulted; +} +#endif + +//------------------------------------------------------------------------ +sal_Bool FmFormModel::ControlsUseRefDevice() const +{ + if ( !m_pImpl->aControlsUseRefDevice ) + { + DocumentType eDocType = eUnknownDocumentType; + if ( m_pObjShell ) + eDocType = DocumentClassification::classifyHostDocument( m_pObjShell->GetModel() ); + m_pImpl->aControlsUseRefDevice.reset( ControlLayouter::useDocumentReferenceDevice( eDocType ) ); + } + return *m_pImpl->aControlsUseRefDevice; +} + +//------------------------------------------------------------------------ +void FmFormModel::SetAutoControlFocus( sal_Bool _bAutoControlFocus ) +{ +#ifndef SVX_LIGHT + if( _bAutoControlFocus != m_bAutoControlFocus ) + { + m_bAutoControlFocus = _bAutoControlFocus; + m_pObjShell->SetModified( sal_True ); + } +#endif +} + +//------------------------------------------------------------------------ +void FmFormModel::SetObjectShell( SfxObjectShell* pShell ) +{ +#ifndef SVX_LIGHT + if (pShell == m_pObjShell) + return; + + if (m_pObjShell) + { + m_pImpl->pUndoEnv->EndListening( *this ); + m_pImpl->pUndoEnv->EndListening( *m_pObjShell ); + } + + m_pObjShell = pShell; + + if (m_pObjShell) + { + m_pImpl->pUndoEnv->SetReadOnly( m_pObjShell->IsReadOnly() || m_pObjShell->IsReadOnlyUI(), FmXUndoEnvironment::Accessor() ); + + if (!m_pImpl->pUndoEnv->IsReadOnly()) + m_pImpl->pUndoEnv->StartListening(*this); + + m_pImpl->pUndoEnv->StartListening( *m_pObjShell ); + } +#endif +} + +//------------------------------------------------------------------------ +FmXUndoEnvironment& FmFormModel::GetUndoEnv() +{ + return *m_pImpl->pUndoEnv; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmobj.cxx b/svx/source/form/fmobj.cxx new file mode 100644 index 000000000000..5f8f2e6ab526 --- /dev/null +++ b/svx/source/form/fmobj.cxx @@ -0,0 +1,739 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include "fmobj.hxx" +#include "fmprop.hrc" +#include "fmvwimp.hxx" +#include "fmpgeimp.hxx" +#include "fmresids.hrc" +#include "svx/fmview.hxx" +#include "svx/fmglob.hxx" +#include "svx/fmpage.hxx" +#include "editeng/editeng.hxx" +#include "svx/svdovirt.hxx" +#include "svx/fmmodel.hxx" +#include "svx/dialmgr.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/awt/XDevice.hpp> +#include <com/sun/star/script/XEventAttacherManager.hpp> +#include <com/sun/star/io/XPersistObject.hpp> +#include <com/sun/star/awt/XControlContainer.hpp> +#include <com/sun/star/util/XCloneable.hpp> +/** === end UNO includes === **/ +#include "svx/fmtools.hxx" + +#include <tools/shl.hxx> +#include <comphelper/property.hxx> +#include <comphelper/processfactory.hxx> +#include <toolkit/awt/vclxdevice.hxx> +#include <vcl/svapp.hxx> +#include <tools/resmgr.hxx> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::script; +using namespace ::com::sun::star::container; +using namespace ::svxform; + +TYPEINIT1(FmFormObj, SdrUnoObj); +DBG_NAME(FmFormObj); +//------------------------------------------------------------------ +FmFormObj::FmFormObj(const ::rtl::OUString& rModelName,sal_Int32 _nType) + :SdrUnoObj ( rModelName ) + ,m_nPos ( -1 ) + ,m_nType ( _nType ) + ,m_pLastKnownRefDevice ( NULL ) +{ + DBG_CTOR(FmFormObj, NULL); + + // normally, this is done in SetUnoControlModel, but if the call happened in the base class ctor, + // then our incarnation of it was not called (since we were not constructed at this time). + impl_checkRefDevice_nothrow( true ); +} + +//------------------------------------------------------------------ +FmFormObj::FmFormObj( sal_Int32 _nType ) + :SdrUnoObj ( String() ) + ,m_nPos ( -1 ) + ,m_nType ( _nType ) + ,m_pLastKnownRefDevice ( NULL ) +{ + DBG_CTOR(FmFormObj, NULL); +} + +//------------------------------------------------------------------ +FmFormObj::~FmFormObj() +{ + DBG_DTOR(FmFormObj, NULL); + + Reference< XComponent> xHistory(m_xEnvironmentHistory, UNO_QUERY); + if (xHistory.is()) + xHistory->dispose(); + + m_xEnvironmentHistory = NULL; + m_aEventsHistory.realloc(0); +} + +//------------------------------------------------------------------ +void FmFormObj::SetObjEnv(const Reference< XIndexContainer > & xForm, const sal_Int32 nIdx, + const Sequence< ScriptEventDescriptor >& rEvts) +{ + m_xParent = xForm; + aEvts = rEvts; + m_nPos = nIdx; +} + +//------------------------------------------------------------------ +void FmFormObj::ClearObjEnv() +{ + m_xParent.clear(); + aEvts.realloc( 0 ); + m_nPos = -1; +} + +//------------------------------------------------------------------ +void FmFormObj::impl_checkRefDevice_nothrow( bool _force ) +{ + const FmFormModel* pFormModel = PTR_CAST( FmFormModel, GetModel() ); + if ( !pFormModel || !pFormModel->ControlsUseRefDevice() ) + return; + + OutputDevice* pCurrentRefDevice = pFormModel ? pFormModel->GetRefDevice() : NULL; + if ( ( m_pLastKnownRefDevice == pCurrentRefDevice ) && !_force ) + return; + + Reference< XControlModel > xControlModel( GetUnoControlModel() ); + if ( !xControlModel.is() ) + return; + + m_pLastKnownRefDevice = pCurrentRefDevice; + if ( m_pLastKnownRefDevice == NULL ) + return; + + try + { + Reference< XPropertySet > xModelProps( GetUnoControlModel(), UNO_QUERY_THROW ); + Reference< XPropertySetInfo > xPropertyInfo( xModelProps->getPropertySetInfo(), UNO_SET_THROW ); + + static const ::rtl::OUString sRefDevicePropName( RTL_CONSTASCII_USTRINGPARAM( "ReferenceDevice" ) ); + if ( xPropertyInfo->hasPropertyByName( sRefDevicePropName ) ) + { + VCLXDevice* pUnoRefDevice = new VCLXDevice; + pUnoRefDevice->SetOutputDevice( m_pLastKnownRefDevice ); + Reference< XDevice > xRefDevice( pUnoRefDevice ); + xModelProps->setPropertyValue( sRefDevicePropName, makeAny( xRefDevice ) ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +//------------------------------------------------------------------ +void FmFormObj::impl_isolateControlModel_nothrow() +{ + try + { + Reference< XChild > xControlModel( GetUnoControlModel(), UNO_QUERY ); + if ( xControlModel.is() ) + { + Reference< XIndexContainer> xParent( xControlModel->getParent(), UNO_QUERY ); + if ( xParent.is() ) + { + sal_Int32 nPos = getElementPos( xParent.get(), xControlModel ); + xParent->removeByIndex( nPos ); + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +//------------------------------------------------------------------ +void FmFormObj::SetPage(SdrPage* _pNewPage) +{ + if ( GetPage() == _pNewPage ) + { + SdrUnoObj::SetPage(_pNewPage); + return; + } + + FmFormPage* pOldFormPage = PTR_CAST( FmFormPage, GetPage() ); + if ( pOldFormPage ) + pOldFormPage->GetImpl().formObjectRemoved( *this ); + + FmFormPage* pNewFormPage = PTR_CAST( FmFormPage, _pNewPage ); + if ( !pNewFormPage ) + { // Maybe it makes sense to create an environment history here : if somebody set's our page to NULL, and we have a valid page before, + // me may want to remember our place within the old page. For this we could create a new m_xEnvironmentHistory to store it. + // So the next SetPage with a valid new page would restore that environment within the new page. + // But for the original Bug (#57300#) we don't need that, so I omit it here. Maybe this will be implemented later. + impl_isolateControlModel_nothrow(); + SdrUnoObj::SetPage(_pNewPage); + return; + } + + Reference< XIndexContainer > xNewPageForms( pNewFormPage->GetForms( true ), UNO_QUERY ); + Reference< XIndexContainer > xNewParent; + Sequence< ScriptEventDescriptor> aNewEvents; + + // calc the new parent for my model (within the new page's forms hierarchy) + // do we have a history ? (from :Clone) + if ( m_xEnvironmentHistory.is() ) + { + // the element in m_xEnvironmentHistory which is equivalent to my new parent (which (perhaps) has to be created within _pNewPage->GetForms) + // is the right-most element in the tree. + Reference< XIndexContainer > xRightMostLeaf = m_xEnvironmentHistory; + try + { + while ( xRightMostLeaf->getCount() ) + { + xRightMostLeaf.set( + xRightMostLeaf->getByIndex( xRightMostLeaf->getCount() - 1 ), + UNO_QUERY_THROW + ); + } + + xNewParent.set( ensureModelEnv( xRightMostLeaf, xNewPageForms ), UNO_QUERY_THROW ); + + // we successfully cloned the environment in m_xEnvironmentHistory, so we can use m_aEventsHistory + // (which describes the events of our model at the moment m_xEnvironmentHistory was created) + aNewEvents = m_aEventsHistory; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + if ( !xNewParent.is() ) + { + // are we a valid part of our current page forms ? + Reference< XIndexContainer > xOldForms; + if ( pOldFormPage ) + xOldForms.set( pOldFormPage->GetForms(), UNO_QUERY_THROW ); + + if ( xOldForms.is() ) + { + // search (upward from our model) for xOldForms + Reference< XChild > xSearch( GetUnoControlModel(), UNO_QUERY ); + while (xSearch.is()) + { + if ( xSearch == xOldForms ) + break; + xSearch = Reference< XChild >( xSearch->getParent(), UNO_QUERY ); + } + if ( xSearch.is() ) // implies xSearch == xOldForms, which means we're a valid part of our current page forms hierarchy + { + Reference< XChild > xMeAsChild( GetUnoControlModel(), UNO_QUERY ); + xNewParent.set( ensureModelEnv( xMeAsChild->getParent(), xNewPageForms ), UNO_QUERY ); + + if ( xNewParent.is() ) + { + try + { + // transfer the events from our (model's) parent to the new (model's) parent, too + Reference< XEventAttacherManager > xEventManager(xMeAsChild->getParent(), UNO_QUERY); + Reference< XIndexAccess > xManagerAsIndex(xEventManager, UNO_QUERY); + if (xManagerAsIndex.is()) + { + sal_Int32 nPos = getElementPos(xManagerAsIndex, xMeAsChild); + if (nPos >= 0) + aNewEvents = xEventManager->getScriptEvents(nPos); + } + else + aNewEvents = aEvts; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + } + } + } + + // now set the page + SdrUnoObj::SetPage(_pNewPage); + + // place my model within the new parent container + if (xNewParent.is()) + { + Reference< XFormComponent > xMeAsFormComp(GetUnoControlModel(), UNO_QUERY); + if (xMeAsFormComp.is()) + { + // check if I have another parent (and remove me, if neccessary) + Reference< XIndexContainer > xOldParent(xMeAsFormComp->getParent(), UNO_QUERY); + if (xOldParent.is()) + { + sal_Int32 nPos = getElementPos(Reference< XIndexAccess > (xOldParent, UNO_QUERY), xMeAsFormComp); + if (nPos > -1) + xOldParent->removeByIndex(nPos); + } + // and insert into the new container + xNewParent->insertByIndex(xNewParent->getCount(), makeAny(xMeAsFormComp)); + + // transfer the events + if (aNewEvents.getLength()) + { + try + { + Reference< XEventAttacherManager > xEventManager(xNewParent, UNO_QUERY); + Reference< XIndexAccess > xManagerAsIndex(xEventManager, UNO_QUERY); + if (xManagerAsIndex.is()) + { + sal_Int32 nPos = getElementPos(xManagerAsIndex, xMeAsFormComp); + DBG_ASSERT(nPos >= 0, "FmFormObj::SetPage : inserted but not present ?"); + xEventManager->registerScriptEvents(nPos, aNewEvents); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + } + } + } + + // delete my history + Reference< XComponent> xHistory(m_xEnvironmentHistory, UNO_QUERY); + if (xHistory.is()) + xHistory->dispose(); + + m_xEnvironmentHistory = NULL; + m_aEventsHistory.realloc(0); + + if ( pNewFormPage ) + pNewFormPage->GetImpl().formObjectInserted( *this ); +} + +//------------------------------------------------------------------ +sal_uInt32 FmFormObj::GetObjInventor() const +{ + return FmFormInventor; +} + +//------------------------------------------------------------------ +sal_uInt16 FmFormObj::GetObjIdentifier() const +{ + return OBJ_UNO; +} + +//------------------------------------------------------------------ +void FmFormObj::clonedFrom(const FmFormObj* _pSource) +{ + DBG_ASSERT(_pSource != NULL, "FmFormObj::clonedFrom : invalid source !"); + Reference< XComponent> xHistory(m_xEnvironmentHistory, UNO_QUERY); + if (xHistory.is()) + xHistory->dispose(); + + m_xEnvironmentHistory = NULL; + m_aEventsHistory.realloc(0); + + Reference< XChild > xSourceAsChild(_pSource->GetUnoControlModel(), UNO_QUERY); + if (!xSourceAsChild.is()) + return; + + Reference< XInterface > xSourceContainer = xSourceAsChild->getParent(); + + m_xEnvironmentHistory = Reference< XIndexContainer >( + ::comphelper::getProcessServiceFactory()->createInstance(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.form.Forms")) ), + UNO_QUERY); + DBG_ASSERT(m_xEnvironmentHistory.is(), "FmFormObj::clonedFrom : could not create a forms collection !"); + + if (m_xEnvironmentHistory.is()) + { + ensureModelEnv(xSourceContainer, m_xEnvironmentHistory); + m_aEventsHistory = aEvts; + // if we we're clone there was a call to operator=, so aEvts are excatly the events we need here ... + } +} + +//------------------------------------------------------------------ +SdrObject* FmFormObj::Clone() const +{ + SdrObject* pReturn = SdrUnoObj::Clone(); + + FmFormObj* pFormObject = PTR_CAST(FmFormObj, pReturn); + DBG_ASSERT(pFormObject != NULL, "FmFormObj::Clone : invalid clone !"); + if (pFormObject) + pFormObject->clonedFrom(this); + + return pReturn; +} + +//------------------------------------------------------------------ +void FmFormObj::NbcReformatText() +{ + impl_checkRefDevice_nothrow( false ); + SdrUnoObj::NbcReformatText(); +} + +//------------------------------------------------------------------ +void FmFormObj::operator= (const SdrObject& rObj) +{ + SdrUnoObj::operator= (rObj); + + FmFormObj* pFormObj = PTR_CAST(FmFormObj, &rObj); + if (pFormObj) + { + // liegt das UnoControlModel in einer Eventumgebung, + // dann koennen noch Events zugeordnet sein + Reference< XFormComponent > xContent(pFormObj->xUnoControlModel, UNO_QUERY); + if (xContent.is()) + { + Reference< XEventAttacherManager > xManager(xContent->getParent(), UNO_QUERY); + Reference< XIndexAccess > xManagerAsIndex(xManager, UNO_QUERY); + if (xManagerAsIndex.is()) + { + sal_Int32 nPos = getElementPos( xManagerAsIndex, xContent ); + if ( nPos >= 0 ) + aEvts = xManager->getScriptEvents( nPos ); + } + } + else + aEvts = pFormObj->aEvts; + } +} + +//------------------------------------------------------------------ +namespace +{ + String lcl_getFormComponentAccessPath(const Reference< XInterface >& _xElement, Reference< XInterface >& _rTopLevelElement) + { + Reference< ::com::sun::star::form::XFormComponent> xChild(_xElement, UNO_QUERY); + Reference< ::com::sun::star::container::XIndexAccess> xParent; + if (xChild.is()) + xParent = Reference< ::com::sun::star::container::XIndexAccess>(xChild->getParent(), UNO_QUERY); + + // while the current content is a form + String sReturn; + String sCurrentIndex; + while (xChild.is()) + { + // get the content's relative pos within it's parent container + sal_Int32 nPos = getElementPos(xParent, xChild); + + // prepend this current relaive pos + sCurrentIndex = String::CreateFromInt32(nPos); + if (sReturn.Len() != 0) + { + sCurrentIndex += '\\'; + sCurrentIndex += sReturn; + } + + sReturn = sCurrentIndex; + + // travel up + if (::comphelper::query_interface((Reference< XInterface >)xParent,xChild)) + xParent = Reference< ::com::sun::star::container::XIndexAccess>(xChild->getParent(), UNO_QUERY); + } + + _rTopLevelElement = xParent; + return sReturn; + } +} + +//------------------------------------------------------------------ +Reference< XInterface > FmFormObj::ensureModelEnv(const Reference< XInterface > & _rSourceContainer, const ::com::sun::star::uno::Reference< ::com::sun::star::container::XIndexContainer > _rTopLevelDestContainer) +{ + Reference< XInterface > xTopLevelSouce; + String sAccessPath = lcl_getFormComponentAccessPath(_rSourceContainer, xTopLevelSouce); + if (!xTopLevelSouce.is()) + // somthing went wrong, maybe _rSourceContainer isn't part of a valid forms hierarchy + return Reference< XInterface > (); + + Reference< XIndexContainer > xDestContainer(_rTopLevelDestContainer); + Reference< XIndexContainer > xSourceContainer(xTopLevelSouce, UNO_QUERY); + DBG_ASSERT(xSourceContainer.is(), "FmFormObj::ensureModelEnv : the top level source is invalid !"); + + for (xub_StrLen i=0; i<sAccessPath.GetTokenCount('\\'); ++i) + { + sal_uInt16 nIndex = (sal_uInt16)sAccessPath.GetToken(i, '\\').ToInt32(); + + // get the DSS of the source form (we have to find an aquivalent for) + DBG_ASSERT(nIndex<xSourceContainer->getCount(), "FmFormObj::ensureModelEnv : invalid access path !"); + Reference< XPropertySet > xSourceForm; + xSourceContainer->getByIndex(nIndex) >>= xSourceForm; + DBG_ASSERT(xSourceForm.is(), "FmFormObj::ensureModelEnv : invalid source form !"); + + Any aSrcCursorSource, aSrcCursorSourceType, aSrcDataSource; + DBG_ASSERT(::comphelper::hasProperty(FM_PROP_COMMAND, xSourceForm) && ::comphelper::hasProperty(FM_PROP_COMMANDTYPE, xSourceForm) + && ::comphelper::hasProperty(FM_PROP_DATASOURCE, xSourceForm), "FmFormObj::ensureModelEnv : invalid access path or invalid form (missing props) !"); + // the parent access path should refer to a row set + try + { + aSrcCursorSource = xSourceForm->getPropertyValue(FM_PROP_COMMAND); + aSrcCursorSourceType = xSourceForm->getPropertyValue(FM_PROP_COMMANDTYPE); + aSrcDataSource = xSourceForm->getPropertyValue(FM_PROP_DATASOURCE); + } + catch(Exception&) + { + DBG_ERROR("FmFormObj::ensureModelEnv : could not retrieve a source DSS !"); + } + + + // calc the number of (source) form siblings with the same DSS + Reference< XPropertySet > xCurrentSourceForm, xCurrentDestForm; + sal_Int16 nCurrentSourceIndex = 0, nCurrentDestIndex = 0; + while (nCurrentSourceIndex <= nIndex) + { + sal_Bool bEqualDSS = sal_False; + while (!bEqualDSS) // (we don't have to check nCurrentSourceIndex here : it's bound by nIndex) + { + xSourceContainer->getByIndex(nCurrentSourceIndex) >>= xCurrentSourceForm; + DBG_ASSERT(xCurrentSourceForm.is(), "FmFormObj::ensureModelEnv : invalid form ancestor (2) !"); + bEqualDSS = sal_False; + if (::comphelper::hasProperty(FM_PROP_DATASOURCE, xCurrentSourceForm)) + { // it is a form + try + { + if ( ::comphelper::compare(xCurrentSourceForm->getPropertyValue(FM_PROP_COMMAND), aSrcCursorSource) + && ::comphelper::compare(xCurrentSourceForm->getPropertyValue(FM_PROP_COMMANDTYPE), aSrcCursorSourceType) + && ::comphelper::compare(xCurrentSourceForm->getPropertyValue(FM_PROP_DATASOURCE), aSrcDataSource) + ) + { + bEqualDSS = sal_True; + } + } + catch(Exception&) + { + DBG_ERROR("FmFormObj::ensureModelEnv : exception while getting a sibling's DSS !"); + } + + } + ++nCurrentSourceIndex; + } + + DBG_ASSERT(bEqualDSS, "FmFormObj::ensureModelEnv : found no source form !"); + // ??? at least the nIndex-th one should have been found ??? + + // now search the next one with the given DSS (within the destination container) + bEqualDSS = sal_False; + while (!bEqualDSS && (nCurrentDestIndex < xDestContainer->getCount())) + { + xDestContainer->getByIndex(nCurrentDestIndex) >>= xCurrentDestForm; + DBG_ASSERT(xCurrentDestForm.is(), "FmFormObj::ensureModelEnv : invalid destination form !"); + bEqualDSS = sal_False; + if (::comphelper::hasProperty(FM_PROP_DATASOURCE, xCurrentDestForm)) + { // it is a form + try + { + if ( ::comphelper::compare(xCurrentDestForm->getPropertyValue(FM_PROP_COMMAND), aSrcCursorSource) + && ::comphelper::compare(xCurrentDestForm->getPropertyValue(FM_PROP_COMMANDTYPE), aSrcCursorSourceType) + && ::comphelper::compare(xCurrentDestForm->getPropertyValue(FM_PROP_DATASOURCE), aSrcDataSource) + ) + { + bEqualDSS = sal_True; + } + } + catch(Exception&) + { + DBG_ERROR("FmFormObj::ensureModelEnv : exception while getting a destination DSS !"); + } + + } + ++nCurrentDestIndex; + } + + if (!bEqualDSS) + { // There is at least one more source form with the given DSS than destination forms are. + // correct this ... + try + { + // create and insert (into the destination) a copy of the form + xCurrentDestForm.set( + ::comphelper::getProcessServiceFactory()->createInstance(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.form.component.DataForm" )) ), + UNO_QUERY_THROW ); + ::comphelper::copyProperties( xCurrentSourceForm, xCurrentDestForm ); + + DBG_ASSERT(nCurrentDestIndex == xDestContainer->getCount(), "FmFormObj::ensureModelEnv : something went wrong with the numbers !"); + xDestContainer->insertByIndex(nCurrentDestIndex, makeAny(xCurrentDestForm)); + + ++nCurrentDestIndex; + // like nCurrentSourceIndex, nCurrentDestIndex now points 'behind' the form it actally means + } + catch(Exception&) + { + DBG_ERROR("FmFormObj::ensureModelEnv : something went seriously wrong while creating a new form !"); + // no more options anymore ... + return Reference< XInterface > (); + } + + } + } + + // now xCurrentDestForm is a form equivalent to xSourceForm (which means they have the same DSS and the same number + // of left siblings with the same DSS, which counts for all their ancestors, too) + + // go down + xDestContainer = Reference< XIndexContainer > (xCurrentDestForm, UNO_QUERY); + xSourceContainer = Reference< XIndexContainer > (xSourceForm, UNO_QUERY); + DBG_ASSERT(xDestContainer.is() && xSourceContainer.is(), "FmFormObj::ensureModelEnv : invalid container !"); + } + + return Reference< XInterface > (xDestContainer, UNO_QUERY); +} + +//------------------------------------------------------------------ +void FmFormObj::SetModel( SdrModel* _pNewModel ) +{ + SdrUnoObj::SetModel( _pNewModel ); + impl_checkRefDevice_nothrow(); +} + +//------------------------------------------------------------------ +FmFormObj* FmFormObj::GetFormObject( SdrObject* _pSdrObject ) +{ + FmFormObj* pFormObject = dynamic_cast< FmFormObj* >( _pSdrObject ); + if ( !pFormObject ) + { + SdrVirtObj* pVirtualObject = dynamic_cast< SdrVirtObj* >( _pSdrObject ); + if ( pVirtualObject ) + pFormObject = dynamic_cast< FmFormObj* >( &pVirtualObject->ReferencedObj() ); + } + return pFormObject; +} + +//------------------------------------------------------------------ +const FmFormObj* FmFormObj::GetFormObject( const SdrObject* _pSdrObject ) +{ + const FmFormObj* pFormObject = dynamic_cast< const FmFormObj* >( _pSdrObject ); + if ( !pFormObject ) + { + const SdrVirtObj* pVirtualObject = dynamic_cast< const SdrVirtObj* >( _pSdrObject ); + if ( pVirtualObject ) + pFormObject = dynamic_cast< const FmFormObj* >( &pVirtualObject->GetReferencedObj() ); + } + return pFormObject; +} + +//------------------------------------------------------------------ +void FmFormObj::SetUnoControlModel( const Reference< com::sun::star::awt::XControlModel >& _rxModel ) +{ + SdrUnoObj::SetUnoControlModel( _rxModel ); + + // TODO: call something like formObjectInserted at the form page, to tell it the new model + + impl_checkRefDevice_nothrow( true ); +} + +//------------------------------------------------------------------ +bool FmFormObj::EndCreate( SdrDragStat& rStat, SdrCreateCmd eCmd ) +{ + bool bResult = SdrUnoObj::EndCreate(rStat, eCmd); + if ( bResult && SDRCREATE_FORCEEND == eCmd && rStat.GetView() ) + { + if ( pPage ) + { + FmFormPage& rPage = dynamic_cast< FmFormPage& >( *pPage ); + + try + { + Reference< XFormComponent > xContent( xUnoControlModel, UNO_QUERY_THROW ); + Reference< XForm > xParentForm( xContent->getParent(), UNO_QUERY ); + + Reference< XIndexContainer > xFormToInsertInto; + + if ( !xParentForm.is() ) + { // model is not yet part of a form component hierachy + xParentForm.set( rPage.GetImpl().findPlaceInFormComponentHierarchy( xContent ), UNO_SET_THROW ); + xFormToInsertInto.set( xParentForm, UNO_QUERY_THROW ); + } + + rPage.GetImpl().setUniqueName( xContent, xParentForm ); + + if ( xFormToInsertInto.is() ) + xFormToInsertInto->insertByIndex( xFormToInsertInto->getCount(), makeAny( xContent ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + FmFormView* pView( dynamic_cast< FmFormView* >( rStat.GetView() ) ); + FmXFormView* pViewImpl = pView ? pView->GetImpl() : NULL; + OSL_ENSURE( pViewImpl, "FmFormObj::EndCreate: no view!?" ); + if ( pViewImpl ) + pViewImpl->onCreatedFormObject( *this ); + } + return bResult; +} + +//------------------------------------------------------------------------------ +void FmFormObj::BrkCreate( SdrDragStat& rStat ) +{ + SdrUnoObj::BrkCreate( rStat ); + impl_isolateControlModel_nothrow(); +} + +// ----------------------------------------------------------------------------- +sal_Int32 FmFormObj::getType() const +{ + return m_nType; +} + +// ----------------------------------------------------------------------------- +// #i70852# overload Layer interface to force to FormColtrol layer + +SdrLayerID FmFormObj::GetLayer() const +{ + // #i72535# + // i70852 was too radical, in SW obects (and thus, FormControls, too) + // get moved to invisible layers to hide them (e.g. in hidden sections). + // This means that form controls ARE allowed to be on other layers than + // the form control layer ATM and that being member of form control layer + // is no criteria to find all FormControls of a document. + // To fix, use parent functionality + return SdrUnoObj::GetLayer(); +} + +void FmFormObj::NbcSetLayer(SdrLayerID nLayer) +{ + // #i72535# + // See above. To fix, use parent functionality + return SdrUnoObj::NbcSetLayer(nLayer); +} + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmobjfac.cxx b/svx/source/form/fmobjfac.cxx new file mode 100644 index 000000000000..7d71331acf00 --- /dev/null +++ b/svx/source/form/fmobjfac.cxx @@ -0,0 +1,266 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include <comphelper/stl_types.hxx> +#include <svx/svdobj.hxx> +#include "svx/fmtools.hxx" +#include "fmservs.hxx" + +#include "fmobjfac.hxx" + +#include <svx/fmglob.hxx> + +#include "fmobj.hxx" +#include "fmshimp.hxx" + +#include <svx/fmshell.hxx> + +#include <svx/svxids.hrc> +#include "tbxform.hxx" +#include <tools/resid.hxx> + +#include "fmresids.hrc" +#include <tools/shl.hxx> +#include <svx/dialmgr.hxx> +#include "fmservs.hxx" +#include "tabwin.hxx" +#include "fmexpl.hxx" +#include "filtnav.hxx" + +#include "fmprop.hrc" +#include "fmPropBrw.hxx" +#include "datanavi.hxx" + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::svxform; + +static BOOL bInit = FALSE; + +/************************************************************************* +|* +|* Ctor +|* +\************************************************************************/ +FmFormObjFactory::FmFormObjFactory() +{ + if ( !bInit ) + { + SdrObjFactory::InsertMakeObjectHdl(LINK(this, FmFormObjFactory, MakeObject)); + + ////////////////////////////////////////////////////////////////////// + // Konfigurations-::com::sun::star::frame::Controller und NavigationBar registrieren + SvxFmTbxCtlConfig::RegisterControl( SID_FM_CONFIG ); + SvxFmTbxCtlAbsRec::RegisterControl( SID_FM_RECORD_ABSOLUTE ); + SvxFmTbxCtlRecText::RegisterControl( SID_FM_RECORD_TEXT ); + SvxFmTbxCtlRecFromText::RegisterControl( SID_FM_RECORD_FROM_TEXT ); + SvxFmTbxCtlRecTotal::RegisterControl( SID_FM_RECORD_TOTAL ); + SvxFmTbxPrevRec::RegisterControl( SID_FM_RECORD_PREV ); + SvxFmTbxNextRec::RegisterControl( SID_FM_RECORD_NEXT ); + ControlConversionMenuController::RegisterControl(SID_FM_CHANGECONTROLTYPE); + + // Registrieung von globalen fenstern + FmFieldWinMgr::RegisterChildWindow(); + FmPropBrwMgr::RegisterChildWindow(); + NavigatorFrameManager::RegisterChildWindow(); + DataNavigatorManager::RegisterChildWindow(); + FmFilterNavigatorWinMgr::RegisterChildWindow(); + + ////////////////////////////////////////////////////////////////////// + // Interface fuer die Formshell registrieren + FmFormShell::RegisterInterface(0); + + ImplSmartRegisterUnoServices(); + bInit = TRUE; + } +} + + +/************************************************************************* +|* +|* Dtor +|* +\************************************************************************/ +FmFormObjFactory::~FmFormObjFactory() +{ +} + + +/************************************************************************* +|* +|* ::com::sun::star::form::Form-Objekte erzeugen +|* +\************************************************************************/ +namespace +{ + void lcl_initProperty( FmFormObj* _pObject, const ::rtl::OUString& _rPropName, const Any& _rValue ) + { + try + { + Reference< XPropertySet > xModelSet( _pObject->GetUnoControlModel(), UNO_QUERY ); + if ( xModelSet.is() ) + xModelSet->setPropertyValue( _rPropName, _rValue ); + } + catch( const Exception& ) + { + DBG_ERROR( "lcl_initProperty: caught an exception!" ); + } + } +} + +IMPL_LINK(FmFormObjFactory, MakeObject, SdrObjFactory*, pObjFactory) +{ + if (pObjFactory->nInventor == FmFormInventor) + { + ::rtl::OUString sServiceSpecifier; + + typedef ::std::vector< ::std::pair< ::rtl::OUString, Any > > PropertyValueArray; + PropertyValueArray aInitialProperties; + + switch ( pObjFactory->nIdentifier ) + { + case OBJ_FM_EDIT: + sServiceSpecifier = FM_COMPONENT_EDIT; + break; + + case OBJ_FM_BUTTON: + sServiceSpecifier = FM_COMPONENT_COMMANDBUTTON; + break; + + case OBJ_FM_FIXEDTEXT: + sServiceSpecifier = FM_COMPONENT_FIXEDTEXT; + break; + + case OBJ_FM_LISTBOX: + sServiceSpecifier = FM_COMPONENT_LISTBOX; + break; + + case OBJ_FM_CHECKBOX: + sServiceSpecifier = FM_COMPONENT_CHECKBOX; + break; + + case OBJ_FM_RADIOBUTTON: + sServiceSpecifier = FM_COMPONENT_RADIOBUTTON; + break; + + case OBJ_FM_GROUPBOX: + sServiceSpecifier = FM_COMPONENT_GROUPBOX; + break; + + case OBJ_FM_COMBOBOX: + sServiceSpecifier = FM_COMPONENT_COMBOBOX; + break; + + case OBJ_FM_GRID: + sServiceSpecifier = FM_COMPONENT_GRID; + break; + + case OBJ_FM_IMAGEBUTTON: + sServiceSpecifier = FM_COMPONENT_IMAGEBUTTON; + break; + + case OBJ_FM_FILECONTROL: + sServiceSpecifier = FM_COMPONENT_FILECONTROL; + break; + + case OBJ_FM_DATEFIELD: + sServiceSpecifier = FM_COMPONENT_DATEFIELD; + break; + + case OBJ_FM_TIMEFIELD: + sServiceSpecifier = FM_COMPONENT_TIMEFIELD; + aInitialProperties.push_back( PropertyValueArray::value_type( FM_PROP_TIMEMAX, makeAny( (sal_Int32)( Time( 23, 59, 59, 99 ).GetTime() ) ) ) ); + break; + + case OBJ_FM_NUMERICFIELD: + sServiceSpecifier = FM_COMPONENT_NUMERICFIELD; + break; + + case OBJ_FM_CURRENCYFIELD: + sServiceSpecifier = FM_COMPONENT_CURRENCYFIELD; + break; + + case OBJ_FM_PATTERNFIELD: + sServiceSpecifier = FM_COMPONENT_PATTERNFIELD; + break; + + case OBJ_FM_HIDDEN: + sServiceSpecifier = FM_COMPONENT_HIDDEN; + break; + + case OBJ_FM_IMAGECONTROL: + sServiceSpecifier = FM_COMPONENT_IMAGECONTROL; + break; + + case OBJ_FM_FORMATTEDFIELD: + sServiceSpecifier = FM_COMPONENT_FORMATTEDFIELD; + break; + + case OBJ_FM_NAVIGATIONBAR: + sServiceSpecifier = FM_SUN_COMPONENT_NAVIGATIONBAR; + break; + + case OBJ_FM_SCROLLBAR: + sServiceSpecifier = FM_SUN_COMPONENT_SCROLLBAR; + aInitialProperties.push_back( PropertyValueArray::value_type( FM_PROP_BORDER, makeAny( (sal_Int16)0 ) ) ); + break; + + case OBJ_FM_SPINBUTTON: + sServiceSpecifier = FM_SUN_COMPONENT_SPINBUTTON; + aInitialProperties.push_back( PropertyValueArray::value_type( FM_PROP_BORDER, makeAny( (sal_Int16)0 ) ) ); + break; + } + + // create the actual object + if ( sServiceSpecifier.getLength() ) + pObjFactory->pNewObj = new FmFormObj( sServiceSpecifier, pObjFactory->nIdentifier ); + else + pObjFactory->pNewObj = new FmFormObj( pObjFactory->nIdentifier ); + + // initialize some properties which we want to differ from the defaults + for ( PropertyValueArray::const_iterator aInitProp = aInitialProperties.begin(); + aInitProp != aInitialProperties.end(); + ++aInitProp + ) + { + lcl_initProperty( + static_cast< FmFormObj* >( pObjFactory->pNewObj ), + aInitProp->first, + aInitProp->second + ); + } + } + + return 0; +} + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmpage.cxx b/svx/source/form/fmpage.cxx new file mode 100644 index 000000000000..ddcf5a445926 --- /dev/null +++ b/svx/source/form/fmpage.cxx @@ -0,0 +1,274 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include <sal/macros.h> + +#define ENABLE_BYTESTRING_STREAM_OPERATORS +#include <svx/fmpage.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XNameContainer.hpp> + + +#include <svx/fmmodel.hxx> + +#ifndef SVX_LIGHT +#include "fmobj.hxx" +#endif + +#ifndef SVX_LIGHT +#include "fmresids.hrc" +#endif +#include <tools/shl.hxx> +#include <svx/dialmgr.hxx> + +#ifndef SVX_LIGHT +#include "fmpgeimp.hxx" +#endif + +#ifndef SVX_LIGHT +#include <sfx2/objsh.hxx> +#endif +#include "svditer.hxx" +#include <svx/svdview.hxx> +#include <tools/urlobj.hxx> +#include <vcl/help.hxx> + + +#ifndef SVX_LIGHT +#include <svx/fmglob.hxx> +#include "fmprop.hrc" +#include "fmundo.hxx" +#include "svx/fmtools.hxx" +using namespace ::svxform; +#endif +#include <comphelper/property.hxx> +#include <rtl/logfile.hxx> + +using com::sun::star::uno::Reference; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::container::XChild; +using com::sun::star::container::XNameContainer; + +TYPEINIT1(FmFormPage, SdrPage); + +//------------------------------------------------------------------ +FmFormPage::FmFormPage(FmFormModel& rModel, StarBASIC* _pBasic, bool bMasterPage) + :SdrPage(rModel, bMasterPage) +#ifndef SVX_LIGHT + ,m_pImpl( new FmFormPageImpl( *this ) ) +#else + ,m_pImpl(NULL) +#endif + ,m_pBasic(_pBasic) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmFormPage::FmFormPage" ); +} + +//------------------------------------------------------------------ +FmFormPage::FmFormPage(const FmFormPage& rPage) + :SdrPage(rPage) +#ifndef SVX_LIGHT + ,m_pImpl(new FmFormPageImpl( *this, rPage.GetImpl() ) ) +#else + ,m_pImpl(NULL) +#endif + ,m_pBasic(0) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmFormPage::FmFormPage" ); + m_sPageName = rPage.m_sPageName; +} + +//------------------------------------------------------------------ +FmFormPage::~FmFormPage() +{ +#ifndef SVX_LIGHT + delete m_pImpl; +#endif +} + +//------------------------------------------------------------------ +void FmFormPage::SetModel(SdrModel* pNewModel) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmFormPage::SetModel" ); + /* #35055# */ + // we want to call the super's "SetModel" method even if the model is the + // same, in case code somewhere in the system depends on it. But our code + // doesn't, so get the old model to do a check. + SdrModel *pOldModel = GetModel(); + + SdrPage::SetModel( pNewModel ); + + /* #35055# */ + if ( ( pOldModel != pNewModel ) && m_pImpl ) + { + try + { + Reference< XNameContainer > xForms( m_pImpl->getForms( false ) ); + if ( xForms.is() ) + { + // we want to keep the current collection, just reset the model + // with which it's associated. + Reference< XChild > xAsChild( xForms, UNO_QUERY ); + if ( xAsChild.is() ) + { + FmFormModel* pDrawModel = (FmFormModel*) GetModel(); + SfxObjectShell* pObjShell = pDrawModel->GetObjectShell(); + if ( pObjShell ) + xAsChild->setParent( pObjShell->GetModel() ); + } + } + } + catch( ::com::sun::star::uno::Exception const& ) + { + OSL_ENSURE( sal_False, "UNO Exception caught resetting model for m_pImpl (FmFormPageImpl) in FmFormPage::SetModel" ); + } + } +} + +//------------------------------------------------------------------ +SdrPage* FmFormPage::Clone() const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmFormPage::Clone" ); + return new FmFormPage(*this); + // hier fehlt noch ein kopieren der Objekte +} + +//------------------------------------------------------------------ +void FmFormPage::InsertObject(SdrObject* pObj, ULONG nPos, + const SdrInsertReason* pReason) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmFormPage::InsertObject" ); + SdrPage::InsertObject( pObj, nPos, pReason ); +#ifndef SVX_LIGHT + if (GetModel() && (!pReason || pReason->GetReason() != SDRREASON_STREAMING)) + ((FmFormModel*)GetModel())->GetUndoEnv().Inserted(pObj); +#endif +} + +//------------------------------------------------------------------ +const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer > & FmFormPage::GetForms( bool _bForceCreate ) const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmFormPage::GetForms" ); +#ifndef SVX_LIGHT + const SdrPage& rMasterPage( *this ); + const FmFormPage* pFormPage = dynamic_cast< const FmFormPage* >( &rMasterPage ); + OSL_ENSURE( pFormPage, "FmFormPage::GetForms: referenced page is no FmFormPage - is this allowed?!" ); + if ( !pFormPage ) + pFormPage = this; + + return pFormPage->m_pImpl->getForms( _bForceCreate ); +#else + static ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer > aRef; + return aRef; +#endif +} + +//------------------------------------------------------------------ +sal_Bool FmFormPage::RequestHelp( Window* pWindow, SdrView* pView, + const HelpEvent& rEvt ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmFormPage::RequestHelp" ); +#ifndef SVX_LIGHT + if( pView->IsAction() ) + return sal_False; + + Point aPos = rEvt.GetMousePosPixel(); + aPos = pWindow->ScreenToOutputPixel( aPos ); + aPos = pWindow->PixelToLogic( aPos ); + + SdrObject* pObj = NULL; + SdrPageView* pPV = NULL; + if ( !pView->PickObj( aPos, 0, pObj, pPV, SDRSEARCH_DEEP ) ) + return sal_False; + + FmFormObj* pFormObject = FmFormObj::GetFormObject( pObj ); + if ( !pFormObject ) + return sal_False; + + UniString aHelpText; + ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > xSet( pFormObject->GetUnoControlModel(), ::com::sun::star::uno::UNO_QUERY ); + if (xSet.is()) + { + if (::comphelper::hasProperty(FM_PROP_HELPTEXT, xSet)) + aHelpText = ::comphelper::getString(xSet->getPropertyValue(FM_PROP_HELPTEXT)).getStr(); + + if (!aHelpText.Len() && ::comphelper::hasProperty(FM_PROP_TARGET_URL, xSet)) + { + ::rtl::OUString aText = ::comphelper::getString(xSet->getPropertyValue(FM_PROP_TARGET_URL)); + INetURLObject aUrl(aText); + + // testen, ob es ein Protokoll-Typ ist, den ich anzeigen will + INetProtocol aProtocol = aUrl.GetProtocol(); + static const INetProtocol s_aQuickHelpSupported[] = + { INET_PROT_FTP, INET_PROT_HTTP, INET_PROT_FILE, INET_PROT_MAILTO, INET_PROT_NEWS, + INET_PROT_HTTPS, INET_PROT_JAVASCRIPT, INET_PROT_IMAP, INET_PROT_POP3, + INET_PROT_VIM, INET_PROT_LDAP + }; + for (sal_uInt16 i=0; i < SAL_N_ELEMENTS(s_aQuickHelpSupported); ++i) + if (s_aQuickHelpSupported[i] == aProtocol) + { + aHelpText = INetURLObject::decode(aUrl.GetURLNoPass(), '%', INetURLObject::DECODE_UNAMBIGUOUS); + break; + } + } + } + if ( aHelpText.Len() != 0 ) + { + // Hilfe anzeigen + Rectangle aItemRect = pObj->GetCurrentBoundRect(); + aItemRect = pWindow->LogicToPixel( aItemRect ); + Point aPt = pWindow->OutputToScreenPixel( aItemRect.TopLeft() ); + aItemRect.Left() = aPt.X(); + aItemRect.Top() = aPt.Y(); + aPt = pWindow->OutputToScreenPixel( aItemRect.BottomRight() ); + aItemRect.Right() = aPt.X(); + aItemRect.Bottom() = aPt.Y(); + if( rEvt.GetMode() == HELPMODE_BALLOON ) + Help::ShowBalloon( pWindow, aItemRect.Center(), aItemRect, aHelpText); + else + Help::ShowQuickHelp( pWindow, aItemRect, aHelpText ); + } +#endif + return sal_True; +} + +//------------------------------------------------------------------ +SdrObject* FmFormPage::RemoveObject(ULONG nObjNum) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmFormPage::RemoveObject" ); + SdrObject* pObj = SdrPage::RemoveObject(nObjNum); +#ifndef SVX_LIGHT + if (pObj && GetModel()) + ((FmFormModel*)GetModel())->GetUndoEnv().Removed(pObj); +#endif + return pObj; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmpgeimp.cxx b/svx/source/form/fmpgeimp.cxx new file mode 100644 index 000000000000..0fef03f19257 --- /dev/null +++ b/svx/source/form/fmpgeimp.cxx @@ -0,0 +1,742 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include "svxerr.hxx" +#include "fmpgeimp.hxx" +#include "fmundo.hxx" +#include "svx/fmtools.hxx" +#include "fmprop.hrc" +#include "fmservs.hxx" +#include "fmobj.hxx" +#include "formcontrolfactory.hxx" +#include "svditer.hxx" +#include "fmresids.hrc" +#include "svx/dbtoolsclient.hxx" +#include "treevisitor.hxx" + +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/util/XCloneable.hpp> +#include <com/sun/star/container/EnumerableMap.hpp> +#include <com/sun/star/drawing/XControlShape.hpp> + +#include <sfx2/objsh.hxx> +#include <svx/fmglob.hxx> +#include <svx/fmpage.hxx> +#include <svx/fmmodel.hxx> +#include <tools/resid.hxx> +#include <tools/diagnose_ex.h> +#include <tools/shl.hxx> +#include <vcl/stdtext.hxx> +#include <svx/dialmgr.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/componentcontext.hxx> +#include <comphelper/uno3.hxx> +#include <comphelper/types.hxx> +#include <unotools/streamwrap.hxx> +#include <rtl/logfile.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::form; +using ::com::sun::star::util::XCloneable; +using ::com::sun::star::awt::XControlModel; +using ::com::sun::star::container::XMap; +using ::com::sun::star::container::EnumerableMap; +using ::com::sun::star::drawing::XControlShape; +using namespace ::svxform; + +DBG_NAME(FmFormPageImpl) +//------------------------------------------------------------------------------ +FmFormPageImpl::FmFormPageImpl( FmFormPage& _rPage ) + :m_rPage( _rPage ) + ,m_bFirstActivation( sal_True ) + ,m_bAttemptedFormCreation( false ) + ,m_bInFind( false ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmFormPageImpl::FmFormPageImpl" ); + DBG_CTOR(FmFormPageImpl,NULL); +} + +//------------------------------------------------------------------------------ +namespace +{ + typedef Reference< XInterface > FormComponent; + + class FormComponentInfo + { + public: + size_t childCount( const FormComponent& _component ) const + { + Reference< XIndexAccess > xContainer( _component, UNO_QUERY ); + if ( xContainer.is() ) + return xContainer->getCount(); + return 0; + } + + FormComponent getChild( const FormComponent& _component, size_t _index ) const + { + Reference< XIndexAccess > xContainer( _component, UNO_QUERY_THROW ); + return FormComponent( xContainer->getByIndex( _index ), UNO_QUERY ); + } + }; + + typedef ::std::pair< FormComponent, FormComponent > FormComponentPair; + + class FormHierarchyComparator + { + public: + FormHierarchyComparator() + { + } + + size_t childCount( const FormComponentPair& _components ) const + { + size_t lhsCount = m_aComponentInfo.childCount( _components.first ); + size_t rhsCount = m_aComponentInfo.childCount( _components.second ); + if ( lhsCount != rhsCount ) + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Found inconsistent form component hierarchies (1)!" ) ), NULL ); + return lhsCount; + } + + FormComponentPair getChild( const FormComponentPair& _components, size_t _index ) const + { + return FormComponentPair( + m_aComponentInfo.getChild( _components.first, _index ), + m_aComponentInfo.getChild( _components.second, _index ) + ); + } + private: + FormComponentInfo m_aComponentInfo; + }; + + typedef ::std::map< Reference< XControlModel >, Reference< XControlModel >, ::comphelper::OInterfaceCompare< XControlModel > > MapControlModels; + + class FormComponentAssignment + { + public: + FormComponentAssignment( MapControlModels& _out_controlModelMap ) + :m_rControlModelMap( _out_controlModelMap ) + { + } + + void process( const FormComponentPair& _component ) + { + Reference< XControlModel > lhsControlModel( _component.first, UNO_QUERY ); + Reference< XControlModel > rhsControlModel( _component.second, UNO_QUERY ); + if ( lhsControlModel.is() != rhsControlModel.is() ) + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Found inconsistent form component hierarchies (2)!" ) ), NULL ); + + if ( lhsControlModel.is() ) + m_rControlModelMap[ lhsControlModel ] = rhsControlModel; + } + + private: + MapControlModels& m_rControlModelMap; + }; +} + +//------------------------------------------------------------------------------ +FmFormPageImpl::FmFormPageImpl( FmFormPage& _rPage, const FmFormPageImpl& rImpl ) + :m_rPage( _rPage ) + ,m_bFirstActivation( sal_True ) + ,m_bAttemptedFormCreation( false ) +{ + DBG_CTOR(FmFormPageImpl,NULL); + + // clone the Forms collection + Reference< XCloneable > xCloneable( const_cast< FmFormPageImpl& >( rImpl ).getForms( false ), UNO_QUERY ); + if ( !xCloneable.is() ) + { + // great, nothing to do + OSL_ENSURE( !const_cast< FmFormPageImpl& >( rImpl ).getForms( false ).is(), "FmFormPageImpl::FmFormPageImpl: a non-cloneable forms container!?" ); + return; + } + try + { + m_xForms.set( xCloneable->createClone(), UNO_QUERY_THROW ); + + // create a mapping between the original control models and their clones + MapControlModels aModelAssignment; + + typedef TreeVisitor< FormComponentPair, FormHierarchyComparator, FormComponentAssignment > FormComponentVisitor; + FormComponentVisitor aVisitor = FormComponentVisitor( FormHierarchyComparator() ); + + FormComponentAssignment aAssignmentProcessor( aModelAssignment ); + aVisitor.process( FormComponentPair( xCloneable, m_xForms ), aAssignmentProcessor ); + + // assign the cloned models to their SdrObjects + SdrObjListIter aForeignIter( rImpl.m_rPage ); + SdrObjListIter aOwnIter( m_rPage ); + + OSL_ENSURE( aForeignIter.IsMore() == aOwnIter.IsMore(), "FmFormPageImpl::FmFormPageImpl: inconsistent number of objects (1)!" ); + while ( aForeignIter.IsMore() && aOwnIter.IsMore() ) + { + FmFormObj* pForeignObj = dynamic_cast< FmFormObj* >( aForeignIter.Next() ); + FmFormObj* pOwnObj = dynamic_cast< FmFormObj* >( aOwnIter.Next() ); + + bool bForeignIsForm = pForeignObj && ( pForeignObj->GetObjInventor() == FmFormInventor ); + bool bOwnIsForm = pOwnObj && ( pOwnObj->GetObjInventor() == FmFormInventor ); + + if ( bForeignIsForm != bOwnIsForm ) + { + OSL_ENSURE( false, "FmFormPageImpl::FmFormPageImpl: inconsistent ordering of objects!" ); + // don't attempt to do further assignments, something's completely messed up + break; + } + if ( !bForeignIsForm ) + // no form control -> next round + continue; + + Reference< XControlModel > xForeignModel( pForeignObj->GetUnoControlModel() ); + OSL_ENSURE( xForeignModel.is(), "FmFormPageImpl::FmFormPageImpl: control shape without control!" ); + if ( !xForeignModel.is() ) + // the SdrObject does not have a UNO Control Model. This is pathological, but well ... So the cloned + // SdrObject will also not have a UNO Control Model. + continue; + + OSL_ENSURE( !pOwnObj->GetUnoControlModel().is(), "FmFormPageImpl::FmFormPageImpl: there already is a control model for the target object!" ); + + MapControlModels::const_iterator assignment = aModelAssignment.find( xForeignModel ); + OSL_ENSURE( assignment != aModelAssignment.end(), "FmFormPageImpl::FmFormPageImpl: no clone found for this model!" ); + if ( assignment == aModelAssignment.end() ) + // the source SdrObject has a model, but it is not part of the model hierarchy in rImpl.getForms(). + // Pathological, too ... + continue; + + pOwnObj->SetUnoControlModel( assignment->second ); + } + OSL_ENSURE( aForeignIter.IsMore() == aOwnIter.IsMore(), "FmFormPageImpl::FmFormPageImpl: inconsistent number of objects (2)!" ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +//------------------------------------------------------------------------------ +Reference< XMap > FmFormPageImpl::getControlToShapeMap() +{ + Reference< XMap > xControlShapeMap( m_aControlShapeMap.get(), UNO_QUERY ); + if ( xControlShapeMap.is() ) + return xControlShapeMap; + + xControlShapeMap = impl_createControlShapeMap_nothrow(); + m_aControlShapeMap = xControlShapeMap; + return xControlShapeMap; +} + +//------------------------------------------------------------------------------ +namespace +{ + static void lcl_insertFormObject_throw( const FmFormObj& _object, const Reference< XMap >& _map ) + { + // the control model + Reference< XControlModel > xControlModel( _object.GetUnoControlModel(), UNO_QUERY ); + OSL_ENSURE( xControlModel.is(), "lcl_insertFormObject_throw: suspicious: no control model!" ); + if ( !xControlModel.is() ) + return; + + Reference< XControlShape > xControlShape( const_cast< FmFormObj& >( _object ).getUnoShape(), UNO_QUERY ); + OSL_ENSURE( xControlShape.is(), "lcl_insertFormObject_throw: suspicious: no control shape!" ); + if ( !xControlShape.is() ) + return; + + _map->put( makeAny( xControlModel ), makeAny( xControlShape ) ); + } + + static void lcl_removeFormObject( const FmFormObj& _object, const Reference< XMap >& _map ) + { + // the control model + Reference< XControlModel > xControlModel( _object.GetUnoControlModel(), UNO_QUERY ); + OSL_ENSURE( xControlModel.is(), "lcl_removeFormObject: suspicious: no control model!" ); + if ( !xControlModel.is() ) + return; + + #if OSL_DEBUG_LEVEL > 0 + Any aOldAssignment = + #endif + _map->remove( makeAny( xControlModel ) ); + OSL_ENSURE( aOldAssignment == makeAny( Reference< XControlShape >( const_cast< FmFormObj& >( _object ).getUnoShape(), UNO_QUERY ) ), + "lcl_removeFormObject: map was inconsistent!" ); + } +} + +//------------------------------------------------------------------------------ +Reference< XMap > FmFormPageImpl::impl_createControlShapeMap_nothrow() +{ + Reference< XMap > xMap; + + try + { + ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() ); + xMap.set( EnumerableMap::create( aContext.getUNOContext(), + ::cppu::UnoType< XControlModel >::get(), + ::cppu::UnoType< XControlShape >::get() + ).get(), UNO_SET_THROW ); + + SdrObjListIter aPageIter( m_rPage ); + while ( aPageIter.IsMore() ) + { + // only FmFormObjs are what we're interested in + FmFormObj* pCurrent = FmFormObj::GetFormObject( aPageIter.Next() ); + if ( !pCurrent ) + continue; + + lcl_insertFormObject_throw( *pCurrent, xMap ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return xMap; +} + +//------------------------------------------------------------------------------ +const Reference< XNameContainer >& FmFormPageImpl::getForms( bool _bForceCreate ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmFormPageImpl::getForms" ); + if ( m_xForms.is() || !_bForceCreate ) + return m_xForms; + + if ( !m_bAttemptedFormCreation ) + { + m_bAttemptedFormCreation = true; + + const ::rtl::OUString sFormsCollectionServiceName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.form.Forms") ); + m_xForms = Reference< XNameContainer > ( + ::comphelper::getProcessServiceFactory()->createInstance( sFormsCollectionServiceName ), + UNO_QUERY + ); + DBG_ASSERT( m_xForms.is(), "FmFormPageImpl::getForms: could not create a forms collection!" ); + + if ( m_aFormsCreationHdl.IsSet() ) + { + m_aFormsCreationHdl.Call( this ); + } + + FmFormModel* pFormsModel = PTR_CAST( FmFormModel, m_rPage.GetModel() ); + + // give the newly created collection a place in the universe + Reference< XChild > xAsChild( m_xForms, UNO_QUERY ); + if ( xAsChild.is() ) + { + SfxObjectShell* pObjShell = pFormsModel ? pFormsModel->GetObjectShell() : NULL; + if ( pObjShell ) + xAsChild->setParent( pObjShell->GetModel() ); + } + + // tell the UNDO environment that we have a new forms collection + if ( pFormsModel ) + pFormsModel->GetUndoEnv().AddForms( m_xForms ); + } + return m_xForms; +} + +//------------------------------------------------------------------------------ +FmFormPageImpl::~FmFormPageImpl() +{ + xCurrentForm = NULL; + + ::comphelper::disposeComponent( m_xForms ); + DBG_DTOR(FmFormPageImpl,NULL); +} + +//------------------------------------------------------------------------------ +bool FmFormPageImpl::validateCurForm() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmFormPageImpl::validateCurForm" ); + if ( !xCurrentForm.is() ) + return false; + + Reference< XChild > xAsChild( xCurrentForm, UNO_QUERY ); + DBG_ASSERT( xAsChild.is(), "FmFormPageImpl::validateCurForm: a form which is no child??" ); + if ( !xAsChild.is() || !xAsChild->getParent().is() ) + xCurrentForm.clear(); + + return xCurrentForm.is(); +} + +//------------------------------------------------------------------------------ +void FmFormPageImpl::setCurForm(Reference< ::com::sun::star::form::XForm > xForm) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmFormPageImpl::setCurForm" ); + xCurrentForm = xForm; +} + +//------------------------------------------------------------------------------ +Reference< XForm > FmFormPageImpl::getDefaultForm() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmFormPageImpl::getDefaultForm" ); + Reference< XForm > xForm; + + Reference< XNameContainer > xForms( getForms() ); + + // by default, we use our "current form" + if ( !validateCurForm() ) + { + // check whether there is a "standard" form + if ( xForms->hasElements() ) + { + // suche die Standardform + ::rtl::OUString sStandardFormname = String( SVX_RES( RID_STR_STDFORMNAME ) ); + + try + { + if ( xForms->hasByName( sStandardFormname ) ) + xForm.set( xForms->getByName( sStandardFormname ), UNO_QUERY_THROW ); + else + { + Reference< XIndexAccess > xFormsByIndex( xForms, UNO_QUERY_THROW ); + xForm.set( xFormsByIndex->getByIndex(0), UNO_QUERY_THROW ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + } + else + { + xForm = xCurrentForm; + } + + // did not find an existing suitable form -> create a new one + if ( !xForm.is() ) + { + SdrModel* pModel = m_rPage.GetModel(); + + if( pModel->IsUndoEnabled() ) + { + XubString aStr(SVX_RES(RID_STR_FORM)); + XubString aUndoStr(SVX_RES(RID_STR_UNDO_CONTAINER_INSERT)); + aUndoStr.SearchAndReplace('#', aStr); + pModel->BegUndo(aUndoStr); + } + + try + { + xForm.set( ::comphelper::getProcessServiceFactory()->createInstance( FM_SUN_COMPONENT_FORM ), UNO_QUERY ); + + // a form should always have the command type table as default + Reference< XPropertySet > xFormProps( xForm, UNO_QUERY_THROW ); + xFormProps->setPropertyValue( FM_PROP_COMMANDTYPE, makeAny( sal_Int32( CommandType::TABLE ) ) ); + + // and the "Standard" name + ::rtl::OUString sName = String( SVX_RES( RID_STR_STDFORMNAME ) ); + xFormProps->setPropertyValue( FM_PROP_NAME, makeAny( sName ) ); + + Reference< XIndexContainer > xContainer( xForms, UNO_QUERY ); + if( pModel->IsUndoEnabled() ) + { + pModel->AddUndo(new FmUndoContainerAction(*(FmFormModel*)pModel, + FmUndoContainerAction::Inserted, + xContainer, + xForm, + xContainer->getCount())); + } + xForms->insertByName( sName, makeAny( xForm ) ); + xCurrentForm = xForm; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + xForm.clear(); + } + + if( pModel->IsUndoEnabled() ) + pModel->EndUndo(); + } + + return xForm; +} + +//------------------------------------------------------------------------------ +Reference< ::com::sun::star::form::XForm > FmFormPageImpl::findPlaceInFormComponentHierarchy( + const Reference< XFormComponent > & rContent, const Reference< XDataSource > & rDatabase, + const ::rtl::OUString& rDBTitle, const ::rtl::OUString& rCursorSource, sal_Int32 nCommandType ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmFormPageImpl::findPlaceInFormComponentHierarchy" ); + // if the control already is child of a form, don't do anything + if (!rContent.is() || rContent->getParent().is()) + return NULL; + + Reference< XForm > xForm; + + // Wenn Datenbank und CursorSource gesetzt sind, dann wird + // die Form anhand dieser Kriterien gesucht, ansonsten nur aktuelle + // und die StandardForm + if (rDatabase.is() && rCursorSource.getLength()) + { + validateCurForm(); + + // erst in der aktuellen form suchen + xForm = findFormForDataSource( xCurrentForm, rDatabase, rCursorSource, nCommandType ); + + Reference< ::com::sun::star::container::XIndexAccess > xFormsByIndex( getForms(), UNO_QUERY ); + DBG_ASSERT(xFormsByIndex.is(), "FmFormPageImpl::findPlaceInFormComponentHierarchy : no index access for my forms collection !"); + sal_Int32 nCount = xFormsByIndex->getCount(); + for (sal_Int32 i = 0; !xForm.is() && i < nCount; i++) + { + Reference< ::com::sun::star::form::XForm > xToSearch; + xFormsByIndex->getByIndex(i) >>= xToSearch; + xForm = findFormForDataSource( xToSearch, rDatabase, rCursorSource, nCommandType ); + } + + // wenn keine ::com::sun::star::form gefunden, dann eine neue erzeugen + if (!xForm.is()) + { + SdrModel* pModel = m_rPage.GetModel(); + + const bool bUndo = pModel->IsUndoEnabled(); + + if( bUndo ) + { + XubString aStr(SVX_RES(RID_STR_FORM)); + XubString aUndoStr(SVX_RES(RID_STR_UNDO_CONTAINER_INSERT)); + aUndoStr.SearchAndReplace('#', aStr); + pModel->BegUndo(aUndoStr); + } + + xForm = Reference< ::com::sun::star::form::XForm >(::comphelper::getProcessServiceFactory()->createInstance(FM_SUN_COMPONENT_FORM), UNO_QUERY); + // a form should always have the command type table as default + Reference< ::com::sun::star::beans::XPropertySet > xFormProps(xForm, UNO_QUERY); + try { xFormProps->setPropertyValue(FM_PROP_COMMANDTYPE, makeAny(sal_Int32(CommandType::TABLE))); } + catch(Exception&) { } + + if (rDBTitle.getLength()) + xFormProps->setPropertyValue(FM_PROP_DATASOURCE,makeAny(rDBTitle)); + else + { + Reference< ::com::sun::star::beans::XPropertySet > xDatabaseProps(rDatabase, UNO_QUERY); + Any aDatabaseUrl = xDatabaseProps->getPropertyValue(FM_PROP_URL); + xFormProps->setPropertyValue(FM_PROP_DATASOURCE, aDatabaseUrl); + } + + xFormProps->setPropertyValue(FM_PROP_COMMAND,makeAny(rCursorSource)); + xFormProps->setPropertyValue(FM_PROP_COMMANDTYPE, makeAny(nCommandType)); + + Reference< ::com::sun::star::container::XNameAccess > xNamedSet( getForms(), UNO_QUERY ); + + const bool bTableOrQuery = ( CommandType::TABLE == nCommandType ) || ( CommandType::QUERY == nCommandType ); + ::rtl::OUString sName = FormControlFactory::getUniqueName( xNamedSet, + bTableOrQuery ? rCursorSource : ::rtl::OUString( String( SVX_RES( RID_STR_STDFORMNAME ) ) ) ); + + xFormProps->setPropertyValue( FM_PROP_NAME, makeAny( sName ) ); + + if( bUndo ) + { + Reference< ::com::sun::star::container::XIndexContainer > xContainer( getForms(), UNO_QUERY ); + pModel->AddUndo(new FmUndoContainerAction(*(FmFormModel*)pModel, + FmUndoContainerAction::Inserted, + xContainer, + xForm, + xContainer->getCount())); + } + + getForms()->insertByName( sName, makeAny( xForm ) ); + + if( bUndo ) + pModel->EndUndo(); + } + xCurrentForm = xForm; + } + + xForm = getDefaultForm(); + return xForm; +} + +//------------------------------------------------------------------------------ +Reference< XForm > FmFormPageImpl::findFormForDataSource( + const Reference< XForm > & rForm, const Reference< XDataSource > & _rxDatabase, + const ::rtl::OUString& _rCursorSource, sal_Int32 nCommandType) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmFormPageImpl::findFormForDataSource" ); + Reference< XForm > xResultForm; + Reference< XRowSet > xDBForm(rForm, UNO_QUERY); + Reference< XPropertySet > xFormProps(rForm, UNO_QUERY); + if (!xDBForm.is() || !xFormProps.is()) + return xResultForm; + + OSL_ENSURE(_rxDatabase.is(), "FmFormPageImpl::findFormForDataSource: invalid data source!"); + ::rtl::OUString sLookupName; // the name of the data source we're looking for + ::rtl::OUString sFormDataSourceName; // the name of the data source the current connection in the form is based on + try + { + Reference< XPropertySet > xDSProps(_rxDatabase, UNO_QUERY); + if (xDSProps.is()) + xDSProps->getPropertyValue(FM_PROP_NAME) >>= sLookupName; + + xFormProps->getPropertyValue(FM_PROP_DATASOURCE) >>= sFormDataSourceName; + // if there's no DataSourceName set at the form, check whether we can deduce one from its + // ActiveConnection + if (0 == sFormDataSourceName.getLength()) + { + Reference< XConnection > xFormConnection; + xFormProps->getPropertyValue( FM_PROP_ACTIVE_CONNECTION ) >>= xFormConnection; + if ( !xFormConnection.is() ) + OStaticDataAccessTools().isEmbeddedInDatabase( xFormProps, xFormConnection ); + if (xFormConnection.is()) + { + Reference< XChild > xConnAsChild(xFormConnection, UNO_QUERY); + if (xConnAsChild.is()) + { + Reference< XDataSource > xFormDS(xConnAsChild->getParent(), UNO_QUERY); + if (xFormDS.is()) + { + xDSProps = xDSProps.query(xFormDS); + if (xDSProps.is()) + xDSProps->getPropertyValue(FM_PROP_NAME) >>= sFormDataSourceName; + } + } + } + } + } + catch(const Exception& e) + { + (void)e; + OSL_ENSURE(sal_False, "FmFormPageImpl::findFormForDataSource: caught an exception!"); + } + + if (sLookupName == sFormDataSourceName) + { + // jetzt noch ueberpruefen ob CursorSource und Type uebereinstimmen + ::rtl::OUString aCursorSource = ::comphelper::getString(xFormProps->getPropertyValue(FM_PROP_COMMAND)); + sal_Int32 nType = ::comphelper::getINT32(xFormProps->getPropertyValue(FM_PROP_COMMANDTYPE)); + if (!aCursorSource.getLength() || ((nType == nCommandType) && (aCursorSource == _rCursorSource))) // found the form + { + xResultForm = rForm; + // Ist noch keine Datenquelle gesetzt, wird dieses hier nachgeholt + if (!aCursorSource.getLength()) + { + xFormProps->setPropertyValue(FM_PROP_COMMAND, makeAny(_rCursorSource)); + xFormProps->setPropertyValue(FM_PROP_COMMANDTYPE, makeAny((sal_Int32)nCommandType)); + } + } + } + + // as long as xResultForm is NULL, search the child forms of rForm + Reference< XIndexAccess > xComponents(rForm, UNO_QUERY); + sal_Int32 nCount = xComponents->getCount(); + for (sal_Int32 i = 0; !xResultForm.is() && i < nCount; ++i) + { + Reference< ::com::sun::star::form::XForm > xSearchForm; + xComponents->getByIndex(i) >>= xSearchForm; + // continue searching in the sub form + if (xSearchForm.is()) + xResultForm = findFormForDataSource( xSearchForm, _rxDatabase, _rCursorSource, nCommandType ); + } + return xResultForm; +} + +//------------------------------------------------------------------------------ +::rtl::OUString FmFormPageImpl::setUniqueName(const Reference< XFormComponent > & xFormComponent, const Reference< XForm > & xControls) +{ +#if OSL_DEBUG_LEVEL > 0 + try + { + Reference< XChild > xChild( xFormComponent, UNO_QUERY_THROW ); + OSL_ENSURE( !xChild->getParent().is(), "FmFormPageImpl::setUniqueName: to be called before insertion!" ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +#endif + ::rtl::OUString sName; + Reference< ::com::sun::star::beans::XPropertySet > xSet(xFormComponent, UNO_QUERY); + if (xSet.is()) + { + sName = ::comphelper::getString( xSet->getPropertyValue( FM_PROP_NAME ) ); + Reference< ::com::sun::star::container::XNameAccess > xNameAcc(xControls, UNO_QUERY); + + if (!sName.getLength() || xNameAcc->hasByName(sName)) + { + // setzen eines default Namens ueber die ClassId + sal_Int16 nClassId( FormComponentType::CONTROL ); + xSet->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId; + + ::rtl::OUString sDefaultName = FormControlFactory::getDefaultUniqueName_ByComponentType( + Reference< XNameAccess >( xControls, UNO_QUERY ), xSet ); + + // bei Radiobuttons, die einen Namen haben, diesen nicht ueberschreiben! + if (!sName.getLength() || nClassId != ::com::sun::star::form::FormComponentType::RADIOBUTTON) + { + xSet->setPropertyValue(FM_PROP_NAME, makeAny(sDefaultName)); + } + + sName = sDefaultName; + } + } + return sName; +} + +//------------------------------------------------------------------ +void FmFormPageImpl::formObjectInserted( const FmFormObj& _object ) +{ + Reference< XMap > xControlShapeMap( m_aControlShapeMap.get(), UNO_QUERY ); + if ( !xControlShapeMap.is() ) + // our map does not exist -> not interested in this event + return; + + try + { + lcl_insertFormObject_throw( _object, xControlShapeMap ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +void FmFormPageImpl::formObjectRemoved( const FmFormObj& _object ) +{ + Reference< XMap > xControlShapeMap( m_aControlShapeMap.get(), UNO_QUERY ); + if ( !xControlShapeMap.is() ) + // our map does not exist -> not interested in this event + return; + + try + { + lcl_removeFormObject( _object, xControlShapeMap ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmscriptingenv.cxx b/svx/source/form/fmscriptingenv.cxx new file mode 100644 index 000000000000..d18019790523 --- /dev/null +++ b/svx/source/form/fmscriptingenv.cxx @@ -0,0 +1,579 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include "fmscriptingenv.hxx" +#include <svx/fmmodel.hxx> + +/** === begin UNO includes === **/ +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/script/XScriptListener.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/reflection/XInterfaceMethodTypeDescription.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/lang/EventObject.hpp> +#include <com/sun/star/awt/XControl.hpp> +/** === end UNO includes === **/ +#include <tools/diagnose_ex.h> +#include <cppuhelper/implbase1.hxx> +#include <comphelper/implementationreference.hxx> +#include <comphelper/componentcontext.hxx> +#include <comphelper/processfactory.hxx> +#include <vcl/svapp.hxx> +#include <osl/mutex.hxx> +#include <sfx2/objsh.hxx> + +#include <boost/shared_ptr.hpp> + +//........................................................................ +namespace svxform +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::script::XEventAttacherManager; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::script::XScriptListener; + using ::com::sun::star::script::ScriptEvent; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::lang::EventObject; + using ::com::sun::star::reflection::InvocationTargetException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::container::XHierarchicalNameAccess; + using ::com::sun::star::reflection::XInterfaceMethodTypeDescription; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::lang::DisposedException; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::lang::EventObject; + using ::com::sun::star::awt::XControl; + using ::com::sun::star::beans::XPropertySet; + /** === end UNO using === **/ + + class FormScriptingEnvironment; + + //==================================================================== + //= FormScriptListener + //==================================================================== + typedef ::cppu::WeakImplHelper1 < XScriptListener + > FormScriptListener_Base; + + /** implements the XScriptListener interface, is used by FormScriptingEnvironment + */ + class FormScriptListener :public FormScriptListener_Base + { + private: + ::osl::Mutex m_aMutex; + ::rtl::Reference< FormScriptingEnvironment > m_pScriptExecutor; + + public: + FormScriptListener( const ::rtl::Reference< FormScriptingEnvironment >& _pScriptExecutor ); + + // XScriptListener + virtual void SAL_CALL firing( const ScriptEvent& aEvent ) throw (RuntimeException); + virtual Any SAL_CALL approveFiring( const ScriptEvent& aEvent ) throw (InvocationTargetException, RuntimeException); + // XEventListener + virtual void SAL_CALL disposing( const EventObject& Source ) throw (RuntimeException); + + // lifetime control + void SAL_CALL dispose(); + + protected: + ~FormScriptListener(); + + private: + /** determines whether calling a given method at a given listener interface can be done asynchronously + + @param _rListenerType + the name of the UNO type whose method is to be checked + @param _rMethodName + the name of the method at the interface determined by _rListenerType + + @return + <TRUE/> if and only if the method is declared <code>oneway</code>, i.e. can be called asynchronously + */ + bool impl_allowAsynchronousCall_nothrow( const ::rtl::OUString& _rListenerType, const ::rtl::OUString& _rMethodName ) const; + + /** determines whether the instance is already disposed + */ + bool impl_isDisposed_nothrow() const { return !m_pScriptExecutor.is(); } + + /** fires the given script event in a thread-safe manner + + This methods calls our script executor's doFireScriptEvent, with previously releasing the given mutex guard, + but ensuring that our script executor is not deleted between this release and the actual call. + + @param _rGuard + a clearable guard to our mutex. Must be the only active guard to our mutex. + @param _rEvent + the event to fire + @param _pSyncronousResult + a place to take a possible result of the script call. + + @precond + m_pScriptExecutor is not <NULL/>. + */ + void impl_doFireScriptEvent_nothrow( ::osl::ClearableMutexGuard& _rGuard, const ScriptEvent& _rEvent, Any* _pSyncronousResult ); + + private: + DECL_LINK( OnAsyncScriptEvent, ScriptEvent* ); + }; + + //==================================================================== + //= FormScriptingEnvironment + //==================================================================== + class FormScriptingEnvironment : public IFormScriptingEnvironment + { + private: + typedef ::comphelper::ImplementationReference< FormScriptListener, XScriptListener > ListenerImplementation; + + private: + ::osl::Mutex m_aMutex; + oslInterlockedCount m_refCount; + ListenerImplementation m_pScriptListener; + FmFormModel& m_rFormModel; + bool m_bDisposed; + + public: + FormScriptingEnvironment( FmFormModel& _rModel ); + virtual ~FormScriptingEnvironment(); + + // callback for FormScriptListener + void doFireScriptEvent( const ScriptEvent& _rEvent, Any* _pSyncronousResult ); + + // IFormScriptingEnvironment + virtual void registerEventAttacherManager( const Reference< XEventAttacherManager >& _rxManager ); + virtual void revokeEventAttacherManager( const Reference< XEventAttacherManager >& _rxManager ); + virtual void dispose(); + + // IReference + virtual oslInterlockedCount SAL_CALL acquire(); + virtual oslInterlockedCount SAL_CALL release(); + + private: + void impl_registerOrRevoke_throw( const Reference< XEventAttacherManager >& _rxManager, bool _bRegister ); + + private: + FormScriptingEnvironment(); // never implemented + FormScriptingEnvironment( const FormScriptingEnvironment& ); // never implemented + FormScriptingEnvironment& operator=( const FormScriptingEnvironment& ); // never implemented + }; + + //==================================================================== + //= FormScriptListener + //==================================================================== + //-------------------------------------------------------------------- + FormScriptListener::FormScriptListener( const ::rtl::Reference< FormScriptingEnvironment >& _pScriptExecutor ) + :m_pScriptExecutor( _pScriptExecutor ) + { + } + + //-------------------------------------------------------------------- + FormScriptListener::~FormScriptListener() + { + } + + //-------------------------------------------------------------------- + bool FormScriptListener::impl_allowAsynchronousCall_nothrow( const ::rtl::OUString& _rListenerType, const ::rtl::OUString& _rMethodName ) const + { + bool bAllowAsynchronousCall = false; + try + { + ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() ); + Reference< XHierarchicalNameAccess > xTypeDescriptions( aContext.getSingleton( "com.sun.star.reflection.theTypeDescriptionManager" ), UNO_QUERY_THROW ); + + ::rtl::OUString sMethodDescription( _rListenerType ); + sMethodDescription += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "::" )); + sMethodDescription += _rMethodName; + + Reference< XInterfaceMethodTypeDescription > xMethod( xTypeDescriptions->getByHierarchicalName( sMethodDescription ), UNO_QUERY_THROW ); + bAllowAsynchronousCall = xMethod->isOneway(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return bAllowAsynchronousCall; + } + + //-------------------------------------------------------------------- + void FormScriptListener::impl_doFireScriptEvent_nothrow( ::osl::ClearableMutexGuard& _rGuard, const ScriptEvent& _rEvent, Any* _pSyncronousResult ) + { + OSL_PRECOND( m_pScriptExecutor.is(), "FormScriptListener::impl_doFireScriptEvent_nothrow: this will crash!" ); + + ::rtl::Reference< FormScriptingEnvironment > pExecutor( m_pScriptExecutor ); + _rGuard.clear(); + pExecutor->doFireScriptEvent( _rEvent, _pSyncronousResult ); + } + + //-------------------------------------------------------------------- + void SAL_CALL FormScriptListener::firing( const ScriptEvent& _rEvent ) throw (RuntimeException) + { + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + static const ::rtl::OUString vbaInterOp( RTL_CONSTASCII_USTRINGPARAM("VBAInterop") ); + if ( _rEvent.ScriptType.equals(vbaInterOp) ) + return; // not handled here + + if ( impl_isDisposed_nothrow() ) + return; + + if ( !impl_allowAsynchronousCall_nothrow( _rEvent.ListenerType.getTypeName(), _rEvent.MethodName ) ) + { + impl_doFireScriptEvent_nothrow( aGuard, _rEvent, NULL ); + return; + } + + acquire(); + Application::PostUserEvent( LINK( this, FormScriptListener, OnAsyncScriptEvent ), new ScriptEvent( _rEvent ) ); + } + + //-------------------------------------------------------------------- + Any SAL_CALL FormScriptListener::approveFiring( const ScriptEvent& _rEvent ) throw (InvocationTargetException, RuntimeException) + { + Any aResult; + + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + if ( !impl_isDisposed_nothrow() ) + impl_doFireScriptEvent_nothrow( aGuard, _rEvent, &aResult ); + + return aResult; + } + + //-------------------------------------------------------------------- + void SAL_CALL FormScriptListener::disposing( const EventObject& /*Source*/ ) throw (RuntimeException) + { + // not interested in + } + + //-------------------------------------------------------------------- + void SAL_CALL FormScriptListener::dispose() + { + ::osl::MutexGuard aGuard( m_aMutex ); + m_pScriptExecutor = NULL; + } + + //-------------------------------------------------------------------- + IMPL_LINK( FormScriptListener, OnAsyncScriptEvent, ScriptEvent*, _pEvent ) + { + OSL_PRECOND( _pEvent != NULL, "FormScriptListener::OnAsyncScriptEvent: invalid event!" ); + if ( !_pEvent ) + return 1L; + + { + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + + if ( !impl_isDisposed_nothrow() ) + impl_doFireScriptEvent_nothrow( aGuard, *_pEvent, NULL ); + } + + delete _pEvent; + // we acquired ourself immediately before posting the event + release(); + return 0L; + } + + //==================================================================== + //= FormScriptingEnvironment + //==================================================================== + //-------------------------------------------------------------------- + FormScriptingEnvironment::FormScriptingEnvironment( FmFormModel& _rModel ) + :m_refCount( 0 ) + ,m_pScriptListener( NULL ) + ,m_rFormModel( _rModel ) + ,m_bDisposed( false ) + { + m_pScriptListener = ListenerImplementation( new FormScriptListener( this ) ); + // note that this is a cyclic reference between the FormScriptListener and the FormScriptingEnvironment + // This cycle is broken up when our instance is disposed. + } + + //-------------------------------------------------------------------- + FormScriptingEnvironment::~FormScriptingEnvironment() + { + } + + //-------------------------------------------------------------------- + void FormScriptingEnvironment::impl_registerOrRevoke_throw( const Reference< XEventAttacherManager >& _rxManager, bool _bRegister ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !_rxManager.is() ) + throw IllegalArgumentException(); + if ( m_bDisposed ) + throw DisposedException(); + + try + { + if ( _bRegister ) + _rxManager->addScriptListener( m_pScriptListener.getRef() ); + else + _rxManager->removeScriptListener( m_pScriptListener.getRef() ); + } + catch( const RuntimeException& ) { throw; } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + //-------------------------------------------------------------------- + void FormScriptingEnvironment::registerEventAttacherManager( const Reference< XEventAttacherManager >& _rxManager ) + { + impl_registerOrRevoke_throw( _rxManager, true ); + } + + //-------------------------------------------------------------------- + void FormScriptingEnvironment::revokeEventAttacherManager( const Reference< XEventAttacherManager >& _rxManager ) + { + impl_registerOrRevoke_throw( _rxManager, false ); + } + + //-------------------------------------------------------------------- + oslInterlockedCount SAL_CALL FormScriptingEnvironment::acquire() + { + return osl_incrementInterlockedCount( &m_refCount ); + } + + //-------------------------------------------------------------------- + oslInterlockedCount SAL_CALL FormScriptingEnvironment::release() + { + if ( 0 == osl_decrementInterlockedCount( &m_refCount ) ) + { + delete this; + return 0; + } + return m_refCount; + } + + //-------------------------------------------------------------------- + IFormScriptingEnvironment::~IFormScriptingEnvironment() + { + } + + //-------------------------------------------------------------------- + namespace + { + //................................................................ + //. NewStyleUNOScript + //................................................................ + class SAL_NO_VTABLE IScript + { + public: + virtual void invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult ) = 0; + + virtual ~IScript() { } + }; + typedef ::boost::shared_ptr< IScript > PScript; + + //................................................................ + //. NewStyleUNOScript + //................................................................ + class NewStyleUNOScript : public IScript + { + SfxObjectShell& m_rObjectShell; + const ::rtl::OUString m_sScriptCode; + + public: + NewStyleUNOScript( SfxObjectShell& _rObjectShell, const ::rtl::OUString& _rScriptCode ) + :m_rObjectShell( _rObjectShell ) + ,m_sScriptCode( _rScriptCode ) + { + } + + // IScript + virtual void invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult ); + }; + + //................................................................ + void NewStyleUNOScript::invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult ) + { + Sequence< sal_Int16 > aOutArgsIndex; + Sequence< Any > aOutArgs; + EventObject aEvent; + Any aCaller; + if ( ( _rArguments.getLength() > 0 ) && ( _rArguments[ 0 ] >>= aEvent ) ) + { + try + { + Reference< XControl > xControl( aEvent.Source, UNO_QUERY_THROW ); + Reference< XPropertySet > xProps( xControl->getModel(), UNO_QUERY_THROW ); + aCaller = xProps->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Name") ) ); + } + catch( Exception& ) {} + } + m_rObjectShell.CallXScript( m_sScriptCode, _rArguments, _rSynchronousResult, aOutArgsIndex, aOutArgs, true, aCaller.hasValue() ? &aCaller : 0 ); + } + + //................................................................ + //. QualifiedBasicScript + //................................................................ + class QualifiedBasicScript : public IScript + { + SfxObjectShell& m_rObjectShell; + const ::rtl::OUString m_sMacroLocation; + const ::rtl::OUString m_sScriptCode; + + public: + QualifiedBasicScript( SfxObjectShell& _rObjectShell, const ::rtl::OUString& _rLocation, const ::rtl::OUString& _rScriptCode ) + :m_rObjectShell( _rObjectShell ) + ,m_sMacroLocation( _rLocation ) + ,m_sScriptCode( _rScriptCode ) + { + } + + // IScript + virtual void invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult ); + }; + + //................................................................ + void QualifiedBasicScript::invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult ) + { + m_rObjectShell.CallStarBasicScript( m_sScriptCode, m_sMacroLocation, + &_rArguments, &_rSynchronousResult ); + } + + //................................................................ + //. UnqualifiedBasicScript + //................................................................ + class UnqualifiedBasicScript : public IScript + { + SfxObjectShell& m_rObjectShell; + const ::rtl::OUString m_sScriptCode; + + public: + UnqualifiedBasicScript( SfxObjectShell& _rObjectShell, const ::rtl::OUString& _rScriptCode ) + :m_rObjectShell( _rObjectShell ) + ,m_sScriptCode( _rScriptCode ) + { + } + + // IScript + virtual void invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult ); + }; + + //................................................................ + void UnqualifiedBasicScript::invoke( const Sequence< Any >& _rArguments, Any& _rSynchronousResult ) + { + m_rObjectShell.CallScript( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StarBasic" ) ), m_sScriptCode, + &_rArguments, &_rSynchronousResult ); + } + } + + //-------------------------------------------------------------------- + void FormScriptingEnvironment::doFireScriptEvent( const ScriptEvent& _rEvent, Any* _pSyncronousResult ) + { + SolarMutexClearableGuard aSolarGuard; + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + + if ( m_bDisposed ) + return; + + SfxObjectShellRef xObjectShell = m_rFormModel.GetObjectShell(); + if( !xObjectShell.Is() ) + return; + + // the script to execute + PScript pScript; + + if ( !_rEvent.ScriptType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "StarBasic" ) ) ) + { + pScript.reset( new NewStyleUNOScript( *xObjectShell, _rEvent.ScriptCode ) ); + } + else + { + ::rtl::OUString sScriptCode = _rEvent.ScriptCode; + ::rtl::OUString sMacroLocation; + + // is there a location in the script name ("application" or "document")? + sal_Int32 nPrefixLen = sScriptCode.indexOf( ':' ); + DBG_ASSERT( 0 <= nPrefixLen, "FormScriptingEnvironment::doFireScriptEvent: Basic script name in old format encountered!" ); + + if ( 0 <= nPrefixLen ) + { + // and it has such a prefix + sMacroLocation = sScriptCode.copy( 0, nPrefixLen ); + DBG_ASSERT( 0 == sMacroLocation.compareToAscii( "document" ) + || 0 == sMacroLocation.compareToAscii( "application" ), + "FormScriptingEnvironment::doFireScriptEvent: invalid (unknown) prefix!" ); + + // strip the prefix: the SfxObjectShell::CallScript knows nothing about such prefixes + sScriptCode = sScriptCode.copy( nPrefixLen + 1 ); + } + + if ( sMacroLocation.getLength() ) + { // we have a StarBasic macro with fully-qualified macro location + pScript.reset( new QualifiedBasicScript( *xObjectShell, sMacroLocation, sScriptCode ) ); + } + else + { // we have a StarBasic macro without qualified location - let the object shell gues .... + pScript.reset( new UnqualifiedBasicScript( *xObjectShell, sScriptCode ) ); + } + } + + OSL_ENSURE( pScript.get(), "FormScriptingEnvironment::doFireScriptEvent: no script to execute!" ); + if ( !pScript.get() ) + // this is an internal error in the above code + throw RuntimeException(); + + aGuard.clear(); + aSolarGuard.clear(); + + Any aIgnoreResult; + pScript->invoke( _rEvent.Arguments, _pSyncronousResult ? *_pSyncronousResult : aIgnoreResult ); + pScript.reset(); + + { + // object shells are not thread safe, so guard the destruction + SolarMutexGuard aSolarGuarsReset; + xObjectShell = NULL; + } + } + + //-------------------------------------------------------------------- + void FormScriptingEnvironment::dispose() + { + ::osl::MutexGuard aGuard( m_aMutex ); + m_bDisposed = true; + m_pScriptListener->dispose(); + } + + //-------------------------------------------------------------------- + PFormScriptingEnvironment createDefaultFormScriptingEnvironment( FmFormModel& _rModel ) + { + return new FormScriptingEnvironment( _rModel ); + } + +//........................................................................ +} // namespace svxform +//........................................................................ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmservs.cxx b/svx/source/form/fmservs.cxx new file mode 100644 index 000000000000..45ceb61db6c1 --- /dev/null +++ b/svx/source/form/fmservs.cxx @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include <com/sun/star/container/XSet.hpp> +#include <cppuhelper/factory.hxx> +#include <comphelper/processfactory.hxx> +#include "fmservs.hxx" + +// ------------------------------------------------------------------------ +#define DECL_SERVICE(ImplName) \ +::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL ImplName##_NewInstance_Impl(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > &) throw( ::com::sun::star::uno::Exception ); + +#define REGISTER_SERVICE(ImplName, ServiceName) \ + sString = (ServiceName); \ + xSingleFactory = ::cppu::createSingleFactory(xServiceFactory, \ + ::rtl::OUString(), ImplName##_NewInstance_Impl, \ + ::com::sun::star::uno::Sequence< ::rtl::OUString>(&sString, 1)); \ + if (xSingleFactory.is()) \ + xSet->insert(::com::sun::star::uno::makeAny(xSingleFactory)); + + + DECL_SERVICE( FmXGridControl ) + DECL_SERVICE( FormController ) + DECL_SERVICE( LegacyFormController ) + + +// ------------------------------------------------------------------------ +namespace svxform +{ + +#define DECL_SELFAWARE_SERVICE( ClassName ) \ + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL ClassName##_Create( \ + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& ); \ + ::rtl::OUString SAL_CALL ClassName##_GetImplementationName(); \ + ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL ClassName##_GetSupportedServiceNames(); \ + + +#define REGISTER_SELFAWARE_SERVICE( ClassName ) \ + xSingleFactory = ::cppu::createSingleFactory( xServiceFactory, \ + ClassName##_GetImplementationName(), \ + ClassName##_Create, \ + ClassName##_GetSupportedServiceNames() \ + ); \ + if ( xSingleFactory.is() ) \ + xSet->insert( ::com::sun::star::uno::makeAny( xSingleFactory ) ); + + + // ------------------------------------------------------------------------ + DECL_SELFAWARE_SERVICE( OAddConditionDialog ) + + // ------------------------------------------------------------------------ + void ImplSmartRegisterUnoServices() + { + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory(::comphelper::getProcessServiceFactory(), ::com::sun::star::uno::UNO_QUERY); + ::com::sun::star::uno::Reference< ::com::sun::star::container::XSet > xSet(xServiceFactory, ::com::sun::star::uno::UNO_QUERY); + if (!xSet.is()) + return; + + ::com::sun::star::uno::Sequence< ::rtl::OUString> aServices; + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XSingleServiceFactory > xSingleFactory; + + ::rtl::OUString sString; + + // ------------------------------------------------------------------------ + // FormController + REGISTER_SERVICE( FormController, FM_FORM_CONTROLLER ); + REGISTER_SERVICE( LegacyFormController, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.form.FormController" ) ) ); + + // ------------------------------------------------------------------------ + // FormController + REGISTER_SELFAWARE_SERVICE( OAddConditionDialog ); + + // ------------------------------------------------------------------------ + // DBGridControl + REGISTER_SERVICE(FmXGridControl, FM_CONTROL_GRID); // compatibility + REGISTER_SERVICE(FmXGridControl, FM_CONTROL_GRIDCONTROL); + REGISTER_SERVICE(FmXGridControl, FM_SUN_CONTROL_GRIDCONTROL); + }; + +} // namespace svxform + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmshell.cxx b/svx/source/form/fmshell.cxx new file mode 100644 index 000000000000..827a2f3bcfcf --- /dev/null +++ b/svx/source/form/fmshell.cxx @@ -0,0 +1,1513 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include "fmvwimp.hxx" +#include <svx/fmshell.hxx> +#include "svx/fmtools.hxx" +#include "fmservs.hxx" +#include "fmprop.hrc" +#include "fmpgeimp.hxx" +#include "fmitems.hxx" +#include "fmundo.hxx" +#include <vcl/waitobj.hxx> +#include <com/sun/star/form/XLoadable.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/beans/XFastPropertySet.hpp> +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/awt/XTabControllerModel.hpp> +#include <sfx2/viewfrm.hxx> +#include <vcl/wrkwin.hxx> +#include <vcl/msgbox.hxx> +#include <svl/whiter.hxx> +#include <sfx2/app.hxx> +#include <svl/intitem.hxx> +#include <svl/visitem.hxx> +#include <unotools/moduleoptions.hxx> +#include <sfx2/objface.hxx> +#include <sfx2/request.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/objsh.hxx> +#include <svx/svdobj.hxx> +#include <svx/fmpage.hxx> +#include "svditer.hxx" +#include "fmobj.hxx" + +#include <svx/svxids.hrc> + +#include "fmresids.hrc" +#include "fmexch.hxx" +#include <svx/fmglob.hxx> +#include <svl/eitem.hxx> +#include <tools/shl.hxx> +#include <tools/diagnose_ex.h> +#include <svx/svdpage.hxx> +#include <svx/fmmodel.hxx> +#include <svx/dialmgr.hxx> +#include "fmshimp.hxx" +#include <svx/svdpagv.hxx> +#include <sfx2/objitem.hxx> +#include <sfx2/viewsh.hxx> +#include <vcl/sound.hxx> +#include "fmexpl.hxx" +#include "formcontrolling.hxx" +#include <svl/numuno.hxx> +#include <connectivity/dbtools.hxx> +#include <comphelper/types.hxx> +#include <comphelper/processfactory.hxx> +#include "fmdocumentclassification.hxx" +#include "formtoolbars.hxx" + +#include <svx/svxdlg.hxx> +#include <svx/dialogs.hrc> + +#include "svx/sdrobjectfilter.hxx" + +#define HANDLE_SQL_ERRORS( action, successflag, context, message ) \ + try \ + { \ + successflag = sal_False; \ + action; \ + successflag = sal_True; \ + } \ + catch(::com::sun::star::sdbc::SQLException& e) \ + { \ + ::com::sun::star::sdb::SQLContext eExtendedInfo = \ + GetImpl()->prependContextInfo(e, Reference< XInterface > (), context, ::rtl::OUString()); \ + displayException(eExtendedInfo); \ + } \ + catch(Exception&) \ + { \ + DBG_ERROR(message); \ + } \ + + +#define DO_SAFE_WITH_ERROR( action, message ) try { action; } catch(Exception&) { DBG_ERROR(message); } + +#define FmFormShell +#include "svxslots.hxx" + +#include <svx/svxids.hrc> +#include "tbxform.hxx" +#include <comphelper/property.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> + +// wird fuer Invalidate verwendet -> mitpflegen +// aufsteigend sortieren !!!!!! +sal_uInt16 ControllerSlotMap[] = // slots des Controllers +{ + SID_FM_CONFIG, + SID_FM_PUSHBUTTON, + SID_FM_RADIOBUTTON, + SID_FM_CHECKBOX, + SID_FM_FIXEDTEXT, + SID_FM_GROUPBOX, + SID_FM_EDIT, + SID_FM_LISTBOX, + SID_FM_COMBOBOX, + SID_FM_DBGRID, + SID_FM_IMAGEBUTTON, + SID_FM_FILECONTROL, + SID_FM_NAVIGATIONBAR, + SID_FM_CTL_PROPERTIES, + SID_FM_PROPERTIES, + SID_FM_TAB_DIALOG, + SID_FM_ADD_FIELD, + SID_FM_DESIGN_MODE, + SID_FM_SHOW_FMEXPLORER, + SID_FM_SHOW_PROPERTIES, + SID_FM_FMEXPLORER_CONTROL, + SID_FM_DATEFIELD, + SID_FM_TIMEFIELD, + SID_FM_NUMERICFIELD, + SID_FM_CURRENCYFIELD, + SID_FM_PATTERNFIELD, + SID_FM_OPEN_READONLY, + SID_FM_IMAGECONTROL, + SID_FM_USE_WIZARDS, + SID_FM_FORMATTEDFIELD, + SID_FM_FILTER_NAVIGATOR, + SID_FM_AUTOCONTROLFOCUS, + SID_FM_SCROLLBAR, + SID_FM_SPINBUTTON, + SID_FM_SHOW_DATANAVIGATOR, + SID_FM_DATANAVIGATOR_CONTROL, + + 0 +}; + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::form::runtime; +using namespace ::com::sun::star::frame; +using namespace ::svxform; + +//======================================================================== +// class FmDesignModeChangedHint +//======================================================================== +TYPEINIT1( FmDesignModeChangedHint, SfxHint ); + +//------------------------------------------------------------------------ +FmDesignModeChangedHint::FmDesignModeChangedHint( sal_Bool bDesMode ) + :m_bDesignMode( bDesMode ) +{ +} + +//------------------------------------------------------------------------ +FmDesignModeChangedHint::~FmDesignModeChangedHint() +{ +} + +//======================================================================== +const sal_uInt32 FM_UI_FEATURE_SHOW_DATABASEBAR = 0x00000001; +const sal_uInt32 FM_UI_FEATURE_SHOW_FIELD = 0x00000002; +const sal_uInt32 FM_UI_FEATURE_SHOW_PROPERTIES = 0x00000004; +const sal_uInt32 FM_UI_FEATURE_SHOW_EXPLORER = 0x00000008; +const sal_uInt32 FM_UI_FEATURE_SHOW_FILTERBAR = 0x00000010; +const sal_uInt32 FM_UI_FEATURE_SHOW_FILTERNAVIGATOR = 0x00000020; +const sal_uInt32 FM_UI_FEATURE_SHOW_TEXT_CONTROL_BAR = 0x00000040; +const sal_uInt32 FM_UI_FEATURE_TB_CONTROLS = 0x00000080; +const sal_uInt32 FM_UI_FEATURE_TB_MORECONTROLS = 0x00000100; +const sal_uInt32 FM_UI_FEATURE_TB_FORMDESIGN = 0x00000200; +const sal_uInt32 FM_UI_FEATURE_SHOW_DATANAVIGATOR = 0x00000400; + +SFX_IMPL_INTERFACE(FmFormShell, SfxShell, SVX_RES(RID_STR_FORMSHELL)) +{ + SFX_FEATURED_OBJECTBAR_REGISTRATION( SFX_OBJECTBAR_NAVIGATION|SFX_VISIBILITY_STANDARD|SFX_VISIBILITY_READONLYDOC, + SVX_RES(RID_SVXTBX_FORM_NAVIGATION), + FM_UI_FEATURE_SHOW_DATABASEBAR ); + + SFX_FEATURED_OBJECTBAR_REGISTRATION( SFX_OBJECTBAR_NAVIGATION|SFX_VISIBILITY_STANDARD|SFX_VISIBILITY_READONLYDOC, + SVX_RES(RID_SVXTBX_FORM_FILTER), + FM_UI_FEATURE_SHOW_FILTERBAR ); + + SFX_FEATURED_OBJECTBAR_REGISTRATION( SFX_OBJECTBAR_OBJECT | SFX_VISIBILITY_STANDARD | SFX_VISIBILITY_READONLYDOC, + SVX_RES( RID_SVXTBX_TEXT_CONTROL_ATTRIBUTES ), + FM_UI_FEATURE_SHOW_TEXT_CONTROL_BAR ); + + SFX_FEATURED_CHILDWINDOW_REGISTRATION(SID_FM_ADD_FIELD, FM_UI_FEATURE_SHOW_FIELD); + SFX_FEATURED_CHILDWINDOW_REGISTRATION(SID_FM_SHOW_PROPERTIES, FM_UI_FEATURE_SHOW_PROPERTIES); + SFX_FEATURED_CHILDWINDOW_REGISTRATION(SID_FM_SHOW_FMEXPLORER, FM_UI_FEATURE_SHOW_EXPLORER); + SFX_FEATURED_CHILDWINDOW_REGISTRATION(SID_FM_FILTER_NAVIGATOR, FM_UI_FEATURE_SHOW_FILTERNAVIGATOR); + SFX_FEATURED_CHILDWINDOW_REGISTRATION(SID_FM_SHOW_DATANAVIGATOR, FM_UI_FEATURE_SHOW_DATANAVIGATOR); + + SFX_FEATURED_OBJECTBAR_REGISTRATION( SFX_OBJECTBAR_OBJECT | SFX_VISIBILITY_STANDARD, + SVX_RES( RID_SVXTBX_CONTROLS ), + FM_UI_FEATURE_TB_CONTROLS ); + + SFX_FEATURED_OBJECTBAR_REGISTRATION( SFX_OBJECTBAR_OBJECT | SFX_VISIBILITY_STANDARD, + SVX_RES( RID_SVXTBX_MORECONTROLS ), + FM_UI_FEATURE_TB_MORECONTROLS ); + + SFX_FEATURED_OBJECTBAR_REGISTRATION( SFX_OBJECTBAR_OBJECT | SFX_VISIBILITY_STANDARD, + SVX_RES( RID_SVXTBX_FORMDESIGN ), + FM_UI_FEATURE_TB_FORMDESIGN ); +} + +//======================================================================== +TYPEINIT1(FmFormShell,SfxShell) + +//------------------------------------------------------------------------ +FmFormShell::FmFormShell( SfxViewShell* _pParent, FmFormView* pView ) + :SfxShell(_pParent) + ,m_pImpl(new FmXFormShell(*this, _pParent->GetViewFrame())) + ,m_pFormView( pView ) + ,m_pFormModel( NULL ) + ,m_pParentShell(_pParent) + ,m_nLastSlot( 0 ) + ,m_bDesignMode( sal_True ) + ,m_bHasForms(sal_False) +{ + m_pImpl->acquire(); + SetPool( &SFX_APP()->GetPool() ); + SetName( String::CreateFromAscii( "Form" ) ); + + SetView(m_pFormView); +} + +//------------------------------------------------------------------------ +FmFormShell::~FmFormShell() +{ + if ( m_pFormView ) + SetView( NULL ); + + m_pImpl->dispose(); + m_pImpl->release(); + m_pImpl = NULL; +} + +//------------------------------------------------------------------------ +void FmFormShell::NotifyMarkListChanged(FmFormView* pWhichView) +{ + FmNavViewMarksChanged aChangeNotification(pWhichView); + Broadcast(aChangeNotification); +} + +//------------------------------------------------------------------------ +sal_uInt16 FmFormShell::PrepareClose(sal_Bool bUI, sal_Bool bForBrowsing) +{ + if ( GetImpl()->didPrepareClose() ) + // we already did a PrepareClose for the current modifications of the current form + // 2002-11-12 #104702# - fs@openoffice.org + return sal_True; + + sal_Bool bResult = sal_True; + // Save the data records, not in DesignMode and FilterMode + if (!m_bDesignMode && !GetImpl()->isInFilterMode() && + m_pFormView && m_pFormView->GetActualOutDev() && + m_pFormView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW) + { + SdrPageView* pCurPageView = m_pFormView->GetSdrPageView(); + + // sal_uInt16 nPos = pCurPageView ? pCurPageView->GetWinList().Find((OutputDevice*)m_pFormView->GetActualOutDev()) : SDRPAGEVIEWWIN_NOTFOUND; + SdrPageWindow* pWindow = pCurPageView ? pCurPageView->FindPageWindow(*((OutputDevice*)m_pFormView->GetActualOutDev())) : 0L; + + if(pWindow) + { + // Zunaechst werden die aktuellen Inhalte der Controls gespeichert + // Wenn alles glatt gelaufen ist, werden die modifizierten Datensaetze gespeichert + if ( GetImpl()->getActiveController().is() ) + { + const ::svx::ControllerFeatures& rController = GetImpl()->getActiveControllerFeatures(); + if ( rController->commitCurrentControl() ) + { + sal_Bool bModified = rController->isModifiedRow(); + + if ( bModified && bUI ) + { + QueryBox aQry(NULL, SVX_RES(RID_QRY_SAVEMODIFIED)); + if (bForBrowsing) + aQry.AddButton(SVX_RES(RID_STR_NEW_TASK), RET_NEWTASK, + BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON); + + switch (aQry.Execute()) + { + case RET_NO: + bModified = sal_False; + GetImpl()->didPrepareClose( sal_True ); + break; + + case RET_CANCEL: + return sal_False; + + case RET_NEWTASK: + return RET_NEWTASK; + } + + if ( bModified ) + bResult = rController->commitCurrentRecord( ); + } + } + } + } + } + return bResult; +} + +//------------------------------------------------------------------------ +void FmFormShell::impl_setDesignMode(sal_Bool bDesign) +{ + if (m_pFormView) + { + if (!bDesign) + m_nLastSlot = SID_FM_DESIGN_MODE; + + GetImpl()->SetDesignMode(bDesign); + // mein m_bDesignMode wird auch von der Impl gesetzt ... + } + else + { + m_bHasForms = sal_False; + m_bDesignMode = bDesign; + UIFeatureChanged(); + } + + GetViewShell()->GetViewFrame()->GetBindings().Invalidate(ControllerSlotMap); +} + +//------------------------------------------------------------------------ +sal_Bool FmFormShell::HasUIFeature( sal_uInt32 nFeature ) +{ + sal_Bool bResult = sal_False; + if ((nFeature & FM_UI_FEATURE_SHOW_DATABASEBAR) == FM_UI_FEATURE_SHOW_DATABASEBAR) + { + // nur wenn auch formulare verfuegbar + bResult = !m_bDesignMode && GetImpl()->hasDatabaseBar() && !GetImpl()->isInFilterMode(); + } + else if ((nFeature & FM_UI_FEATURE_SHOW_FILTERBAR) == FM_UI_FEATURE_SHOW_FILTERBAR) + { + // nur wenn auch formulare verfuegbar + bResult = !m_bDesignMode && GetImpl()->hasDatabaseBar() && GetImpl()->isInFilterMode(); + } + else if ((nFeature & FM_UI_FEATURE_SHOW_FILTERNAVIGATOR) == FM_UI_FEATURE_SHOW_FILTERNAVIGATOR) + { + bResult = !m_bDesignMode && GetImpl()->hasDatabaseBar() && GetImpl()->isInFilterMode(); + } + else if ((nFeature & FM_UI_FEATURE_SHOW_FIELD) == FM_UI_FEATURE_SHOW_FIELD) + { + bResult = m_bDesignMode && m_pFormView && m_bHasForms; + } + else if ((nFeature & FM_UI_FEATURE_SHOW_PROPERTIES) == FM_UI_FEATURE_SHOW_PROPERTIES) + { + bResult = m_bDesignMode && m_pFormView && m_bHasForms; + } + else if ((nFeature & FM_UI_FEATURE_SHOW_EXPLORER) == FM_UI_FEATURE_SHOW_EXPLORER) + { + bResult = m_bDesignMode; // OJ #101593# && m_pFormView && m_bHasForms; + } + else if ( ( nFeature & FM_UI_FEATURE_SHOW_TEXT_CONTROL_BAR ) == FM_UI_FEATURE_SHOW_TEXT_CONTROL_BAR ) + { + bResult = !GetImpl()->IsReadonlyDoc() && m_pImpl->IsActiveControl( true ); + } + else if ((nFeature & FM_UI_FEATURE_SHOW_DATANAVIGATOR) == FM_UI_FEATURE_SHOW_DATANAVIGATOR) + { + bResult = GetImpl()->isEnhancedForm(); + } + else if ( ( ( nFeature & FM_UI_FEATURE_TB_CONTROLS ) == FM_UI_FEATURE_TB_CONTROLS ) + || ( ( nFeature & FM_UI_FEATURE_TB_MORECONTROLS ) == FM_UI_FEATURE_TB_MORECONTROLS ) + || ( ( nFeature & FM_UI_FEATURE_TB_FORMDESIGN ) == FM_UI_FEATURE_TB_FORMDESIGN ) + ) + { + bResult = sal_True; + } + + return bResult; +} + +//------------------------------------------------------------------------ +void FmFormShell::Execute(SfxRequest &rReq) +{ + sal_uInt16 nSlot = rReq.GetSlot(); + + ////////////////////////////////////////////////////////////////////// + // MasterSlot setzen + switch( nSlot ) + { + case SID_FM_PUSHBUTTON: + case SID_FM_RADIOBUTTON: + case SID_FM_CHECKBOX: + case SID_FM_FIXEDTEXT: + case SID_FM_GROUPBOX: + case SID_FM_LISTBOX: + case SID_FM_COMBOBOX: + case SID_FM_NAVIGATIONBAR: + case SID_FM_EDIT: + case SID_FM_DBGRID: + case SID_FM_IMAGEBUTTON: + case SID_FM_IMAGECONTROL: + case SID_FM_FILECONTROL: + case SID_FM_DATEFIELD: + case SID_FM_TIMEFIELD: + case SID_FM_NUMERICFIELD: + case SID_FM_CURRENCYFIELD: + case SID_FM_PATTERNFIELD: + case SID_FM_FORMATTEDFIELD: + case SID_FM_SCROLLBAR: + case SID_FM_SPINBUTTON: + m_nLastSlot = nSlot; + GetViewShell()->GetViewFrame()->GetBindings().Invalidate( SID_FM_CONFIG ); + break; + } + + ////////////////////////////////////////////////////////////////////// + // Identifier und Inventor des Uno-Controls setzen + sal_uInt16 nIdentifier = 0; + switch( nSlot ) + { + case SID_FM_CHECKBOX: + nIdentifier = OBJ_FM_CHECKBOX; + break; + case SID_FM_PUSHBUTTON: + nIdentifier = OBJ_FM_BUTTON; + break; + case SID_FM_FIXEDTEXT: + nIdentifier = OBJ_FM_FIXEDTEXT; + break; + case SID_FM_LISTBOX: + nIdentifier = OBJ_FM_LISTBOX; + break; + case SID_FM_EDIT: + nIdentifier = OBJ_FM_EDIT; + break; + case SID_FM_RADIOBUTTON: + nIdentifier = OBJ_FM_RADIOBUTTON; + break; + case SID_FM_GROUPBOX: + nIdentifier = OBJ_FM_GROUPBOX; + break; + case SID_FM_COMBOBOX: + nIdentifier = OBJ_FM_COMBOBOX; + break; + case SID_FM_NAVIGATIONBAR: + nIdentifier = OBJ_FM_NAVIGATIONBAR; + break; + case SID_FM_DBGRID: + nIdentifier = OBJ_FM_GRID; + break; + case SID_FM_IMAGEBUTTON: + nIdentifier = OBJ_FM_IMAGEBUTTON; + break; + case SID_FM_IMAGECONTROL: + nIdentifier = OBJ_FM_IMAGECONTROL; + break; + case SID_FM_FILECONTROL: + nIdentifier = OBJ_FM_FILECONTROL; + break; + case SID_FM_DATEFIELD: + nIdentifier = OBJ_FM_DATEFIELD; + break; + case SID_FM_TIMEFIELD: + nIdentifier = OBJ_FM_TIMEFIELD; + break; + case SID_FM_NUMERICFIELD: + nIdentifier = OBJ_FM_NUMERICFIELD; + break; + case SID_FM_CURRENCYFIELD: + nIdentifier = OBJ_FM_CURRENCYFIELD; + break; + case SID_FM_PATTERNFIELD: + nIdentifier = OBJ_FM_PATTERNFIELD; + break; + case SID_FM_FORMATTEDFIELD: + nIdentifier = OBJ_FM_FORMATTEDFIELD; + break; + case SID_FM_SCROLLBAR: + nIdentifier = OBJ_FM_SCROLLBAR; + break; + case SID_FM_SPINBUTTON: + nIdentifier = OBJ_FM_SPINBUTTON; + break; + } + + switch ( nSlot ) + { + case SID_FM_CHECKBOX: + case SID_FM_PUSHBUTTON: + case SID_FM_FIXEDTEXT: + case SID_FM_LISTBOX: + case SID_FM_EDIT: + case SID_FM_RADIOBUTTON: + case SID_FM_COMBOBOX: + case SID_FM_NAVIGATIONBAR: + case SID_FM_GROUPBOX: + case SID_FM_DBGRID: + case SID_FM_IMAGEBUTTON: + case SID_FM_IMAGECONTROL: + case SID_FM_FILECONTROL: + case SID_FM_DATEFIELD: + case SID_FM_TIMEFIELD: + case SID_FM_NUMERICFIELD: + case SID_FM_CURRENCYFIELD: + case SID_FM_PATTERNFIELD: + case SID_FM_FORMATTEDFIELD: + case SID_FM_SCROLLBAR: + case SID_FM_SPINBUTTON: + { + SFX_REQUEST_ARG( rReq, pGrabFocusItem, SfxBoolItem, SID_FM_TOGGLECONTROLFOCUS, sal_False ); + if ( pGrabFocusItem && pGrabFocusItem->GetValue() ) + { // see below + SfxViewShell* pShell = GetViewShell(); + Window* pShellWnd = pShell ? pShell->GetWindow() : NULL; + if ( pShellWnd ) + pShellWnd->GrabFocus(); + break; + } + + SfxUInt16Item aIdentifierItem( SID_FM_CONTROL_IDENTIFIER, nIdentifier ); + SfxUInt32Item aInventorItem( SID_FM_CONTROL_INVENTOR, FmFormInventor ); + const SfxPoolItem* pArgs[] = + { + &aIdentifierItem, &aInventorItem, NULL + }; + const SfxPoolItem* pInternalArgs[] = + { + NULL + }; + + GetViewShell()->GetViewFrame()->GetDispatcher()->Execute( SID_FM_CREATE_CONTROL, SFX_CALLMODE_ASYNCHRON, + pArgs, rReq.GetModifier(), pInternalArgs ); + + if ( rReq.GetModifier() & KEY_MOD1 ) + { + // #99013# if selected with control key, return focus to current view + // do this asynchron, so that the creation can be finished first + // reusing the SID_FM_TOGGLECONTROLFOCUS is somewhat hacky ... which it wouldn't if it would have another + // name, so I do not really have a big problem with this .... + SfxBoolItem aGrabFocusIndicatorItem( SID_FM_TOGGLECONTROLFOCUS, sal_True ); + GetViewShell()->GetViewFrame()->GetDispatcher()->Execute( nSlot, SFX_CALLMODE_ASYNCHRON, + &aGrabFocusIndicatorItem, NULL ); + } + + rReq.Done(); + } break; + } + + // Individuelle Aktionen + switch( nSlot ) + { + case SID_FM_MORE_CONTROLS: + case SID_FM_FORM_DESIGN_TOOLS: + { + FormToolboxes aToolboxAccess( GetImpl()->getHostFrame() ); + aToolboxAccess.toggleToolbox( nSlot ); + rReq.Done(); + } + break; + + case SID_FM_TOGGLECONTROLFOCUS: + { + FmFormView* pFormView = GetFormView(); + if ( !pFormView ) + break; + + // if we execute this ourself, then either the application does not implement an own handling for this, + // of we're on the top of the dispatcher stack, which means a control has the focus. + // In the latter case, we put the focus to the document window, otherwise, we focus the first control + const bool bHasControlFocus = GetImpl()->HasControlFocus(); + if ( bHasControlFocus ) + { + const OutputDevice* pDevice = GetCurrentViewDevice(); + Window* pWindow = dynamic_cast< Window* >( const_cast< OutputDevice* >( pDevice ) ); + if ( pWindow ) + pWindow->GrabFocus(); + } + else + { + pFormView->GrabFirstControlFocus( ); + } + } + break; + + case SID_FM_VIEW_AS_GRID: + GetImpl()->CreateExternalView(); + break; + case SID_FM_CONVERTTO_EDIT : + case SID_FM_CONVERTTO_BUTTON : + case SID_FM_CONVERTTO_FIXEDTEXT : + case SID_FM_CONVERTTO_LISTBOX : + case SID_FM_CONVERTTO_CHECKBOX : + case SID_FM_CONVERTTO_RADIOBUTTON : + case SID_FM_CONVERTTO_GROUPBOX : + case SID_FM_CONVERTTO_COMBOBOX : + case SID_FM_CONVERTTO_IMAGEBUTTON : + case SID_FM_CONVERTTO_FILECONTROL : + case SID_FM_CONVERTTO_DATE : + case SID_FM_CONVERTTO_TIME : + case SID_FM_CONVERTTO_NUMERIC : + case SID_FM_CONVERTTO_CURRENCY : + case SID_FM_CONVERTTO_PATTERN : + case SID_FM_CONVERTTO_IMAGECONTROL : + case SID_FM_CONVERTTO_FORMATTED : + case SID_FM_CONVERTTO_SCROLLBAR : + case SID_FM_CONVERTTO_SPINBUTTON : + case SID_FM_CONVERTTO_NAVIGATIONBAR : + GetImpl()->executeControlConversionSlot( nSlot ); + // nach dem Konvertieren die Selektion neu bestimmern, da sich ja das selektierte Objekt + // geaendert hat + GetImpl()->SetSelection(GetFormView()->GetMarkedObjectList()); + break; + case SID_FM_LEAVE_CREATE: + m_nLastSlot = 0; + GetViewShell()->GetViewFrame()->GetBindings().Invalidate( SID_FM_CONFIG ); + rReq.Done(); + break; + case SID_FM_SHOW_PROPERTY_BROWSER: + { + SFX_REQUEST_ARG( rReq, pShowItem, SfxBoolItem, SID_FM_SHOW_PROPERTIES, sal_False ); + sal_Bool bShow = sal_True; + if ( pShowItem ) + bShow = pShowItem->GetValue(); + GetImpl()->ShowSelectionProperties( bShow ); + + rReq.Done(); + } break; + + case SID_FM_PROPERTIES: + { + // PropertyBrowser anzeigen + SFX_REQUEST_ARG(rReq, pShowItem, SfxBoolItem, nSlot, sal_False); + sal_Bool bShow = pShowItem ? pShowItem->GetValue() : sal_True; + + InterfaceBag aOnlyTheForm; + aOnlyTheForm.insert( Reference< XInterface >( GetImpl()->getCurrentForm(), UNO_QUERY ) ); + GetImpl()->setCurrentSelection( aOnlyTheForm ); + + GetImpl()->ShowSelectionProperties( bShow ); + + rReq.Done(); + } break; + + case SID_FM_CTL_PROPERTIES: + { + SFX_REQUEST_ARG(rReq, pShowItem, SfxBoolItem, nSlot, sal_False); + sal_Bool bShow = pShowItem ? pShowItem->GetValue() : sal_True; + + OSL_ENSURE( GetImpl()->onlyControlsAreMarked(), "FmFormShell::Execute: ControlProperties should be disabled!" ); + if ( bShow ) + GetImpl()->selectLastMarkedControls(); + GetImpl()->ShowSelectionProperties( bShow ); + + rReq.Done(); + } break; + case SID_FM_SHOW_PROPERTIES: + case SID_FM_ADD_FIELD: + case SID_FM_FILTER_NAVIGATOR: + case SID_FM_SHOW_DATANAVIGATOR : + { + GetViewShell()->GetViewFrame()->ChildWindowExecute( rReq ); + rReq.Done(); + } break; + case SID_FM_SHOW_FMEXPLORER: + { + if (!m_pFormView) // setzen der ::com::sun::star::sdbcx::View Forcieren + GetViewShell()->GetViewFrame()->GetDispatcher()->Execute(SID_CREATE_SW_DRAWVIEW); + + GetViewShell()->GetViewFrame()->ChildWindowExecute(rReq); + rReq.Done(); + } + break; + + case SID_FM_TAB_DIALOG: + { + GetImpl()->ExecuteTabOrderDialog( Reference< XTabControllerModel >( GetImpl()->getCurrentForm(), UNO_QUERY ) ); + rReq.Done(); + } + break; + + case SID_FM_DESIGN_MODE: + { + SFX_REQUEST_ARG(rReq, pDesignItem, SfxBoolItem, nSlot, sal_False); + sal_Bool bDesignMode = pDesignItem ? pDesignItem->GetValue() : !m_bDesignMode; + SetDesignMode( bDesignMode ); + if ( m_bDesignMode == bDesignMode ) + rReq.Done(); + + m_nLastSlot = SID_FM_DESIGN_MODE; + GetViewShell()->GetViewFrame()->GetBindings().Invalidate( SID_FM_CONFIG ); + } + break; + + case SID_FM_AUTOCONTROLFOCUS: + { + FmFormModel* pModel = GetFormModel(); + DBG_ASSERT(pModel, "FmFormShell::Execute : invalid call !"); + // should have been disabled in GetState if we don't have a FormModel + pModel->SetAutoControlFocus( !pModel->GetAutoControlFocus() ); + GetViewShell()->GetViewFrame()->GetBindings().Invalidate(SID_FM_AUTOCONTROLFOCUS); + } + break; + case SID_FM_OPEN_READONLY: + { + FmFormModel* pModel = GetFormModel(); + DBG_ASSERT(pModel, "FmFormShell::Execute : invalid call !"); + // should have been disabled in GetState if we don't have a FormModel + pModel->SetOpenInDesignMode( !pModel->GetOpenInDesignMode() ); + GetViewShell()->GetViewFrame()->GetBindings().Invalidate(SID_FM_OPEN_READONLY); + } + break; + case SID_FM_USE_WIZARDS: + { + GetImpl()->SetWizardUsing(!GetImpl()->GetWizardUsing()); + GetViewShell()->GetViewFrame()->GetBindings().Invalidate(SID_FM_USE_WIZARDS); + } + break; + case SID_FM_SEARCH: + { + const ::svx::ControllerFeatures& rController = GetImpl()->getActiveControllerFeatures(); + if ( rController->commitCurrentControl() && rController->commitCurrentRecord() ) + GetImpl()->ExecuteSearch(); + rReq.Done(); + } + break; + + case SID_FM_RECORD_FIRST: + case SID_FM_RECORD_PREV: + case SID_FM_RECORD_NEXT: + case SID_FM_RECORD_LAST: + case SID_FM_RECORD_NEW: + case SID_FM_REFRESH: + case SID_FM_REFRESH_FORM_CONTROL: + case SID_FM_RECORD_DELETE: + case SID_FM_RECORD_UNDO: + case SID_FM_RECORD_SAVE: + case SID_FM_REMOVE_FILTER_SORT: + case SID_FM_SORTDOWN: + case SID_FM_SORTUP: + case SID_FM_AUTOFILTER: + case SID_FM_ORDERCRIT: + case SID_FM_FORM_FILTERED: + { + GetImpl()->ExecuteFormSlot( nSlot ); + rReq.Done(); + } + break; + + case SID_FM_RECORD_ABSOLUTE: + { + const ::svx::ControllerFeatures& rController = GetImpl()->getNavControllerFeatures(); + sal_Int32 nRecord = -1; + + const SfxItemSet* pArgs = rReq.GetArgs(); + if ( pArgs ) + { + const SfxPoolItem* pItem; + if ( ( pArgs->GetItemState( FN_PARAM_1, sal_True, &pItem ) ) == SFX_ITEM_SET ) + { + const SfxInt32Item* pTypedItem = PTR_CAST( SfxInt32Item, pItem ); + if ( pTypedItem ) + nRecord = Max( pTypedItem->GetValue(), sal_Int32(0) ); + } + } + else + { + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + DBG_ASSERT( pFact, "no dialog factory!" ); + if ( pFact ) + { + ::std::auto_ptr< AbstractFmInputRecordNoDialog > dlg( pFact->CreateFmInputRecordNoDialog( NULL ) ); + DBG_ASSERT( dlg.get(), "Dialogdiet fail!" ); + dlg->SetValue( rController->getCursor()->getRow() ); + if ( dlg->Execute() == RET_OK ) + nRecord = dlg->GetValue(); + + rReq.AppendItem( SfxInt32Item( FN_PARAM_1, nRecord ) ); + } + } + + if ( nRecord != -1 ) + rController->execute( nSlot, ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Position" )), makeAny( (sal_Int32)nRecord ) ); + + rReq.Done(); + } break; + case SID_FM_FILTER_EXECUTE: + case SID_FM_FILTER_EXIT: + { + sal_Bool bCancelled = ( SID_FM_FILTER_EXIT == nSlot ); + sal_Bool bReopenNavigator = sal_False; + + if ( !bCancelled ) + { + // if the filter navigator is still open, we need to close it, so it can possibly + // commit it's most recent changes + if ( GetViewShell() && GetViewShell()->GetViewFrame() ) + if ( GetViewShell()->GetViewFrame()->HasChildWindow( SID_FM_FILTER_NAVIGATOR ) ) + { + GetViewShell()->GetViewFrame()->ToggleChildWindow( SID_FM_FILTER_NAVIGATOR ); + bReopenNavigator = sal_True; + } + + Reference< runtime::XFormController > xController( GetImpl()->getActiveController() ); + + if ( GetViewShell()->GetViewFrame()->HasChildWindow( SID_FM_FILTER_NAVIGATOR ) + // closing the window was denied, for instance because of a invalid criterion + + || ( xController.is() + && !GetImpl()->getActiveControllerFeatures()->commitCurrentControl( ) + ) + // committing the controller was denied + ) + { + rReq.Done(); + break; + } + } + + GetImpl()->stopFiltering( !bCancelled ); + rReq.Done(); + + if ( bReopenNavigator ) + // we closed the navigator only to implicitly commit it (as we do not have another + // direct wire to it), but to the user, it should look it it was always open + GetViewShell()->GetViewFrame()->ToggleChildWindow( SID_FM_FILTER_NAVIGATOR ); + } + break; + + case SID_FM_FILTER_START: + { + GetImpl()->startFiltering(); + rReq.Done(); + + // initially open the filter navigator, the whole form based filter is pretty useless without it + SfxBoolItem aIdentifierItem( SID_FM_FILTER_NAVIGATOR, TRUE ); + GetViewShell()->GetViewFrame()->GetDispatcher()->Execute( SID_FM_FILTER_NAVIGATOR, SFX_CALLMODE_ASYNCHRON, + &aIdentifierItem, NULL ); + } break; + } +} + +//------------------------------------------------------------------------ +void FmFormShell::GetState(SfxItemSet &rSet) +{ + SfxWhichIter aIter( rSet ); + sal_uInt16 nWhich = aIter.FirstWhich(); + while ( nWhich ) + { + switch( nWhich ) + { + case SID_FM_MORE_CONTROLS: + case SID_FM_FORM_DESIGN_TOOLS: + { + FormToolboxes aToolboxAccess( GetImpl()->getHostFrame() ); + rSet.Put( SfxBoolItem( nWhich, aToolboxAccess.isToolboxVisible( nWhich ) ) ); + } + break; + + case SID_FM_FILTER_EXECUTE: + case SID_FM_FILTER_EXIT: + if (!GetImpl()->isInFilterMode()) + rSet.DisableItem( nWhich ); + break; + + case SID_FM_USE_WIZARDS: + if ( !SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::E_SDATABASE ) ) + rSet.Put( SfxVisibilityItem( nWhich, sal_False ) ); + else if (!m_bDesignMode || !GetFormModel()) + rSet.DisableItem( nWhich ); + else + rSet.Put( SfxBoolItem(nWhich, GetImpl()->GetWizardUsing() ) ); + break; + case SID_FM_AUTOCONTROLFOCUS: + if (!m_bDesignMode || !GetFormModel()) + rSet.DisableItem( nWhich ); + else + rSet.Put( SfxBoolItem(nWhich, GetFormModel()->GetAutoControlFocus() ) ); + break; + case SID_FM_OPEN_READONLY: + if (!m_bDesignMode || !GetFormModel()) + rSet.DisableItem( nWhich ); + else + rSet.Put( SfxBoolItem(nWhich, GetFormModel()->GetOpenInDesignMode() ) ); + break; + + case SID_FM_NAVIGATIONBAR: + case SID_FM_DBGRID: + if ( !SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::E_SDATABASE ) ) + { + rSet.Put( SfxVisibilityItem( nWhich, sal_False ) ); + break; + } + // NO break! + + case SID_FM_SCROLLBAR: + case SID_FM_IMAGECONTROL: + case SID_FM_FILECONTROL: + case SID_FM_CURRENCYFIELD: + case SID_FM_PATTERNFIELD: + case SID_FM_IMAGEBUTTON: + case SID_FM_RADIOBUTTON: + case SID_FM_COMBOBOX: + case SID_FM_GROUPBOX: + case SID_FM_CHECKBOX: + case SID_FM_PUSHBUTTON: + case SID_FM_FIXEDTEXT: + case SID_FM_LISTBOX: + case SID_FM_EDIT: + case SID_FM_DATEFIELD: + case SID_FM_TIMEFIELD: + case SID_FM_NUMERICFIELD: + case SID_FM_FORMATTEDFIELD: + case SID_FM_SPINBUTTON: + if (!m_bDesignMode) + rSet.DisableItem( nWhich ); + else + { + sal_Bool bLayerLocked = sal_False; + if (m_pFormView) + { + // Ist der ::com::sun::star::drawing::Layer gelocked, so m???ssen die Slots disabled werden. #36897 + SdrPageView* pPV = m_pFormView->GetSdrPageView(); + if (pPV != NULL) + bLayerLocked = pPV->IsLayerLocked(m_pFormView->GetActiveLayer()); + } + if (bLayerLocked) + rSet.DisableItem( nWhich ); + else + rSet.Put( SfxBoolItem(nWhich, (nWhich==m_nLastSlot)) ); + } + break; + case SID_FM_FILTER_NAVIGATOR_CONTROL: + { + if (GetImpl()->isInFilterMode()) + rSet.Put(SfxObjectItem(nWhich, this)); + else + rSet.Put(SfxObjectItem(nWhich)); + } break; + case SID_FM_FIELDS_CONTROL: + case SID_FM_PROPERTY_CONTROL: + { + if (!m_bDesignMode || !m_pFormView || !m_bHasForms) + rSet.Put(SfxObjectItem(nWhich)); + else + rSet.Put(SfxObjectItem(nWhich, this)); + + } break; + case SID_FM_FMEXPLORER_CONTROL: + case SID_FM_DATANAVIGATOR_CONTROL : + { + if (!m_bDesignMode || !m_pFormView) + rSet.Put(SfxObjectItem(nWhich)); + else + rSet.Put(SfxObjectItem(nWhich, this)); + + } break; + case SID_FM_ADD_FIELD: + case SID_FM_SHOW_FMEXPLORER: + case SID_FM_SHOW_PROPERTIES: + case SID_FM_FILTER_NAVIGATOR: + case SID_FM_SHOW_DATANAVIGATOR: + { + if ( GetViewShell()->GetViewFrame()->KnowsChildWindow(nWhich) ) + rSet.Put( SfxBoolItem( nWhich, GetViewShell()->GetViewFrame()->HasChildWindow(nWhich)) ); + else + rSet.DisableItem(nWhich); + } break; + + case SID_FM_SHOW_PROPERTY_BROWSER: + { + rSet.Put(SfxBoolItem(GetImpl()->IsPropBrwOpen())); + } + break; + + case SID_FM_CTL_PROPERTIES: + { + // der Impl eventuell die Moeglichjkeit geben, ihre an der aktuellen MarkList ausgerichteten Objekte + // auf den neuesten Stand zu bringen + if (GetImpl()->IsSelectionUpdatePending()) + GetImpl()->ForceUpdateSelection(sal_False); + + if ( !m_pFormView || !m_bDesignMode || !GetImpl()->onlyControlsAreMarked() ) + rSet.DisableItem( nWhich ); + else + { + sal_Bool bChecked = GetImpl()->IsPropBrwOpen() && !GetImpl()->isSolelySelected( GetImpl()->getCurrentForm() ); + // if the property browser is open, and only controls are marked, and the current selection + // does not consist of only the current form, then the current selection is the (composition of) + // the currently marked controls + rSet.Put( SfxBoolItem( nWhich, bChecked ) ); + } + } break; + + case SID_FM_PROPERTIES: + { + // der Impl eventuell die Moeglichjkeit geben, ihre an der aktuellen MarkList ausgerichteten Objekte + // auf den neuesten Stand zu bringen + if (GetImpl()->IsSelectionUpdatePending()) + GetImpl()->ForceUpdateSelection(sal_False); + + if ( !m_pFormView || !m_bDesignMode || !GetImpl()->getCurrentForm().is() ) + rSet.DisableItem( nWhich ); + else + { + sal_Bool bChecked = GetImpl()->IsPropBrwOpen() && GetImpl()->isSolelySelected( GetImpl()->getCurrentForm() ); + rSet.Put(SfxBoolItem(nWhich, bChecked)); + } + } break; + case SID_FM_TAB_DIALOG: + // der Impl eventuell die Moeglichjkeit geben, ihre an der aktuellen MarkList ausgerichteten Objekte + // auf den neuesten Stand zu bringen + if (GetImpl()->IsSelectionUpdatePending()) + GetImpl()->ForceUpdateSelection(sal_False); + + if (!m_pFormView || !m_bDesignMode || !GetImpl()->getCurrentForm().is() ) + rSet.DisableItem( nWhich ); + break; + case SID_FM_CONFIG: + rSet.Put(SfxUInt16Item(nWhich, m_nLastSlot)); + break; + case SID_FM_DESIGN_MODE: + if (!m_pFormView || GetImpl()->IsReadonlyDoc() ) + rSet.DisableItem( nWhich ); + else + rSet.Put( SfxBoolItem(nWhich, m_bDesignMode) ); + break; + case SID_FM_SEARCH: + case SID_FM_RECORD_FIRST: + case SID_FM_RECORD_NEXT: + case SID_FM_RECORD_PREV: + case SID_FM_RECORD_LAST: + case SID_FM_RECORD_NEW: + case SID_FM_RECORD_DELETE: + case SID_FM_RECORD_ABSOLUTE: + case SID_FM_RECORD_TOTAL: + case SID_FM_RECORD_SAVE: + case SID_FM_RECORD_UNDO: + case SID_FM_FORM_FILTERED: + case SID_FM_REMOVE_FILTER_SORT: + case SID_FM_SORTUP: + case SID_FM_SORTDOWN: + case SID_FM_ORDERCRIT: + case SID_FM_FILTER_START: + case SID_FM_AUTOFILTER: + case SID_FM_REFRESH: + case SID_FM_REFRESH_FORM_CONTROL: + case SID_FM_VIEW_AS_GRID: + GetFormState(rSet,nWhich); + break; + + case SID_FM_CHANGECONTROLTYPE: + { + if ( !m_pFormView || !m_bDesignMode ) + rSet.DisableItem( nWhich ); + else + { + if ( !GetImpl()->canConvertCurrentSelectionToControl( OBJ_FM_FIXEDTEXT ) ) + // if it cannot be converted to a fixed text, it is no single control + rSet.DisableItem( nWhich ); + } + } break; + + case SID_FM_CONVERTTO_FILECONTROL : + case SID_FM_CONVERTTO_CURRENCY : + case SID_FM_CONVERTTO_PATTERN : + case SID_FM_CONVERTTO_IMAGECONTROL : + case SID_FM_CONVERTTO_SCROLLBAR : + case SID_FM_CONVERTTO_NAVIGATIONBAR : + case SID_FM_CONVERTTO_IMAGEBUTTON : + case SID_FM_CONVERTTO_EDIT : + case SID_FM_CONVERTTO_BUTTON : + case SID_FM_CONVERTTO_FIXEDTEXT : + case SID_FM_CONVERTTO_LISTBOX : + case SID_FM_CONVERTTO_CHECKBOX : + case SID_FM_CONVERTTO_RADIOBUTTON : + case SID_FM_CONVERTTO_GROUPBOX : + case SID_FM_CONVERTTO_COMBOBOX : + case SID_FM_CONVERTTO_DATE : + case SID_FM_CONVERTTO_TIME : + case SID_FM_CONVERTTO_NUMERIC : + case SID_FM_CONVERTTO_FORMATTED : + case SID_FM_CONVERTTO_SPINBUTTON : + { + if ( !m_pFormView || !m_bDesignMode || !GetImpl()->canConvertCurrentSelectionToControl( nWhich ) ) + rSet.DisableItem( nWhich ); + else + { + rSet.Put( SfxBoolItem( nWhich, sal_False ) ); + // just to have a defined state (available and not checked) + } + } + break; + } + nWhich = aIter.NextWhich(); + } +} + +//------------------------------------------------------------------------ +void FmFormShell::GetFormState(SfxItemSet &rSet, sal_uInt16 nWhich) +{ + if ( !GetImpl()->getNavController().is() + || !isRowSetAlive(GetImpl()->getNavController()->getModel()) + || !m_pFormView + || m_bDesignMode + || !GetImpl()->getActiveForm().is() + || GetImpl()->isInFilterMode() + ) + rSet.DisableItem(nWhich); + else + { + sal_Bool bEnable = sal_False; + try + { + switch (nWhich) + { + case SID_FM_VIEW_AS_GRID: + if (GetImpl()->getHostFrame().is() && GetImpl()->getNavController().is()) + { + bEnable = sal_True; + sal_Bool bDisplayingCurrent = + GetImpl()->getInternalForm( + Reference< XForm >( GetImpl()->getNavController()->getModel(), UNO_QUERY ) + ) == GetImpl()->getExternallyDisplayedForm(); + rSet.Put(SfxBoolItem(nWhich, bDisplayingCurrent)); + } + break; + + case SID_FM_SEARCH: + { + Reference< ::com::sun::star::beans::XPropertySet > xNavSet(GetImpl()->getActiveForm(), UNO_QUERY); + sal_Int32 nCount = ::comphelper::getINT32(xNavSet->getPropertyValue(FM_PROP_ROWCOUNT)); + bEnable = nCount != 0; + } break; + case SID_FM_RECORD_ABSOLUTE: + case SID_FM_RECORD_TOTAL: + { + FeatureState aState; + GetImpl()->getNavControllerFeatures()->getState( nWhich, aState ); + if ( SID_FM_RECORD_ABSOLUTE == nWhich ) + { + sal_Int32 nPosition = 0; + aState.State >>= nPosition; + rSet.Put( SfxInt32Item( nWhich, nPosition ) ); + } + else if ( SID_FM_RECORD_TOTAL == nWhich ) + { + ::rtl::OUString sTotalCount; + aState.State >>= sTotalCount; + rSet.Put( SfxStringItem( nWhich, sTotalCount ) ); + } + bEnable = aState.Enabled; + } + break; + + // first, prev, next, last, and absolute affect the nav controller, not the + // active controller + case SID_FM_RECORD_FIRST: + case SID_FM_RECORD_PREV: + case SID_FM_RECORD_NEXT: + case SID_FM_RECORD_LAST: + case SID_FM_RECORD_NEW: + case SID_FM_RECORD_SAVE: + case SID_FM_RECORD_UNDO: + case SID_FM_RECORD_DELETE: + case SID_FM_REFRESH: + case SID_FM_REFRESH_FORM_CONTROL: + case SID_FM_REMOVE_FILTER_SORT: + case SID_FM_SORTUP: + case SID_FM_SORTDOWN: + case SID_FM_AUTOFILTER: + case SID_FM_ORDERCRIT: + bEnable = GetImpl()->IsFormSlotEnabled( nWhich ); + break; + + case SID_FM_FORM_FILTERED: + { + FeatureState aState; + bEnable = GetImpl()->IsFormSlotEnabled( nWhich, &aState ); + + rSet.Put( SfxBoolItem( nWhich, ::comphelper::getBOOL( aState.State ) ) ); + } + break; + + case SID_FM_FILTER_START: + bEnable = GetImpl()->getActiveControllerFeatures()->canDoFormFilter(); + break; + } + } + catch( const Exception& ) + { + DBG_ERROR( "FmFormShell::GetFormState: caught an exception while determining the state!" ); + } + if (!bEnable) + rSet.DisableItem(nWhich); + } +} + +//------------------------------------------------------------------------ +FmFormPage* FmFormShell::GetCurPage() const +{ + FmFormPage* pP = NULL; + if (m_pFormView && m_pFormView->GetSdrPageView()) + pP = PTR_CAST(FmFormPage,m_pFormView->GetSdrPageView()->GetPage()); + return pP; +} + +//------------------------------------------------------------------------ +void FmFormShell::SetView( FmFormView* _pView ) +{ + if ( m_pFormView ) + { + if ( IsActive() ) + GetImpl()->viewDeactivated( *m_pFormView ); + + m_pFormView->SetFormShell( NULL, FmFormView::FormShellAccess() ); + m_pFormView = NULL; + m_pFormModel = NULL; + } + + if ( !_pView ) + return; + + m_pFormView = _pView; + m_pFormView->SetFormShell( this, FmFormView::FormShellAccess() ); + m_pFormModel = (FmFormModel*)m_pFormView->GetModel(); + + impl_setDesignMode( m_pFormView->IsDesignMode() ); + + // We activate our view if we are activated ourself, but sometimes the Activate precedes the SetView. + // But here we know both the view and our activation state so we at least are able to pass the latter + // to the former. + // FS - 30.06.99 - 67308 + if ( IsActive() ) + GetImpl()->viewActivated( *m_pFormView ); +} + +//------------------------------------------------------------------------ +void FmFormShell::DetermineForms(sal_Bool bInvalidate) +{ + // Existieren Formulare auf der aktuellen Page + sal_Bool bForms = GetImpl()->hasForms(); + if (bForms != m_bHasForms) + { + m_bHasForms = bForms; + if (bInvalidate) + UIFeatureChanged(); + } +} + +//------------------------------------------------------------------------ +sal_Bool FmFormShell::GetY2KState(sal_uInt16& nReturn) +{ + return GetImpl()->GetY2KState(nReturn); +} + +//------------------------------------------------------------------------ +void FmFormShell::SetY2KState(sal_uInt16 n) +{ + GetImpl()->SetY2KState(n); +} + +//------------------------------------------------------------------------ +void FmFormShell::Activate(sal_Bool bMDI) +{ + SfxShell::Activate(bMDI); + + if ( m_pFormView ) + GetImpl()->viewActivated( *m_pFormView, sal_True ); +} + +//------------------------------------------------------------------------ +void FmFormShell::Deactivate(sal_Bool bMDI) +{ + SfxShell::Deactivate(bMDI); + + if ( m_pFormView ) + GetImpl()->viewDeactivated( *m_pFormView, sal_False ); +} + +//------------------------------------------------------------------------ +void FmFormShell::ExecuteTextAttribute( SfxRequest& _rReq ) +{ + m_pImpl->ExecuteTextAttribute( _rReq ); +} + +//------------------------------------------------------------------------ +void FmFormShell::GetTextAttributeState( SfxItemSet& _rSet ) +{ + m_pImpl->GetTextAttributeState( _rSet ); +} + +//------------------------------------------------------------------------ +bool FmFormShell::IsActiveControl() const +{ + return m_pImpl->IsActiveControl(); +} + +//------------------------------------------------------------------------ +void FmFormShell::ForgetActiveControl() +{ + m_pImpl->ForgetActiveControl(); +} + +//------------------------------------------------------------------------ +void FmFormShell::SetControlActivationHandler( const Link& _rHdl ) +{ + m_pImpl->SetControlActivationHandler( _rHdl ); +} + +//------------------------------------------------------------------------ +namespace +{ + SdrUnoObj* lcl_findUnoObject( const SdrObjList& _rObjList, const Reference< XControlModel >& _rxModel ) + { + SdrObjListIter aIter( _rObjList ); + while ( aIter.IsMore() ) + { + SdrObject* pObject = aIter.Next(); + SdrUnoObj* pUnoObject = pObject ? PTR_CAST( SdrUnoObj, pObject ) : NULL; + if ( !pUnoObject ) + continue; + + Reference< XControlModel > xControlModel = pUnoObject->GetUnoControlModel(); + if ( !xControlModel.is() ) + continue; + + if ( _rxModel == xControlModel ) + return pUnoObject; + } + return NULL; + } +} + +//------------------------------------------------------------------------ +void FmFormShell::ToggleControlFocus( const SdrUnoObj& i_rUnoObject, const SdrView& i_rView, OutputDevice& i_rDevice ) const +{ + try + { + // check if the focus currently is in a control + // Well, okay, do it the other way 'round: Check whether the current control of the active controller + // actually has the focus. This should be equivalent. + const bool bHasControlFocus = GetImpl()->HasControlFocus(); + + if ( bHasControlFocus ) + { + Window* pWindow( dynamic_cast< Window* >( &i_rDevice ) ); + OSL_ENSURE( pWindow, "FmFormShell::ToggleControlFocus: I need a Window, really!" ); + if ( pWindow ) + pWindow->GrabFocus(); + } + else + { + Reference< XControl > xControl; + GetFormControl( i_rUnoObject.GetUnoControlModel(), i_rView, i_rDevice, xControl ); + Reference< XWindow > xControlWindow( xControl, UNO_QUERY ); + if ( xControlWindow.is() ) + xControlWindow->setFocus(); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +//------------------------------------------------------------------------ +namespace +{ + class FocusableControlsFilter : public ::svx::ISdrObjectFilter + { + public: + FocusableControlsFilter( const SdrView& i_rView, const OutputDevice& i_rDevice ) + :m_rView( i_rView ) + ,m_rDevice( i_rDevice ) + { + } + + public: + virtual bool includeObject( const SdrObject& i_rObject ) const + { + const SdrUnoObj* pUnoObj = dynamic_cast< const SdrUnoObj* >( &i_rObject ); + if ( !pUnoObj ) + return false; + + Reference< XControl > xControl = pUnoObj->GetUnoControl( m_rView, m_rDevice ); + return FmXFormView::isFocusable( xControl ); + } + + private: + const SdrView& m_rView; + const OutputDevice& m_rDevice; + }; +} + +//------------------------------------------------------------------------ +::std::auto_ptr< ::svx::ISdrObjectFilter > FmFormShell::CreateFocusableControlFilter( const SdrView& i_rView, const OutputDevice& i_rDevice ) const +{ + ::std::auto_ptr< ::svx::ISdrObjectFilter > pFilter; + + if ( !i_rView.IsDesignMode() ) + pFilter.reset( new FocusableControlsFilter( i_rView, i_rDevice ) ); + + return pFilter; +} + +//------------------------------------------------------------------------ +SdrUnoObj* FmFormShell::GetFormControl( const Reference< XControlModel >& _rxModel, const SdrView& _rView, const OutputDevice& _rDevice, Reference< XControl >& _out_rxControl ) const +{ + if ( !_rxModel.is() ) + return NULL; + + // we can only retrieve controls for SdrObjects which belong to page which is actually displayed in the given view + SdrPageView* pPageView = _rView.GetSdrPageView(); + SdrPage* pPage = pPageView ? pPageView->GetPage() : NULL; + OSL_ENSURE( pPage, "FmFormShell::GetFormControl: no page displayed in the given view!" ); + if ( !pPage ) + return NULL; + + SdrUnoObj* pUnoObject = lcl_findUnoObject( *pPage, _rxModel ); + if ( pUnoObject ) + { + _out_rxControl = pUnoObject->GetUnoControl( _rView, _rDevice ); + return pUnoObject; + } + +#if OSL_DEBUG_LEVEL > 0 + // perhaps we are fed with a control model which lives on a page other than the one displayed + // in the given view. This is worth being reported as error, in non-product builds. + FmFormModel* pModel = GetFormModel(); + if ( pModel ) + { + sal_uInt16 pageCount = pModel->GetPageCount(); + for ( sal_uInt16 page = 0; page < pageCount; ++page ) + { + pPage = pModel->GetPage( page ); + OSL_ENSURE( pPage, "FmFormShell::GetFormControl: NULL page encountered!" ); + if ( !pPage ) + continue; + + pUnoObject = lcl_findUnoObject( *pPage, _rxModel ); + OSL_ENSURE( !pUnoObject, "FmFormShell::GetFormControl: the given control model belongs to a wrong page (displayed elsewhere)!" ); + } + } +#endif + + return NULL; +} + +//------------------------------------------------------------------------ +Reference< runtime::XFormController > FmFormShell::GetFormController( const Reference< XForm >& _rxForm, const SdrView& _rView, const OutputDevice& _rDevice ) const +{ + const FmFormView* pFormView = dynamic_cast< const FmFormView* >( &_rView ); + if ( !pFormView ) + return NULL; + + return pFormView->GetFormController( _rxForm, _rDevice ); +} + +//------------------------------------------------------------------------ +void FmFormShell::SetDesignMode( sal_Bool _bDesignMode ) +{ + if ( _bDesignMode == m_bDesignMode ) + return; + + FmFormModel* pModel = GetFormModel(); + if (pModel) + // fuer die Zeit des Uebergangs das Undo-Environment ausschalten, das sichert, dass man dort auch nicht-transiente + // Properties mal eben aendern kann (sollte allerdings mit Vorsicht genossen und beim Rueckschalten des Modes + // auch immer wieder rueckgaegig gemacht werden. Ein Beispiel ist das Setzen der maximalen Text-Laenge durch das + // OEditModel an seinem Control.) + pModel->GetUndoEnv().Lock(); + + // dann die eigentliche Umschaltung + if ( m_bDesignMode || PrepareClose( sal_True ) ) + impl_setDesignMode(!m_bDesignMode ); + + // und mein Undo-Environment wieder an + if ( pModel ) + pModel->GetUndoEnv().UnLock(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmshimp.cxx b/svx/source/form/fmshimp.cxx new file mode 100644 index 000000000000..cf39a32ca903 --- /dev/null +++ b/svx/source/form/fmshimp.cxx @@ -0,0 +1,4340 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include <sal/macros.h> +#include "fmitems.hxx" +#include "fmobj.hxx" +#include "fmpgeimp.hxx" +#include "svx/fmtools.hxx" +#include "fmprop.hrc" +#include "fmresids.hrc" +#include "fmservs.hxx" +#include "fmshimp.hxx" +#include "fmtextcontrolshell.hxx" +#include "fmundo.hxx" +#include "fmurl.hxx" +#include "fmvwimp.hxx" +#include "formtoolbars.hxx" +#include "gridcols.hxx" +#include "svditer.hxx" +#include "svx/dialmgr.hxx" +#include "svx/dialogs.hrc" +#include "svx/fmglob.hxx" +#include "svx/fmmodel.hxx" +#include "svx/fmpage.hxx" +#include "svx/fmshell.hxx" +#include "svx/obj3d.hxx" +#include "svx/sdrpagewindow.hxx" +#include "svx/svdpagv.hxx" +#include "svx/svxdlg.hxx" +#include "svx/svxids.hrc" + +/** === begin UNO includes === **/ +#include <com/sun/star/awt/XWindow2.hpp> +#include <com/sun/star/awt/XCheckBox.hpp> +#include <com/sun/star/awt/XListBox.hpp> +#include <com/sun/star/awt/XTextComponent.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/container/XContainer.hpp> +#include <com/sun/star/container/XEnumeration.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/form/ListSourceType.hpp> +#include <com/sun/star/form/XBoundComponent.hpp> +#include <com/sun/star/form/XBoundControl.hpp> +#include <com/sun/star/form/XGrid.hpp> +#include <com/sun/star/form/XGridPeer.hpp> +#include <com/sun/star/form/XLoadable.hpp> +#include <com/sun/star/form/XReset.hpp> +#include <com/sun/star/form/binding/XBindableValue.hpp> +#include <com/sun/star/form/binding/XListEntrySink.hpp> +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/script/XEventAttacherManager.hpp> +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#include <com/sun/star/util/XCancellable.hpp> +#include <com/sun/star/util/XModeSelector.hpp> +#include <com/sun/star/util/XModifyBroadcaster.hpp> +#include <com/sun/star/util/XNumberFormatter.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <com/sun/star/beans/XIntrospection.hpp> +/** === end UNO includes === **/ + +#include <comphelper/extract.hxx> +#include <comphelper/evtmethodhelper.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/property.hxx> +#include <comphelper/stl_types.hxx> +#include <connectivity/dbtools.hxx> +#include <cppuhelper/servicefactory.hxx> +#include <osl/mutex.hxx> +#include <rtl/logfile.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/frame.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/viewsh.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <tools/color.hxx> +#include <tools/diagnose_ex.h> +#include <tools/shl.hxx> +#include <tools/urlobj.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/waitobj.hxx> +#include <osl/mutex.hxx> + +#include <algorithm> +#include <functional> + +// wird fuer Invalidate verwendet -> mitpflegen +sal_uInt16 DatabaseSlotMap[] = +{ + SID_FM_RECORD_FIRST, + SID_FM_RECORD_NEXT, + SID_FM_RECORD_PREV, + SID_FM_RECORD_LAST, + SID_FM_RECORD_NEW, + SID_FM_RECORD_DELETE, + SID_FM_RECORD_ABSOLUTE, + SID_FM_RECORD_TOTAL, + SID_FM_RECORD_SAVE, + SID_FM_RECORD_UNDO, + SID_FM_REMOVE_FILTER_SORT, + SID_FM_SORTUP, + SID_FM_SORTDOWN, + SID_FM_ORDERCRIT, + SID_FM_AUTOFILTER, + SID_FM_FORM_FILTERED, + SID_FM_REFRESH, + SID_FM_REFRESH_FORM_CONTROL, + SID_FM_SEARCH, + SID_FM_FILTER_START, + SID_FM_VIEW_AS_GRID, + 0 +}; + +// wird fuer Invalidate verwendet -> mitpflegen +// aufsteigend sortieren !!!!!! +sal_Int16 DlgSlotMap[] = // slots des Controllers +{ + SID_FM_CTL_PROPERTIES, + SID_FM_PROPERTIES, + SID_FM_TAB_DIALOG, + SID_FM_ADD_FIELD, + SID_FM_SHOW_FMEXPLORER, + SID_FM_FIELDS_CONTROL, + SID_FM_SHOW_PROPERTIES, + SID_FM_PROPERTY_CONTROL, + SID_FM_FMEXPLORER_CONTROL, + SID_FM_SHOW_DATANAVIGATOR, + SID_FM_DATANAVIGATOR_CONTROL, + 0 +}; + +sal_Int16 SelObjectSlotMap[] = // vom SelObject abhaengige Slots +{ + SID_FM_CONVERTTO_EDIT, + SID_FM_CONVERTTO_BUTTON, + SID_FM_CONVERTTO_FIXEDTEXT, + SID_FM_CONVERTTO_LISTBOX, + SID_FM_CONVERTTO_CHECKBOX, + SID_FM_CONVERTTO_RADIOBUTTON, + SID_FM_CONVERTTO_GROUPBOX, + SID_FM_CONVERTTO_COMBOBOX, + SID_FM_CONVERTTO_IMAGEBUTTON, + SID_FM_CONVERTTO_FILECONTROL, + SID_FM_CONVERTTO_DATE, + SID_FM_CONVERTTO_TIME, + SID_FM_CONVERTTO_NUMERIC, + SID_FM_CONVERTTO_CURRENCY, + SID_FM_CONVERTTO_PATTERN, + SID_FM_CONVERTTO_IMAGECONTROL, + SID_FM_CONVERTTO_FORMATTED, + SID_FM_CONVERTTO_SCROLLBAR, + SID_FM_CONVERTTO_SPINBUTTON, + SID_FM_CONVERTTO_NAVIGATIONBAR, + + SID_FM_FMEXPLORER_CONTROL, + SID_FM_DATANAVIGATOR_CONTROL, + + 0 +}; + +// die folgenden Arrays muessen kosistent sein, also einander entsprechende Eintraege an der selben relativen Position +// innerhalb ihres jeweiligen Arrays stehen +sal_Int16 nConvertSlots[] = +{ + SID_FM_CONVERTTO_EDIT, + SID_FM_CONVERTTO_BUTTON, + SID_FM_CONVERTTO_FIXEDTEXT, + SID_FM_CONVERTTO_LISTBOX, + SID_FM_CONVERTTO_CHECKBOX, + SID_FM_CONVERTTO_RADIOBUTTON, + SID_FM_CONVERTTO_GROUPBOX, + SID_FM_CONVERTTO_COMBOBOX, + SID_FM_CONVERTTO_IMAGEBUTTON, + SID_FM_CONVERTTO_FILECONTROL, + SID_FM_CONVERTTO_DATE, + SID_FM_CONVERTTO_TIME, + SID_FM_CONVERTTO_NUMERIC, + SID_FM_CONVERTTO_CURRENCY, + SID_FM_CONVERTTO_PATTERN, + SID_FM_CONVERTTO_IMAGECONTROL, + SID_FM_CONVERTTO_FORMATTED, + SID_FM_CONVERTTO_SCROLLBAR, + SID_FM_CONVERTTO_SPINBUTTON, + SID_FM_CONVERTTO_NAVIGATIONBAR +}; + +sal_Int16 nCreateSlots[] = +{ + SID_FM_EDIT, + SID_FM_PUSHBUTTON, + SID_FM_FIXEDTEXT, + SID_FM_LISTBOX, + SID_FM_CHECKBOX, + SID_FM_RADIOBUTTON, + SID_FM_GROUPBOX, + SID_FM_COMBOBOX, + SID_FM_IMAGEBUTTON, + SID_FM_FILECONTROL, + SID_FM_DATEFIELD, + SID_FM_TIMEFIELD, + SID_FM_NUMERICFIELD, + SID_FM_CURRENCYFIELD, + SID_FM_PATTERNFIELD, + SID_FM_IMAGECONTROL, + SID_FM_FORMATTEDFIELD, + SID_FM_SCROLLBAR, + SID_FM_SPINBUTTON, + SID_FM_NAVIGATIONBAR +}; + +sal_Int16 nObjectTypes[] = +{ + OBJ_FM_EDIT, + OBJ_FM_BUTTON, + OBJ_FM_FIXEDTEXT, + OBJ_FM_LISTBOX, + OBJ_FM_CHECKBOX, + OBJ_FM_RADIOBUTTON, + OBJ_FM_GROUPBOX, + OBJ_FM_COMBOBOX, + OBJ_FM_IMAGEBUTTON, + OBJ_FM_FILECONTROL, + OBJ_FM_DATEFIELD, + OBJ_FM_TIMEFIELD, + OBJ_FM_NUMERICFIELD, + OBJ_FM_CURRENCYFIELD, + OBJ_FM_PATTERNFIELD, + OBJ_FM_IMAGECONTROL, + OBJ_FM_FORMATTEDFIELD, + OBJ_FM_SCROLLBAR, + OBJ_FM_SPINBUTTON, + OBJ_FM_NAVIGATIONBAR +}; + +using namespace ::com::sun::star; +using namespace ::com::sun::star::ui; +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::form::binding; +using namespace ::com::sun::star::form::runtime; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::view; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::script; +using namespace ::svxform; +using namespace ::svx; + +//============================================================================== +//= helper +//============================================================================== +namespace +{ + //.......................................................................... + void collectInterfacesFromMarkList( const SdrMarkList& _rMarkList, InterfaceBag& /* [out] */ _rInterfaces ) + { + _rInterfaces.clear(); + + sal_uInt32 nMarkCount = _rMarkList.GetMarkCount(); + for ( sal_uInt32 i = 0; i < nMarkCount; ++i) + { + SdrObject* pCurrent = _rMarkList.GetMark( i )->GetMarkedSdrObj(); + + SdrObjListIter* pGroupIterator = NULL; + if ( pCurrent->IsGroupObject() ) + { + pGroupIterator = new SdrObjListIter( *pCurrent->GetSubList() ); + pCurrent = pGroupIterator->IsMore() ? pGroupIterator->Next() : NULL; + } + + while ( pCurrent ) + { + FmFormObj* pAsFormObject = FmFormObj::GetFormObject( pCurrent ); + // note this will de-reference virtual objects, if necessary/possible + if ( pAsFormObject ) + { + Reference< XInterface > xControlModel( pAsFormObject->GetUnoControlModel(), UNO_QUERY ); + // the UNO_QUERY is important for normalization + if ( xControlModel.is() ) + _rInterfaces.insert( xControlModel ); + } + + // next element + pCurrent = pGroupIterator && pGroupIterator->IsMore() ? pGroupIterator->Next() : NULL; + } + + if ( pGroupIterator ) + delete pGroupIterator; + } + } + + //.......................................................................... + sal_Int16 GridView2ModelPos(const Reference< XIndexAccess>& rColumns, sal_Int16 nViewPos) + { + try + { + if (rColumns.is()) + { + // loop through all columns + sal_Int16 i; + Reference< XPropertySet> xCur; + for (i=0; i<rColumns->getCount(); ++i) + { + rColumns->getByIndex(i) >>= xCur; + if (!::comphelper::getBOOL(xCur->getPropertyValue(FM_PROP_HIDDEN))) + { + // for every visible col : if nViewPos is greater zero, decrement it, else we + // have found the model position + if (!nViewPos) + break; + else + --nViewPos; + } + } + if (i<rColumns->getCount()) + return i; + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + return (sal_Int16)-1; + } + + //.......................................................................... + void TransferEventScripts(const Reference< XControlModel>& xModel, const Reference< XControl>& xControl, + const Sequence< ScriptEventDescriptor>& rTransferIfAvailable) + { + // first check if we have a XEventAttacherManager for the model + Reference< XChild> xModelChild(xModel, UNO_QUERY); + if (!xModelChild.is()) + return; // nothing to do + + Reference< XEventAttacherManager> xEventManager(xModelChild->getParent(), UNO_QUERY); + if (!xEventManager.is()) + return; // nothing to do + + if (!rTransferIfAvailable.getLength()) + return; // nothing to do + + // check for the index of the model within it's parent + Reference< XIndexAccess> xParentIndex(xModelChild->getParent(), UNO_QUERY); + if (!xParentIndex.is()) + return; // nothing to do + sal_Int32 nIndex = getElementPos(xParentIndex, xModel); + if (nIndex<0 || nIndex>=xParentIndex->getCount()) + return; // nothing to do + + // then we need informations about the listeners supported by the control and the model + Sequence< Type> aModelListeners; + Sequence< Type> aControlListeners; + + Reference< XIntrospection> xModelIntrospection(::comphelper::getProcessServiceFactory()->createInstance(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.beans.Introspection"))), UNO_QUERY); + Reference< XIntrospection> xControlIntrospection(::comphelper::getProcessServiceFactory()->createInstance(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.beans.Introspection"))), UNO_QUERY); + + if (xModelIntrospection.is() && xModel.is()) + { + Any aModel(makeAny(xModel)); + aModelListeners = xModelIntrospection->inspect(aModel)->getSupportedListeners(); + } + + if (xControlIntrospection.is() && xControl.is()) + { + Any aControl(makeAny(xControl)); + aControlListeners = xControlIntrospection->inspect(aControl)->getSupportedListeners(); + } + + sal_Int32 nMaxNewLen = aModelListeners.getLength() + aControlListeners.getLength(); + if (!nMaxNewLen) + return; // the model and the listener don't support any listeners (or we were unable to retrieve these infos) + + Sequence< ScriptEventDescriptor> aTransferable(nMaxNewLen); + ScriptEventDescriptor* pTransferable = aTransferable.getArray(); + + const ScriptEventDescriptor* pCurrent = rTransferIfAvailable.getConstArray(); + sal_Int32 i,j,k; + for (i=0; i<rTransferIfAvailable.getLength(); ++i, ++pCurrent) + { + // search the model/control idl classes for the event described by pCurrent + for ( Sequence< Type>* pCurrentArray = &aModelListeners; + pCurrentArray; + pCurrentArray = (pCurrentArray == &aModelListeners) ? &aControlListeners : NULL + ) + { + const Type* pCurrentListeners = pCurrentArray->getConstArray(); + for (j=0; j<pCurrentArray->getLength(); ++j, ++pCurrentListeners) + { + UniString aListener = (*pCurrentListeners).getTypeName(); + xub_StrLen nTokens = aListener.GetTokenCount('.'); + if (nTokens) + aListener = aListener.GetToken(nTokens - 1, '.'); + + if (aListener == pCurrent->ListenerType.getStr()) + // the current ScriptEventDescriptor doesn't match the current listeners class + continue; + + // now check the methods + Sequence< ::rtl::OUString> aMethodsNames = ::comphelper::getEventMethodsForType(*pCurrentListeners); + + const ::rtl::OUString* pMethodsNames = aMethodsNames.getConstArray(); + for (k=0; k<aMethodsNames.getLength(); ++k, ++pMethodsNames) + { + if ((*pMethodsNames).compareTo(pCurrent->EventMethod) != COMPARE_EQUAL) + // the current ScriptEventDescriptor doesn't match the current listeners current method + continue; + + // we can transfer the script event : the model (control) supports it + *pTransferable = *pCurrent; + ++pTransferable; + break; + } + if (k<aMethodsNames.getLength()) + break; + } + } + } + + sal_Int32 nRealNewLen = pTransferable - aTransferable.getArray(); + aTransferable.realloc(nRealNewLen); + + xEventManager->registerScriptEvents(nIndex, aTransferable); + } + + //------------------------------------------------------------------------------ + ::rtl::OUString getServiceNameByControlType(sal_Int16 nType) + { + switch (nType) + { + case OBJ_FM_EDIT : return FM_COMPONENT_TEXTFIELD; + case OBJ_FM_BUTTON : return FM_COMPONENT_COMMANDBUTTON; + case OBJ_FM_FIXEDTEXT : return FM_COMPONENT_FIXEDTEXT; + case OBJ_FM_LISTBOX : return FM_COMPONENT_LISTBOX; + case OBJ_FM_CHECKBOX : return FM_COMPONENT_CHECKBOX; + case OBJ_FM_RADIOBUTTON : return FM_COMPONENT_RADIOBUTTON; + case OBJ_FM_GROUPBOX : return FM_COMPONENT_GROUPBOX; + case OBJ_FM_COMBOBOX : return FM_COMPONENT_COMBOBOX; + case OBJ_FM_GRID : return FM_COMPONENT_GRIDCONTROL; + case OBJ_FM_IMAGEBUTTON : return FM_COMPONENT_IMAGEBUTTON; + case OBJ_FM_FILECONTROL : return FM_COMPONENT_FILECONTROL; + case OBJ_FM_DATEFIELD : return FM_COMPONENT_DATEFIELD; + case OBJ_FM_TIMEFIELD : return FM_COMPONENT_TIMEFIELD; + case OBJ_FM_NUMERICFIELD : return FM_COMPONENT_NUMERICFIELD; + case OBJ_FM_CURRENCYFIELD : return FM_COMPONENT_CURRENCYFIELD; + case OBJ_FM_PATTERNFIELD : return FM_COMPONENT_PATTERNFIELD; + case OBJ_FM_HIDDEN : return FM_COMPONENT_HIDDENCONTROL; + case OBJ_FM_IMAGECONTROL : return FM_COMPONENT_IMAGECONTROL; + case OBJ_FM_FORMATTEDFIELD : return FM_COMPONENT_FORMATTEDFIELD; + case OBJ_FM_SCROLLBAR : return FM_SUN_COMPONENT_SCROLLBAR; + case OBJ_FM_SPINBUTTON : return FM_SUN_COMPONENT_SPINBUTTON; + case OBJ_FM_NAVIGATIONBAR : return FM_SUN_COMPONENT_NAVIGATIONBAR; + } + return ::rtl::OUString(); + } + +} + +//------------------------------------------------------------------------------ +// check if the control has one of the interfaces we can use for searching +// *_pCurrentText will be filled with the current text of the control (as used when searching this control) +sal_Bool IsSearchableControl( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface>& _rxControl, + ::rtl::OUString* _pCurrentText ) +{ + if ( !_rxControl.is() ) + return sal_False; + + Reference< XTextComponent > xAsText( _rxControl, UNO_QUERY ); + if ( xAsText.is() ) + { + if ( _pCurrentText ) + *_pCurrentText = xAsText->getText(); + return sal_True; + } + + Reference< XListBox > xListBox( _rxControl, UNO_QUERY ); + if ( xListBox.is() ) + { + if ( _pCurrentText ) + *_pCurrentText = xListBox->getSelectedItem(); + return sal_True; + } + + Reference< XCheckBox > xCheckBox( _rxControl, UNO_QUERY ); + if ( xCheckBox.is() ) + { + if ( _pCurrentText ) + { + switch ( (TriState)xCheckBox->getState() ) + { + case STATE_NOCHECK: *_pCurrentText = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "0" )); break; + case STATE_CHECK: *_pCurrentText = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "1" )); break; + default: *_pCurrentText = ::rtl::OUString(); break; + } + } + return sal_True; + } + + return sal_False; +} + +//------------------------------------------------------------------------------ +sal_Bool FmXBoundFormFieldIterator::ShouldStepInto(const Reference< XInterface>& _rContainer) const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXBoundFormFieldIterator::ShouldStepInto" ); + if (_rContainer == m_xStartingPoint) + // would be quite stupid to step over the root .... + return sal_True; + + return Reference< XControlModel>(_rContainer, UNO_QUERY).is(); +} + +//------------------------------------------------------------------------------ +sal_Bool FmXBoundFormFieldIterator::ShouldHandleElement(const Reference< XInterface>& _rElement) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXBoundFormFieldIterator::ShouldHandleElement" ); + if (!_rElement.is()) + // NULL element + return sal_False; + + if (Reference< XForm>(_rElement, UNO_QUERY).is() || Reference< XGrid>(_rElement, UNO_QUERY).is()) + // a forms or a grid + return sal_False; + + Reference< XPropertySet> xSet(_rElement, UNO_QUERY); + if (!xSet.is() || !::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet)) + // no "BoundField" property + return sal_False; + + Any aVal( xSet->getPropertyValue(FM_PROP_BOUNDFIELD) ); + if (aVal.getValueTypeClass() != TypeClass_INTERFACE) + // void or invalid property value + return sal_False; + + return aVal.hasValue(); +} + +//------------------------------------------------------------------------------ +sal_Bool isControlList(const SdrMarkList& rMarkList) +{ + // enthaelt die liste nur Controls und mindestens ein control + sal_uInt32 nMarkCount = rMarkList.GetMarkCount(); + sal_Bool bControlList = nMarkCount != 0; + + sal_Bool bHadAnyLeafs = sal_False; + + for (sal_uInt32 i = 0; i < nMarkCount && bControlList; i++) + { + SdrObject *pObj = rMarkList.GetMark(i)->GetMarkedSdrObj(); + E3dObject* pAs3DObject = PTR_CAST(E3dObject, pObj); + // E3dObject's do not contain any 2D-objects (by definition) + // we need this extra check here : an E3dObject->IsGroupObject says "YES", but an SdrObjListIter working + // with an E3dObject doesn't give me any Nodes (E3dObject has a sub list, but no members in that list, + // cause there implementation differs from the one of "normal" SdrObject's. Unfortunally SdrObject::IsGroupObject + // doesn't check the element count of the sub list, which is simply a bug in IsGroupObject we can't fix at the moment). + // So at the end of this function bControlList would have the same value it was initialized with above : sal_True + // And this would be wrong :) + // 03.02.00 - 72529 - FS + if (!pAs3DObject) + { + if (pObj->IsGroupObject()) + { + SdrObjListIter aIter(*pObj->GetSubList()); + while (aIter.IsMore() && bControlList) + { + bControlList = FmFormInventor == aIter.Next()->GetObjInventor(); + bHadAnyLeafs = sal_True; + } + } + else + { + bHadAnyLeafs = sal_True; + bControlList = FmFormInventor == pObj->GetObjInventor(); + } + } + } + + return bControlList && bHadAnyLeafs; +} + +//------------------------------------------------------------------------ +Reference< XForm > GetForm(const Reference< XInterface>& _rxElement) +{ + Reference< XForm > xForm( _rxElement, UNO_QUERY ); + if ( xForm.is() ) + return xForm; + + Reference< XChild > xChild( _rxElement, UNO_QUERY ); + if ( xChild.is() ) + return GetForm( xChild->getParent() ); + + return Reference< XForm >(); +} + +//======================================================================== +// class FmXFormShell_Base_Disambiguation +//======================================================================== +FmXFormShell_Base_Disambiguation::FmXFormShell_Base_Disambiguation( ::osl::Mutex& _rMutex ) + :FmXFormShell_BD_BASE( _rMutex ) +{ +} + +void SAL_CALL FmXFormShell_Base_Disambiguation::disposing() +{ + WeakComponentImplHelperBase::disposing(); + // Note: + // This is a HACK. + // Normally it should be sufficient to call the "disposing" of our direct + // base class, but SUN PRO 5 does not like this and claims there is a conflict + // with the XEventListener::disposing(EventObject) of our various listener + // base classes. +} + +//======================================================================== +// class FmXFormShell +//======================================================================== +DBG_NAME(FmXFormShell); +//------------------------------------------------------------------------ +FmXFormShell::FmXFormShell( FmFormShell& _rShell, SfxViewFrame* _pViewFrame ) + :FmXFormShell_BASE(m_aMutex) + ,FmXFormShell_CFGBASE(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Office.Common/Misc")), CONFIG_MODE_DELAYED_UPDATE) + ,m_eNavigate( NavigationBarMode_NONE ) + ,m_nInvalidationEvent( 0 ) + ,m_nActivationEvent( 0 ) + ,m_pShell( &_rShell ) + ,m_pTextShell( new ::svx::FmTextControlShell( _pViewFrame ) ) + ,m_aActiveControllerFeatures( ::comphelper::getProcessServiceFactory(), this ) + ,m_aNavControllerFeatures( ::comphelper::getProcessServiceFactory(), this ) + ,m_eDocumentType( eUnknownDocumentType ) + ,m_nLockSlotInvalidation( 0 ) + ,m_bHadPropertyBrowserInDesignMode( sal_False ) + ,m_bTrackProperties( sal_True ) + ,m_bUseWizards( sal_True ) + ,m_bDatabaseBar( sal_False ) + ,m_bInActivate( sal_False ) + ,m_bSetFocus( sal_False ) + ,m_bFilterMode( sal_False ) + ,m_bChangingDesignMode( sal_False ) + ,m_bPreparedClose( sal_False ) + ,m_bFirstActivation( sal_True ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::FmXFormShell" ); + DBG_CTOR(FmXFormShell,NULL); + m_aMarkTimer.SetTimeout(100); + m_aMarkTimer.SetTimeoutHdl(LINK(this,FmXFormShell,OnTimeOut)); + + if ( _pViewFrame ) + m_xAttachedFrame = _pViewFrame->GetFrame().GetFrameInterface(); + + // to prevent deletion of this we acquire our refcounter once + ::comphelper::increment(FmXFormShell_BASE::m_refCount); + + // correct the refcounter + ::comphelper::decrement(FmXFormShell_BASE::m_refCount); + + // cache the current configuration settings we're interested in + implAdjustConfigCache(); + // and register for changes on this settings + Sequence< ::rtl::OUString > aNames(1); + aNames[0] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("FormControlPilotsEnabled")); + EnableNotification(aNames); +} + +//------------------------------------------------------------------------ +FmXFormShell::~FmXFormShell() +{ + delete m_pTextShell; + DBG_DTOR(FmXFormShell,NULL); +} + +//------------------------------------------------------------------ +Reference< XModel > FmXFormShell::getContextDocument() const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getContextDocument" ); + Reference< XModel > xModel; + + // determine the type of document we live in + try + { + Reference< XController > xController; + if ( m_xAttachedFrame.is() ) + xController = m_xAttachedFrame->getController(); + if ( xController.is() ) + xModel = xController->getModel(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return xModel; +} + +//------------------------------------------------------------------ +bool FmXFormShell::isEnhancedForm() const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::isEnhancedForm" ); + return getDocumentType() == eEnhancedForm; +} + +//------------------------------------------------------------------ +bool FmXFormShell::impl_checkDisposed() const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::impl_checkDisposed" ); + if ( !m_pShell ) + { + OSL_ENSURE( false, "FmXFormShell::impl_checkDisposed: already disposed!" ); + return true; + } + return false; +} + +//------------------------------------------------------------------ +::svxform::DocumentType FmXFormShell::getDocumentType() const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getDocumentType" ); + if ( m_eDocumentType != eUnknownDocumentType ) + return m_eDocumentType; + + // determine the type of document we live in + Reference< XModel > xModel = getContextDocument(); + if ( xModel.is() ) + m_eDocumentType = DocumentClassification::classifyDocument( xModel ); + else + { + OSL_ENSURE( sal_False, "FmXFormShell::getDocumentType: can't determine the document type!" ); + m_eDocumentType = eTextDocument; + // fallback, just to have a defined state + } + + return m_eDocumentType; +} + +//------------------------------------------------------------------ +bool FmXFormShell::IsReadonlyDoc() const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::IsReadonlyDoc" ); + if ( impl_checkDisposed() ) + return true; + + FmFormModel* pModel = m_pShell->GetFormModel(); + if ( pModel && pModel->GetObjectShell() ) + return pModel->GetObjectShell()->IsReadOnly() || pModel->GetObjectShell()->IsReadOnlyUI(); + return true; +} + +//------------------------------------------------------------------ +Any SAL_CALL FmXFormShell::queryInterface( const Type& type) throw ( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::queryInterface" ); + return FmXFormShell_BASE::queryInterface(type); +} +//------------------------------------------------------------------------------ +Sequence< Type > SAL_CALL FmXFormShell::getTypes( ) throw(RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getTypes" ); + return FmXFormShell_BASE::getTypes(); +} +//------------------------------------------------------------------------------ +Sequence< sal_Int8 > SAL_CALL FmXFormShell::getImplementationId() throw(RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getImplementationId" ); + static ::cppu::OImplementationId* pId = 0; + if (! pId) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if (! pId) + { + static ::cppu::OImplementationId aId; + pId = &aId; + } + } + return pId->getImplementationId(); +} +// EventListener +//------------------------------------------------------------------------------ +void SAL_CALL FmXFormShell::disposing(const EventObject& e) throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::disposing" ); + impl_checkDisposed(); + + if (m_xActiveController == e.Source) + { + // wird der Controller freigeben dann alles loslassen + stopListening(); + m_xActiveForm = NULL; + m_xActiveController = NULL; + m_xNavigationController = NULL; + + m_aActiveControllerFeatures.dispose(); + m_aNavControllerFeatures.dispose(); + + if ( m_pShell ) + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().InvalidateShell(*m_pShell); + } + + if (e.Source == m_xExternalViewController) + { + Reference< runtime::XFormController > xFormController( m_xExternalViewController, UNO_QUERY ); + OSL_ENSURE( xFormController.is(), "FmXFormShell::disposing: invalid external view controller!" ); + if (xFormController.is()) + xFormController->removeActivateListener((XFormControllerListener*)this); + + Reference< ::com::sun::star::lang::XComponent> xComp(m_xExternalViewController, UNO_QUERY); + if (xComp.is()) + xComp->removeEventListener((XEventListener*)(XPropertyChangeListener*)this); + + m_xExternalViewController = NULL; + m_xExternalDisplayedForm = NULL; + m_xExtViewTriggerController = NULL; + + InvalidateSlot( SID_FM_VIEW_AS_GRID, sal_False ); + } +} + +//------------------------------------------------------------------------------ +void SAL_CALL FmXFormShell::propertyChange(const PropertyChangeEvent& evt) throw(::com::sun::star::uno::RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::propertyChange" ); + if ( impl_checkDisposed() ) + return; + + if (evt.PropertyName == FM_PROP_ROWCOUNT) + { + // Das gleich folgenden Update erzwingt ein Neu-Painten der entsprechenden Slots. Wenn ich mich aber hier nicht + // in dem HauptThread der Applikation befinde (weil zum Beispiel ein Cursor gerade Datensaetze zaehlt und mir dabei + // immer diese PropertyChanges beschert), kann sich das mit en normalen Paints im HauptThread der Applikation beissen. + // (Solche Paints passieren zum Beispiel, wenn man einfach nur eine andere Applikation ueber das Office legt und wieder + // zurueckschaltet). + // Deshalb die Benutzung des SolarMutex, der sichert das ab. + ::osl::SolarMutex& rSolarSafety = Application::GetSolarMutex(); + if (rSolarSafety.tryToAcquire()) + { + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(SID_FM_RECORD_TOTAL , sal_True, sal_False); + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Update(SID_FM_RECORD_TOTAL); + rSolarSafety.release(); + } + else + { + // with the following the slot is invalidated asynchron + LockSlotInvalidation(sal_True); + InvalidateSlot(SID_FM_RECORD_TOTAL, sal_False); + LockSlotInvalidation(sal_False); + } + } + + // this may be called from a non-main-thread so invalidate the shell asynchronously + LockSlotInvalidation(sal_True); + InvalidateSlot(0, 0); // special meaning : invalidate m_pShell + LockSlotInvalidation(sal_False); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::invalidateFeatures( const ::std::vector< sal_Int32 >& _rFeatures ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::invalidateFeatures" ); + if ( impl_checkDisposed() ) + return; + + OSL_ENSURE( _rFeatures.size() > 0, "FmXFormShell::invalidateFeatures: invalid arguments!" ); + + if ( m_pShell->GetViewShell() && m_pShell->GetViewShell()->GetViewFrame() ) + { + // unfortunately, SFX requires sal_uInt16 + ::std::vector< sal_uInt16 > aSlotIds; + aSlotIds.reserve( _rFeatures.size() ); + ::std::copy( _rFeatures.begin(), + _rFeatures.end(), + ::std::insert_iterator< ::std::vector< sal_uInt16 > >( aSlotIds, aSlotIds.begin() ) + ); + + // furthermore, SFX wants a terminating 0 + aSlotIds.push_back( 0 ); + + // and, last but not least, SFX wants the ids to be sorted + ::std::sort( aSlotIds.begin(), aSlotIds.end() - 1 ); + + sal_uInt16 *pSlotIds = aSlotIds.empty() ? 0 : &(aSlotIds[0]); + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate( pSlotIds ); + } +} + +//------------------------------------------------------------------------------ +void SAL_CALL FmXFormShell::formActivated(const EventObject& rEvent) throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::formActivated" ); + if ( impl_checkDisposed() ) + return; + + Reference< runtime::XFormController > xController( rEvent.Source, UNO_QUERY_THROW ); + m_pTextShell->formActivated( xController ); + setActiveController( xController ); +} + +//------------------------------------------------------------------------------ +void SAL_CALL FmXFormShell::formDeactivated(const EventObject& rEvent) throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::formDeactivated" ); + if ( impl_checkDisposed() ) + return; + + Reference< runtime::XFormController > xController( rEvent.Source, UNO_QUERY_THROW ); + m_pTextShell->formDeactivated( xController ); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::disposing() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::disposing" ); + impl_checkDisposed(); + + FmXFormShell_BASE::disposing(); + + if ( m_pShell && !m_pShell->IsDesignMode() ) + setActiveController( NULL, sal_True ); + // do NOT save the content of the old form (the second parameter tells this) + // if we're here, then we expect that PrepareClose has been called, and thus the user + // got a chance to commit or reject any changes. So in case we're here and there + // are still uncommitted changes, the user explicitly wanted this. + // 2002-11-11 - 104702 - fs@openoffice.org + + m_pTextShell->dispose(); + + m_xAttachedFrame = NULL; + + CloseExternalFormViewer(); + + while ( m_aLoadingPages.size() ) + { + Application::RemoveUserEvent( m_aLoadingPages.front().nEventId ); + m_aLoadingPages.pop(); + } + + { + ::osl::MutexGuard aGuard(m_aInvalidationSafety); + if (m_nInvalidationEvent) + { + Application::RemoveUserEvent(m_nInvalidationEvent); + m_nInvalidationEvent = 0; + } + if ( m_nActivationEvent ) + { + Application::RemoveUserEvent( m_nActivationEvent ); + m_nActivationEvent = 0; + } + } + + { + ::osl::ClearableMutexGuard aGuard(m_aAsyncSafety); + aGuard.clear(); + + DBG_ASSERT(!m_nInvalidationEvent, "FmXFormShell::~FmXFormShell : still have an invalidation event !"); + // should habe been deleted while beeing disposed + + m_aMarkTimer.Stop(); + } + + DisableNotification(); + + RemoveElement( m_xForms ); + m_xForms.clear(); + + impl_switchActiveControllerListening( false ); + m_xActiveController = NULL; + m_xActiveForm = NULL; + + m_pShell = NULL; + m_xNavigationController = NULL; + m_xCurrentForm = NULL; + m_xLastGridFound = NULL; + m_xAttachedFrame = NULL; + m_xExternalViewController = NULL; + m_xExtViewTriggerController = NULL; + m_xExternalDisplayedForm = NULL; + m_xLastGridFound = NULL; + + InterfaceBag aEmpty; + m_aCurrentSelection.swap( aEmpty ); + + m_aActiveControllerFeatures.dispose(); + m_aNavControllerFeatures.dispose(); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::UpdateSlot( sal_Int16 _nId ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::UpdateSlot" ); + if ( impl_checkDisposed() ) + return; + + ::osl::MutexGuard aGuard(m_aInvalidationSafety); + + if ( m_nLockSlotInvalidation ) + { + OSL_ENSURE( sal_False, "FmXFormShell::UpdateSlot: cannot update if invalidation is currently locked!" ); + InvalidateSlot( _nId, sal_False ); + } + else + { + OSL_ENSURE( _nId, "FmXFormShell::UpdateSlot: can't update the complete shell!" ); + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate( _nId, sal_True, sal_True ); + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Update( _nId ); + } +} + +//------------------------------------------------------------------------------ +void FmXFormShell::InvalidateSlot( sal_Int16 nId, sal_Bool bWithId ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::InvalidateSlot" ); + if ( impl_checkDisposed() ) + return; + + ::osl::MutexGuard aGuard(m_aInvalidationSafety); + if (m_nLockSlotInvalidation) + { + m_arrInvalidSlots.Insert(nId, m_arrInvalidSlots.Count()); + BYTE nFlags = ( bWithId ? 0x01 : 0 ); + m_arrInvalidSlots_Flags.Insert(nFlags, m_arrInvalidSlots_Flags.Count()); + } + else + if (nId) + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(nId, sal_True, bWithId); + else + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().InvalidateShell(*m_pShell); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::LockSlotInvalidation(sal_Bool bLock) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::LockSlotInvalidation" ); + if ( impl_checkDisposed() ) + return; + + ::osl::MutexGuard aGuard(m_aInvalidationSafety); + DBG_ASSERT(bLock || m_nLockSlotInvalidation>0, "FmXFormShell::LockSlotInvalidation : invalid call !"); + + if (bLock) + ++m_nLockSlotInvalidation; + else if (!--m_nLockSlotInvalidation) + { + // alles, was sich waehrend der gelockten Phase angesammelt hat, (asynchron) invalidieren + if (!m_nInvalidationEvent) + m_nInvalidationEvent = Application::PostUserEvent(LINK(this, FmXFormShell, OnInvalidateSlots)); + } +} + +//------------------------------------------------------------------------------ +IMPL_LINK(FmXFormShell, OnInvalidateSlots, void*, EMPTYARG) +{ + if ( impl_checkDisposed() ) + return 0L; + + ::osl::MutexGuard aGuard(m_aInvalidationSafety); + m_nInvalidationEvent = 0; + + DBG_ASSERT(m_arrInvalidSlots.Count() == m_arrInvalidSlots_Flags.Count(), + "FmXFormShell::OnInvalidateSlots : inconsistent slot arrays !"); + BYTE nFlags; + for (sal_Int16 i=0; i<m_arrInvalidSlots.Count(); ++i) + { + nFlags = m_arrInvalidSlots_Flags[i]; + + if (m_arrInvalidSlots[i]) + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(m_arrInvalidSlots[i], sal_True, (nFlags & 0x01)); + else + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().InvalidateShell(*m_pShell); + } + + m_arrInvalidSlots.Remove(0, m_arrInvalidSlots.Count()); + m_arrInvalidSlots_Flags.Remove(0, m_arrInvalidSlots_Flags.Count()); + return 0L; +} + +//------------------------------------------------------------------------------ +void FmXFormShell::ForceUpdateSelection(sal_Bool bAllowInvalidation) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::ForceUpdateSelection" ); + if ( impl_checkDisposed() ) + return; + + if (IsSelectionUpdatePending()) + { + m_aMarkTimer.Stop(); + + // die Invalidierung der Slots, die implizit von SetSelection besorgt wird, eventuell abschalten + if (!bAllowInvalidation) + LockSlotInvalidation(sal_True); + + SetSelection(m_pShell->GetFormView()->GetMarkedObjectList()); + + if (!bAllowInvalidation) + LockSlotInvalidation(sal_False); + } +} + +//------------------------------------------------------------------------------ +PopupMenu* FmXFormShell::GetConversionMenu() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::GetConversionMenu" ); + + PopupMenu* pNewMenu = new PopupMenu(SVX_RES( RID_FMSHELL_CONVERSIONMENU )); + + ImageList aImageList( SVX_RES( RID_SVXIMGLIST_FMEXPL) ); + for ( size_t i = 0; i < SAL_N_ELEMENTS( nConvertSlots ); ++i ) + { + // das entsprechende Image dran + pNewMenu->SetItemImage(nConvertSlots[i], aImageList.GetImage(nCreateSlots[i])); + } + + return pNewMenu; +} + +//------------------------------------------------------------------------------ +bool FmXFormShell::isControlConversionSlot( sal_uInt16 nSlotId ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::isControlConversionSlot" ); + for ( size_t i = 0; i < SAL_N_ELEMENTS( nConvertSlots ); ++i ) + if (nConvertSlots[i] == nSlotId) + return true; + return false; +} + +//------------------------------------------------------------------------------ +bool FmXFormShell::executeControlConversionSlot( sal_uInt16 _nSlotId ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::executeControlConversionSlot" ); + OSL_PRECOND( canConvertCurrentSelectionToControl( _nSlotId ), "FmXFormShell::executeControlConversionSlot: illegal call!" ); + InterfaceBag::const_iterator aSelectedElement = m_aCurrentSelection.begin(); + if ( aSelectedElement == m_aCurrentSelection.end() ) + return false; + + return executeControlConversionSlot( Reference< XFormComponent >( *aSelectedElement, UNO_QUERY ), _nSlotId ); +} + +//------------------------------------------------------------------------------ +bool FmXFormShell::executeControlConversionSlot( const Reference< XFormComponent >& _rxObject, sal_uInt16 _nSlotId ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::executeControlConversionSlot" ); + if ( impl_checkDisposed() ) + return false; + + OSL_ENSURE( _rxObject.is(), "FmXFormShell::executeControlConversionSlot: invalid object!" ); + if ( !_rxObject.is() ) + return false; + + SdrPage* pPage = m_pShell->GetCurPage(); + FmFormPage* pFormPage = pPage ? dynamic_cast< FmFormPage* >( pPage ) : NULL; + OSL_ENSURE( pFormPage, "FmXFormShell::executeControlConversionSlot: no current (form) page!" ); + if ( !pFormPage ) + return false; + + OSL_ENSURE( isSolelySelected( _rxObject ), + "FmXFormShell::executeControlConversionSlot: hmm ... shouldn't this parameter be redundant?" ); + + for ( size_t lookupSlot = 0; lookupSlot < SAL_N_ELEMENTS( nConvertSlots ); ++lookupSlot ) + { + if (nConvertSlots[lookupSlot] == _nSlotId) + { + Reference< XInterface > xNormalizedObject( _rxObject, UNO_QUERY ); + + FmFormObj* pFormObject = NULL; + SdrObjListIter aPageIter( *pFormPage ); + while ( aPageIter.IsMore() ) + { + SdrObject* pCurrent = aPageIter.Next(); + pFormObject = FmFormObj::GetFormObject( pCurrent ); + if ( !pFormObject ) + continue; + + Reference< XInterface > xCurrentNormalized( pFormObject->GetUnoControlModel(), UNO_QUERY ); + if ( xCurrentNormalized.get() == xNormalizedObject.get() ) + break; + + pFormObject = NULL; + } + + if ( !pFormObject ) + return false; + + ::rtl::OUString sNewName( getServiceNameByControlType( nObjectTypes[ lookupSlot ] ) ); + Reference< XControlModel> xNewModel( ::comphelper::getProcessServiceFactory()->createInstance( sNewName ), UNO_QUERY ); + if (!xNewModel.is()) + return false; + + Reference< XControlModel> xOldModel( pFormObject->GetUnoControlModel() ); + Reference< XServiceInfo> xModelInfo(xOldModel, UNO_QUERY); + + // Properties uebertragen + Reference< XPropertySet> xOldSet(xOldModel, UNO_QUERY); + Reference< XPropertySet> xNewSet(xNewModel, UNO_QUERY); + + + Locale aNewLanguage = Application::GetSettings().GetUILocale(); + TransferFormComponentProperties(xOldSet, xNewSet, aNewLanguage); + + Sequence< ::com::sun::star::script::ScriptEventDescriptor> aOldScripts; + Reference< XChild> xChild(xOldModel, UNO_QUERY); + if (xChild.is()) + { + Reference< XIndexAccess> xParent(xChild->getParent(), UNO_QUERY); + + // remember old script events + Reference< ::com::sun::star::script::XEventAttacherManager> xEvManager(xChild->getParent(), UNO_QUERY); + if (xParent.is() && xEvManager.is()) + { + sal_Int32 nIndex = getElementPos(xParent, xOldModel); + if (nIndex>=0 && nIndex<xParent->getCount()) + aOldScripts = xEvManager->getScriptEvents(nIndex); + } + + // replace the mdoel within the parent container + Reference< XIndexContainer> xIndexParent(xChild->getParent(), UNO_QUERY); + if (xIndexParent.is()) + { + // the form container works with FormComponents + Reference< XFormComponent> xComponent(xNewModel, UNO_QUERY); + DBG_ASSERT(xComponent.is(), "FmXFormShell::executeControlConversionSlot: the new model is no form component !"); + Any aNewModel(makeAny(xComponent)); + try + { + + sal_Int32 nIndex = getElementPos(xParent, xOldModel); + if (nIndex>=0 && nIndex<xParent->getCount()) + xIndexParent->replaceByIndex(nIndex, aNewModel); + else + { + DBG_ERROR("FmXFormShell::executeControlConversionSlot: could not replace the model !"); + Reference< ::com::sun::star::lang::XComponent> xNewComponent(xNewModel, UNO_QUERY); + if (xNewComponent.is()) + xNewComponent->dispose(); + return false; + } + } + catch(Exception&) + { + DBG_ERROR("FmXFormShell::executeControlConversionSlot: could not replace the model !"); + Reference< ::com::sun::star::lang::XComponent> xNewComponent(xNewModel, UNO_QUERY); + if (xNewComponent.is()) + xNewComponent->dispose(); + return false; + } + + } + } + + // special handling for the LabelControl-property : can only be set when the model is placed + // within the forms hierarchy + if (::comphelper::hasProperty(FM_PROP_CONTROLLABEL, xOldSet) && ::comphelper::hasProperty(FM_PROP_CONTROLLABEL, xNewSet)) + { + try + { + xNewSet->setPropertyValue(FM_PROP_CONTROLLABEL, xOldSet->getPropertyValue(FM_PROP_CONTROLLABEL)); + } + catch(Exception&) + { + } + + } + + // neues Model setzen + pFormObject->SetChanged(); + pFormObject->SetUnoControlModel(xNewModel); + + // transfer script events + // (do this _after_ SetUnoControlModel as we need the new (implicitly created) control) + if (aOldScripts.getLength()) + { + // das Control zum Model suchen + Reference< XControlContainer > xControlContainer( getControlContainerForView() ); + + Sequence< Reference< XControl> > aControls( xControlContainer->getControls() ); + const Reference< XControl>* pControls = aControls.getConstArray(); + + sal_uInt32 nLen = aControls.getLength(); + Reference< XControl> xControl; + for (sal_uInt32 i=0 ; i<nLen; ++i) + { + if (pControls[i]->getModel() == xNewModel) + { + xControl = pControls[i]; + break; + } + } + TransferEventScripts(xNewModel, xControl, aOldScripts); + } + + // transfer value bindings, if possible + { + Reference< XBindableValue > xOldBindable( xOldModel, UNO_QUERY ); + Reference< XBindableValue > xNewBindable( xNewModel, UNO_QUERY ); + if ( xOldBindable.is() ) + { + try + { + if ( xNewBindable.is() ) + xNewBindable->setValueBinding( xOldBindable->getValueBinding() ); + xOldBindable->setValueBinding( NULL ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + } + // same for list entry sources + { + Reference< XListEntrySink > xOldSink( xOldModel, UNO_QUERY ); + Reference< XListEntrySink > xNewSink( xNewModel, UNO_QUERY ); + if ( xOldSink.is() ) + { + try + { + if ( xNewSink.is() ) + xNewSink->setListEntrySource( xOldSink->getListEntrySource() ); + xOldSink->setListEntrySource( NULL ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + } + + // create an undo action + FmFormModel* pModel = m_pShell->GetFormModel(); + DBG_ASSERT(pModel != NULL, "FmXFormShell::executeControlConversionSlot: my shell has no model !"); + if (pModel && pModel->IsUndoEnabled() ) + { + pModel->AddUndo(new FmUndoModelReplaceAction(*pModel, pFormObject, xOldModel)); + } + else + { + FmUndoModelReplaceAction::DisposeElement( xOldModel ); + } + + return true; + } + } + return false; +} + +//------------------------------------------------------------------------------ +bool FmXFormShell::canConvertCurrentSelectionToControl( sal_Int16 nConversionSlot ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::canConvertCurrentSelectionToControl" ); + if ( m_aCurrentSelection.empty() ) + return false; + + InterfaceBag::const_iterator aCheck = m_aCurrentSelection.begin(); + Reference< XServiceInfo > xElementInfo( *aCheck, UNO_QUERY ); + if ( !xElementInfo.is() ) + // no service info -> cannot determine this + return false; + + if ( ++aCheck != m_aCurrentSelection.end() ) + // more than one element + return false; + + if ( Reference< XForm >::query( xElementInfo ).is() ) + // it's a form + return false; + + sal_Int16 nObjectType = getControlTypeByObject( xElementInfo ); + + if ( ( OBJ_FM_HIDDEN == nObjectType ) + || ( OBJ_FM_CONTROL == nObjectType ) + || ( OBJ_FM_GRID == nObjectType ) + ) + return false; // those types cannot be converted + + DBG_ASSERT(SAL_N_ELEMENTS(nConvertSlots) == SAL_N_ELEMENTS(nObjectTypes), + "FmXFormShell::canConvertCurrentSelectionToControl: nConvertSlots & nObjectTypes must have the same size !"); + + for ( size_t i = 0; i < SAL_N_ELEMENTS( nConvertSlots ); ++i ) + if (nConvertSlots[i] == nConversionSlot) + return nObjectTypes[i] != nObjectType; + + return sal_True; // all other slots: assume "yes" +} + +//------------------------------------------------------------------------------ +void FmXFormShell::checkControlConversionSlotsForCurrentSelection( Menu& rMenu ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::checkControlConversionSlotsForCurrentSelection" ); + for (sal_Int16 i=0; i<rMenu.GetItemCount(); ++i) + // der Context ist schon von einem Typ, der dem Eitnrag entspricht -> disable + rMenu.EnableItem( rMenu.GetItemId(i), canConvertCurrentSelectionToControl( rMenu.GetItemId( i ) ) ); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::LoopGrids(sal_Int16 nWhat) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::LoopGrids" ); + if ( impl_checkDisposed() ) + return; + + Reference< XIndexContainer> xControlModels(m_xActiveForm, UNO_QUERY); + if (xControlModels.is()) + { + for (sal_Int16 i=0; i<xControlModels->getCount(); ++i) + { + Reference< XPropertySet> xModelSet; + xControlModels->getByIndex(i) >>= xModelSet; + if (!xModelSet.is()) + continue; + + if (!::comphelper::hasProperty(FM_PROP_CLASSID, xModelSet)) + continue; + sal_Int16 nClassId = ::comphelper::getINT16(xModelSet->getPropertyValue(FM_PROP_CLASSID)); + if (FormComponentType::GRIDCONTROL != nClassId) + continue; + + if (!::comphelper::hasProperty(FM_PROP_CURSORCOLOR, xModelSet) || !::comphelper::hasProperty(FM_PROP_ALWAYSSHOWCURSOR, xModelSet) || !::comphelper::hasProperty(FM_PROP_DISPLAYSYNCHRON, xModelSet)) + continue; + + switch (nWhat & GA_SYNC_MASK) + { + case GA_DISABLE_SYNC: + { + sal_Bool bB(sal_False); + xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, Any(&bB,getBooleanCppuType())); + } + break; + case GA_FORCE_SYNC: + { + Any aOldVal( xModelSet->getPropertyValue(FM_PROP_DISPLAYSYNCHRON) ); + sal_Bool bB(sal_True); + xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, Any(&bB,getBooleanCppuType())); + xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, aOldVal); + } + break; + case GA_ENABLE_SYNC: + { + sal_Bool bB(sal_True); + xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, Any(&bB,getBooleanCppuType())); + } + break; + } + + if (nWhat & GA_DISABLE_ROCTRLR) + { + sal_Bool bB(sal_False); + xModelSet->setPropertyValue(FM_PROP_ALWAYSSHOWCURSOR, Any(&bB,getBooleanCppuType())); + Reference< XPropertyState> xModelPropState(xModelSet, UNO_QUERY); + if (xModelPropState.is()) + xModelPropState->setPropertyToDefault(FM_PROP_CURSORCOLOR); + else + xModelSet->setPropertyValue(FM_PROP_CURSORCOLOR, Any()); // this should be the default + } + else if (nWhat & GA_ENABLE_ROCTRLR) + { + sal_Bool bB(sal_True); + xModelSet->setPropertyValue(FM_PROP_ALWAYSSHOWCURSOR, Any(&bB,getBooleanCppuType())); + xModelSet->setPropertyValue(FM_PROP_CURSORCOLOR, makeAny(sal_Int32(COL_LIGHTRED))); + } + } + } +} + +//------------------------------------------------------------------------------ +Reference< XControlContainer > FmXFormShell::getControlContainerForView() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getControlContainerForView" ); + if ( impl_checkDisposed() ) + return NULL; + + SdrPageView* pPageView = NULL; + if ( m_pShell && m_pShell->GetFormView() ) + pPageView = m_pShell->GetFormView()->GetSdrPageView(); + + Reference< XControlContainer> xControlContainer; + if ( pPageView ) + xControlContainer = pPageView->GetPageWindow(0)->GetControlContainer(); + + return xControlContainer; +} + +//------------------------------------------------------------------------------ +void FmXFormShell::ExecuteTabOrderDialog( const Reference< XTabControllerModel >& _rxForForm ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::ExecuteTabOrderDialog" ); + if ( impl_checkDisposed() ) + return; + + OSL_PRECOND( _rxForForm.is(), "FmXFormShell::ExecuteTabOrderDialog: invalid tabbing model!" ); + if ( !_rxForForm.is() ) + return; + + try + { + Sequence< Any > aDialogArgs( 3 ); + aDialogArgs[0] <<= NamedValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TabbingModel" ) ), + makeAny( _rxForForm ) + ); + aDialogArgs[1] <<= NamedValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ControlContext" ) ), + makeAny( getControlContainerForView() ) + ); + + Reference< XWindow > xParentWindow; + if ( m_pShell->GetViewShell() && m_pShell->GetViewShell()->GetViewFrame() ) + xParentWindow = VCLUnoHelper::GetInterface ( &m_pShell->GetViewShell()->GetViewFrame()->GetWindow() ); + aDialogArgs[2] <<= NamedValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ParentWindow" ) ), + makeAny( xParentWindow ) + ); + + Reference< dialogs::XExecutableDialog > xDialog( + ::comphelper::getProcessServiceFactory()->createInstanceWithArguments( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.form.ui.TabOrderDialog" ) ), + aDialogArgs + ), + UNO_QUERY + ); + OSL_ENSURE( xDialog.is(), "FmXFormShell::ExecuteTabOrderDialog: could not create the dialog!" ); + + if ( xDialog.is() ) + xDialog->execute(); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FmXFormShell::ExecuteTabOrderDialog: caught an exception!" ); + } +} + +//------------------------------------------------------------------------------ +void FmXFormShell::ExecuteSearch() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::ExecuteSearch" ); + if ( impl_checkDisposed() ) + return; + + // eine Sammlung aller (logischen) Formulare + FmFormArray aEmpty; + m_aSearchForms.swap( aEmpty ); + ::std::vector< String > aContextNames; + impl_collectFormSearchContexts_nothrow( m_pShell->GetCurPage()->GetForms(), ::rtl::OUString(), m_aSearchForms, aContextNames ); + OSL_POSTCOND( m_aSearchForms.size() == aContextNames.size(), + "FmXFormShell::ExecuteSearch: nonsense!" ); + if ( m_aSearchForms.size() != aContextNames.size() ) + return; + + // filter out the forms which do not contain valid controls at all + { + FmFormArray aValidForms; + ::std::vector< String > aValidContexts; + FmFormArray::const_iterator form = m_aSearchForms.begin(); + ::std::vector< String >::const_iterator contextName = aContextNames.begin(); + for ( ; form != m_aSearchForms.end(); ++form, ++contextName ) + { + FmSearchContext aTestContext; + aTestContext.nContext = static_cast< sal_Int16 >( form - m_aSearchForms.begin() ); + sal_uInt32 nValidControls = OnSearchContextRequest( &aTestContext ); + if ( nValidControls > 0 ) + { + aValidForms.push_back( *form ); + aValidContexts.push_back( *contextName ); + } + } + + m_aSearchForms.swap( aValidForms ); + aContextNames.swap( aValidContexts ); + } + + if (m_aSearchForms.size() == 0) + { // es gibt keine Controls, die alle Bedingungen fuer eine Suche erfuellen + ErrorBox(NULL, WB_OK, SVX_RESSTR(RID_STR_NODATACONTROLS)).Execute(); + return; + } + + // jetzt brauche ich noch einen 'initial context' + sal_Int16 nInitialContext = 0; + Reference< XForm> xActiveForm( getActiveForm()); + for ( size_t i=0; i<m_aSearchForms.size(); ++i ) + { + if (m_aSearchForms.at(i) == xActiveForm) + { + nInitialContext = (sal_Int16)i; + break; + } + } + + // wenn der Dialog initial den Text des aktiven Controls anbieten soll, muss dieses ein XTextComponent-Interface habe, + // ausserdem macht das nur Sinn, wenn das aktuelle Feld auch an ein Tabellen- (oder was-auch-immer-)Feld gebunden ist + UniString strActiveField; + UniString strInitialText; + // ... das bekomme ich von meinem FormController + DBG_ASSERT(m_xActiveController.is(), "FmXFormShell::ExecuteSearch : no active controller !"); + Reference< XControl> xActiveControl( m_xActiveController->getCurrentControl()); + if (xActiveControl.is()) + { + // das Control kann mir sein Model sagen ... + Reference< XControlModel> xActiveModel( xActiveControl->getModel()); + DBG_ASSERT(xActiveModel.is(), "FmXFormShell::ExecuteSearch : active control has no model !"); + + // das Model frage ich nach der ControlSource-Eigenschaft ... + Reference< XPropertySet> xProperties(xActiveControl->getModel(), UNO_QUERY); + if (::comphelper::hasProperty(FM_PROP_CONTROLSOURCE, xProperties) && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xProperties)) + { + Reference< XPropertySet> xField; + xProperties->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField; + if (xField.is()) // (nur wenn das Ding wirklich gebunden ist) + { + // und das Control selber nach einem TextComponent-Interface (damit ich mir dort den Text abholen kann) + Reference< XTextComponent> xText(xActiveControl, UNO_QUERY); + if (xText.is()) + { + strActiveField = getLabelName(xProperties).getStr(); + strInitialText = xText->getText().getStr(); + } + } + } + else + { + // das Control selber hat keine ControlSource, aber vielleicht ist es ein GridControl + Reference< XGrid> xGrid(xActiveControl, UNO_QUERY); + if (xGrid.is()) + { + // fuer strActiveField brauche ich die die ControlSource der Column, dafuer den Columns-Container, dafuer die + // GridPeer + Reference< XGridPeer> xGridPeer(xActiveControl->getPeer(), UNO_QUERY); + Reference< XIndexAccess> xColumns; + if (xGridPeer.is()) + xColumns = Reference< XIndexAccess>(xGridPeer->getColumns(),UNO_QUERY); + + sal_Int16 nViewCol = xGrid->getCurrentColumnPosition(); + sal_Int16 nModelCol = GridView2ModelPos(xColumns, nViewCol); + Reference< XPropertySet> xCurrentCol; + if(xColumns.is()) + xColumns->getByIndex(nModelCol) >>= xCurrentCol; + if (xCurrentCol.is()) + strActiveField = ::comphelper::getString(xCurrentCol->getPropertyValue(FM_PROP_LABEL)).getStr(); + + // the text fo the current column + Reference< XIndexAccess> xColControls(xGridPeer, UNO_QUERY); + Reference< XInterface> xCurControl; + xColControls->getByIndex(nViewCol) >>= xCurControl; + ::rtl::OUString sInitialText; + if (IsSearchableControl(xCurControl, &sInitialText)) + strInitialText = sInitialText.getStr(); + } + } + } + + // um eventuelle GridControls, die ich kenne, kuemmern + LoopGrids(GA_DISABLE_SYNC /*| GA_ENABLE_ROCTRLR*/); + + // jetzt bin ich reif fuer den Dialog + // wenn die potentiellen Deadlocks, die durch die Benutzung des Solar-Mutex in MTs VCLX...-Klasen entstehen, irgendwann mal + // ausgeraeumt sind, sollte hier ein SM_USETHREAD rein, denn die Suche in einem eigenen Thread ist doch etwas fluessiger + // sollte allerdings irgendwie von dem unterliegenden Cursor abhaengig gemacht werden, DAO zum Beispiel ist nicht thread-sicher + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + AbstractFmSearchDialog* pDialog = NULL; + if ( pFact ) + pDialog = pFact->CreateFmSearchDialog( &m_pShell->GetViewShell()->GetViewFrame()->GetWindow(), strInitialText, aContextNames, nInitialContext, LINK( this, FmXFormShell, OnSearchContextRequest ) ); + DBG_ASSERT( pDialog, "FmXFormShell::ExecuteSearch: could not create the search dialog!" ); + if ( pDialog ) + { + pDialog->SetActiveField( strActiveField ); + pDialog->SetFoundHandler( LINK( this, FmXFormShell, OnFoundData ) ); + pDialog->SetCanceledNotFoundHdl( LINK( this, FmXFormShell, OnCanceledNotFound ) ); + pDialog->Execute(); + delete pDialog; + } + + // GridControls wieder restaurieren + LoopGrids(GA_ENABLE_SYNC | GA_DISABLE_ROCTRLR); + + m_pShell->GetFormView()->UnMarkAll(m_pShell->GetFormView()->GetSdrPageView()); + // da ich in OnFoundData (fals ich dort war) Controls markiert habe +} + +//------------------------------------------------------------------------------ +sal_Bool FmXFormShell::GetY2KState(sal_uInt16& n) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::GetY2KState" ); + if ( impl_checkDisposed() ) + return sal_False; + + if (m_pShell->IsDesignMode()) + // im Design-Modus (ohne aktive Controls) soll sich das Haupt-Dokument darum kuemmern + return sal_False; + + Reference< XForm> xForm( getActiveForm()); + if (!xForm.is()) + // kein aktuelles Formular (also insbesondere kein aktuelles Control) -> das Haupt-Dokument soll sich kuemmern + return sal_False; + + Reference< XRowSet> xDB(xForm, UNO_QUERY); + DBG_ASSERT(xDB.is(), "FmXFormShell::GetY2KState : current form has no dbform-interface !"); + + Reference< XNumberFormatsSupplier> xSupplier( getNumberFormats(OStaticDataAccessTools().getRowSetConnection(xDB), sal_False)); + if (xSupplier.is()) + { + Reference< XPropertySet> xSet(xSupplier->getNumberFormatSettings()); + if (xSet.is()) + { + try + { + Any aVal( xSet->getPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TwoDigitDateStart"))) ); + aVal >>= n; + return sal_True; + } + catch(Exception&) + { + } + + } + } + return sal_False; +} + +//------------------------------------------------------------------------------ +void FmXFormShell::SetY2KState(sal_uInt16 n) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::SetY2KState" ); + if ( impl_checkDisposed() ) + return; + + Reference< XForm > xActiveForm( getActiveForm()); + Reference< XRowSet > xActiveRowSet( xActiveForm, UNO_QUERY ); + if ( xActiveRowSet.is() ) + { + Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( getRowSetConnection( xActiveRowSet ), sal_False ) ); + if (xSupplier.is()) + { + Reference< XPropertySet> xSet(xSupplier->getNumberFormatSettings()); + if (xSet.is()) + { + try + { + Any aVal; + aVal <<= n; + xSet->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TwoDigitDateStart")), aVal); + } + catch(Exception&) + { + DBG_ERROR("FmXFormShell::SetY2KState: Exception occurred!"); + } + + } + return; + } + } + + // kein aktives Formular gefunden -> alle aktuell vorhandenen Formulare durchiterieren + Reference< XIndexAccess> xCurrentForms( m_xForms); + if (!xCurrentForms.is()) + { // im alive-Modus sind meine Forms nicht gesetzt, wohl aber die an der Page + if (m_pShell->GetCurPage()) + xCurrentForms = Reference< XIndexAccess>( m_pShell->GetCurPage()->GetForms( false ), UNO_QUERY ); + } + if (!xCurrentForms.is()) + return; + + ::comphelper::IndexAccessIterator aIter(xCurrentForms); + Reference< XInterface> xCurrentElement( aIter.Next()); + while (xCurrentElement.is()) + { + // ist das aktuelle Element eine DatabaseForm ? + Reference< XRowSet> xElementAsRowSet( xCurrentElement, UNO_QUERY ); + if ( xElementAsRowSet.is() ) + { + Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( getRowSetConnection( xElementAsRowSet ), sal_False ) ); + if (!xSupplier.is()) + continue; + + Reference< XPropertySet> xSet(xSupplier->getNumberFormatSettings()); + if (xSet.is()) + { + try + { + Any aVal; + aVal <<= n; + xSet->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TwoDigitDateStart")), aVal); + } + catch(Exception&) + { + DBG_ERROR("FmXFormShell::SetY2KState: Exception occurred!"); + } + + } + } + xCurrentElement = aIter.Next(); + } +} + +//------------------------------------------------------------------------------ +void FmXFormShell::CloseExternalFormViewer() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::CloseExternalFormViewer" ); + if ( impl_checkDisposed() ) + return; + + if (!m_xExternalViewController.is()) + return; + + Reference< ::com::sun::star::frame::XFrame> xExternalViewFrame( m_xExternalViewController->getFrame()); + Reference< ::com::sun::star::frame::XDispatchProvider> xCommLink(xExternalViewFrame, UNO_QUERY); + if (!xCommLink.is()) + return; + + xExternalViewFrame->setComponent(NULL,NULL); + ::comphelper::disposeComponent(xExternalViewFrame); + m_xExternalViewController = NULL; + m_xExtViewTriggerController = NULL; + m_xExternalDisplayedForm = NULL; +} + +//------------------------------------------------------------------------------ +Reference< XResultSet> FmXFormShell::getInternalForm(const Reference< XResultSet>& _xForm) const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getInternalForm" ); + if ( impl_checkDisposed() ) + return NULL; + + Reference< runtime::XFormController> xExternalCtrlr(m_xExternalViewController, UNO_QUERY); + if (xExternalCtrlr.is() && (_xForm == xExternalCtrlr->getModel())) + { + DBG_ASSERT(m_xExternalDisplayedForm.is(), "FmXFormShell::getInternalForm : invalid external form !"); + return m_xExternalDisplayedForm; + } + return _xForm; +} + +//------------------------------------------------------------------------------ +Reference< XForm> FmXFormShell::getInternalForm(const Reference< XForm>& _xForm) const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getInternalForm" ); + if ( impl_checkDisposed() ) + return NULL; + + Reference< runtime::XFormController > xExternalCtrlr(m_xExternalViewController, UNO_QUERY); + if (xExternalCtrlr.is() && (_xForm == xExternalCtrlr->getModel())) + { + DBG_ASSERT(m_xExternalDisplayedForm.is(), "FmXFormShell::getInternalForm : invalid external form !"); + return Reference< XForm>(m_xExternalDisplayedForm, UNO_QUERY); + } + return _xForm; +} + +//------------------------------------------------------------------------ +namespace +{ + static bool lcl_isNavigationRelevant( sal_Int32 _nWhich ) + { + return ( _nWhich == SID_FM_RECORD_FIRST ) + || ( _nWhich == SID_FM_RECORD_PREV ) + || ( _nWhich == SID_FM_RECORD_NEXT ) + || ( _nWhich == SID_FM_RECORD_LAST ) + || ( _nWhich == SID_FM_RECORD_NEW ); + } +} + +//------------------------------------------------------------------------------ +bool FmXFormShell::IsFormSlotEnabled( sal_Int32 _nSlot, FeatureState* _pCompleteState ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::IsFormSlotEnabled" ); + const ::svx::ControllerFeatures& rController = + lcl_isNavigationRelevant( _nSlot ) + ? getNavControllerFeatures() + : getActiveControllerFeatures(); + + if ( !_pCompleteState ) + return rController->isEnabled( _nSlot ); + + rController->getState( _nSlot, *_pCompleteState ); + return _pCompleteState->Enabled; +} + +//------------------------------------------------------------------------------ +void FmXFormShell::ExecuteFormSlot( sal_Int32 _nSlot ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::ExecuteFormSlot" ); + const ::svx::ControllerFeatures& rController = + lcl_isNavigationRelevant( _nSlot ) + ? getNavControllerFeatures() + : getActiveControllerFeatures(); + + rController->execute( _nSlot ); + + if ( _nSlot == SID_FM_RECORD_UNDO ) + { + // if we're doing an UNDO, *and* if the affected form is the form which we also display + // as external view, then we need to reset the controls of the external form, too + if ( getInternalForm( getActiveForm() ) == m_xExternalDisplayedForm ) + { + Reference< XIndexAccess > xContainer( m_xExternalDisplayedForm, UNO_QUERY ); + if ( xContainer.is() ) + { + Reference< XReset > xReset; + for ( sal_Int32 i = 0; i < xContainer->getCount(); ++i ) + { + if ( ( xContainer->getByIndex( i ) >>= xReset ) && xReset.is() ) + { + // no resets on sub forms + Reference< XForm > xAsForm( xReset, UNO_QUERY ); + if ( !xAsForm.is() ) + xReset->reset(); + } + } + } + } + } +} + +//------------------------------------------------------------------------------ +void FmXFormShell::impl_switchActiveControllerListening( const bool _bListen ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::impl_switchActiveControllerListening" ); + Reference< XComponent> xComp( m_xActiveController, UNO_QUERY ); + if ( !xComp.is() ) + return; + + if ( _bListen ) + xComp->addEventListener( (XFormControllerListener*)this ); + else + xComp->removeEventListener( (XFormControllerListener*)this ); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::setActiveController( const Reference< runtime::XFormController >& xController, sal_Bool _bNoSaveOldContent ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::setActiveController" ); + if ( impl_checkDisposed() ) + return; + + if (m_bChangingDesignMode) + return; + DBG_ASSERT(!m_pShell->IsDesignMode(), "nur im alive mode verwenden"); + + // Ist die Routine ein zweites Mal gerufen worden, + // dann sollte der Focus nicht mehr umgesetzt werden + if (m_bInActivate) + { + m_bSetFocus = xController != m_xActiveController; + return; + } + + if (xController != m_xActiveController) + { + ::osl::ClearableMutexGuard aGuard(m_aAsyncSafety); + // switch all nav dispatchers belonging to the form of the current nav controller to 'non active' + Reference< XResultSet> xNavigationForm; + if (m_xNavigationController.is()) + xNavigationForm = Reference< XResultSet>(m_xNavigationController->getModel(), UNO_QUERY); + aGuard.clear(); + + m_bInActivate = sal_True; + + // check if the 2 controllers serve different forms + Reference< XResultSet> xOldForm; + if (m_xActiveController.is()) + xOldForm = Reference< XResultSet>(m_xActiveController->getModel(), UNO_QUERY); + Reference< XResultSet> xNewForm; + if (xController.is()) + xNewForm = Reference< XResultSet>(xController->getModel(), UNO_QUERY); + xOldForm = getInternalForm(xOldForm); + xNewForm = getInternalForm(xNewForm); + + sal_Bool bDifferentForm = ( xOldForm.get() != xNewForm.get() ); + sal_Bool bNeedSave = bDifferentForm && !_bNoSaveOldContent; + // we save the content of the old form if we move to a new form, and saving old content is allowed + + if ( m_xActiveController.is() && bNeedSave ) + { + // beim Wechsel des Controllers den Inhalt speichern, ein Commit + // wurde bereits ausgefuehrt + if ( m_aActiveControllerFeatures->commitCurrentControl() ) + { + m_bSetFocus = sal_True; + if ( m_aActiveControllerFeatures->isModifiedRow() ) + { + sal_Bool bIsNew = m_aActiveControllerFeatures->isInsertionRow(); + sal_Bool bResult = m_aActiveControllerFeatures->commitCurrentRecord(); + if ( !bResult && m_bSetFocus ) + { + // if we couldn't save the current record, set the focus back to the + // current control + Reference< XWindow > xWindow( m_xActiveController->getCurrentControl(), UNO_QUERY ); + if ( xWindow.is() ) + xWindow->setFocus(); + m_bInActivate = sal_False; + return; + } + else if ( bResult && bIsNew ) + { + Reference< XResultSet > xCursor( m_aActiveControllerFeatures->getCursor().get() ); + if ( xCursor.is() ) + { + DO_SAFE( xCursor->last(); ); + } + } + } + } + } + + stopListening(); + + impl_switchActiveControllerListening( false ); + + m_aActiveControllerFeatures.dispose(); + m_xActiveController = xController; + if ( m_xActiveController.is() ) + m_aActiveControllerFeatures.assign( m_xActiveController ); + + impl_switchActiveControllerListening( true ); + + if ( m_xActiveController.is() ) + m_xActiveForm = getInternalForm( Reference< XForm >( m_xActiveController->getModel(), UNO_QUERY ) ); + else + m_xActiveForm = NULL; + + startListening(); + + // activate all dispatchers belonging to form of the new navigation controller + xNavigationForm = NULL; + if (m_xNavigationController.is()) + xNavigationForm = Reference< XResultSet>(m_xNavigationController->getModel(), UNO_QUERY); + + m_bInActivate = sal_False; + + m_pShell->UIFeatureChanged(); + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().InvalidateShell(*m_pShell); + + InvalidateSlot(SID_FM_FILTER_NAVIGATOR_CONTROL, sal_True); + } +} + +//------------------------------------------------------------------------------ +void FmXFormShell::getCurrentSelection( InterfaceBag& /* [out] */ _rSelection ) const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getCurrentSelection" ); + _rSelection = m_aCurrentSelection; +} + +//------------------------------------------------------------------------------ +bool FmXFormShell::setCurrentSelectionFromMark( const SdrMarkList& _rMarkList ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::setCurrentSelectionFromMark" ); + m_aLastKnownMarkedControls.clear(); + + if ( ( _rMarkList.GetMarkCount() > 0 ) && isControlList( _rMarkList ) ) + collectInterfacesFromMarkList( _rMarkList, m_aLastKnownMarkedControls ); + + return setCurrentSelection( m_aLastKnownMarkedControls ); +} + +//------------------------------------------------------------------------------ +bool FmXFormShell::selectLastMarkedControls() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::selectLastMarkedControls" ); + return setCurrentSelection( m_aLastKnownMarkedControls ); +} + +//------------------------------------------------------------------------------ +bool FmXFormShell::setCurrentSelection( const InterfaceBag& _rSelection ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::setCurrentSelection" ); + if ( impl_checkDisposed() ) + return false; + + DBG_ASSERT( m_pShell->IsDesignMode(), "FmXFormShell::setCurrentSelection: only to be used in design mode!" ); + + if ( _rSelection.empty() && m_aCurrentSelection.empty() ) + // nothing to do + return false; + + if ( _rSelection.size() == m_aCurrentSelection.size() ) + { + InterfaceBag::const_iterator aNew = _rSelection.begin(); + InterfaceBag::const_iterator aOld = m_aCurrentSelection.begin(); + for ( ; aNew != _rSelection.end(); ++aNew, ++aOld ) + { + OSL_ENSURE( Reference< XInterface >( *aNew, UNO_QUERY ).get() == aNew->get(), "FmXFormShell::setCurrentSelection: new interface not normalized!" ); + OSL_ENSURE( Reference< XInterface >( *aOld, UNO_QUERY ).get() == aOld->get(), "FmXFormShell::setCurrentSelection: old interface not normalized!" ); + + if ( aNew->get() != aOld->get() ) + break; + } + + if ( aNew == _rSelection.end() ) + // both bags equal + return false; + } + + // the following is some strange code to ensure that when you have two grid controls in a document, + // only one of them can have a selected column. + // TODO: this should happen elsewhere, but not here - shouldn't it? + if ( !m_aCurrentSelection.empty() ) + { + Reference< XChild > xCur; if ( m_aCurrentSelection.size() == 1 ) xCur = xCur.query( *m_aCurrentSelection.begin() ); + Reference< XChild > xNew; if ( _rSelection.size() == 1 ) xNew = xNew.query( *_rSelection.begin() ); + + // is there nothing to be selected, or the parents differ, and the parent of the current object + // is a selection supplier, then deselect + if ( xCur.is() && ( !xNew.is() || ( xCur->getParent() != xNew->getParent() ) ) ) + { + Reference< XSelectionSupplier > xSel( xCur->getParent(), UNO_QUERY ); + if ( xSel.is() ) + xSel->select( Any() ); + } + } + + m_aCurrentSelection = _rSelection; + + // determine the form which all the selected obj�cts belong to, if any + Reference< XForm > xNewCurrentForm; + for ( InterfaceBag::const_iterator loop = m_aCurrentSelection.begin(); + loop != m_aCurrentSelection.end(); + ++loop + ) + { + Reference< XForm > xThisRoundsForm( GetForm( *loop ) ); + OSL_ENSURE( xThisRoundsForm.is(), "FmXFormShell::setCurrentSelection: *everything* should belong to a form!" ); + + if ( !xNewCurrentForm.is() ) + { // the first form we encounterd + xNewCurrentForm = xThisRoundsForm; + } + else if ( xNewCurrentForm != xThisRoundsForm ) + { // different forms -> no "current form" at all + xNewCurrentForm.clear(); + break; + } + } + + if ( !m_aCurrentSelection.empty() ) + impl_updateCurrentForm( xNewCurrentForm ); + + // ensure some slots are updated + for ( size_t i = 0; i < SAL_N_ELEMENTS( SelObjectSlotMap ); ++i ) + InvalidateSlot( SelObjectSlotMap[i], sal_False); + + return true; +} + +//------------------------------------------------------------------------------ +bool FmXFormShell::isSolelySelected( const Reference< XInterface >& _rxObject ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::isSolelySelected" ); + return ( m_aCurrentSelection.size() == 1 ) && ( *m_aCurrentSelection.begin() == _rxObject ); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::forgetCurrentForm() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::forgetCurrentForm" ); + if ( !m_xCurrentForm.is() ) + return; + + // reset ... + impl_updateCurrentForm( NULL ); + + // ... and try finding a new current form + // #i88186# / 2008-04-12 / frank.schoenheit@sun.com + impl_defaultCurrentForm_nothrow(); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::impl_updateCurrentForm( const Reference< XForm >& _rxNewCurForm ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::impl_updateCurrentForm" ); + if ( impl_checkDisposed() ) + return; + + m_xCurrentForm = _rxNewCurForm; + + // propagate to the FormPage(Impl) + FmFormPage* pPage = m_pShell->GetCurPage(); + if ( pPage ) + pPage->GetImpl().setCurForm( m_xCurrentForm ); + + // ensure the UI which depends on the current form is up-to-date + for ( size_t i = 0; i < SAL_N_ELEMENTS( DlgSlotMap ); ++i ) + InvalidateSlot( DlgSlotMap[i], sal_False ); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::startListening() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::startListening" ); + if ( impl_checkDisposed() ) + return; + + Reference< XRowSet> xDatabaseForm(m_xActiveForm, UNO_QUERY); + if (xDatabaseForm.is() && getRowSetConnection(xDatabaseForm).is()) + { + Reference< XPropertySet> xActiveFormSet(m_xActiveForm, UNO_QUERY); + if (xActiveFormSet.is()) + { + // wenn es eine Datenquelle gibt, dann den Listener aufbauen + // TODO: this is strange - shouldn't this depend on a isLoaded instead of + // a "has command value"? Finally, the command value only means that it was + // intended to be loaded, not that it actually *is* loaded + ::rtl::OUString aSource = ::comphelper::getString(xActiveFormSet->getPropertyValue(FM_PROP_COMMAND)); + if (aSource.getLength()) + { + m_bDatabaseBar = sal_True; + + xActiveFormSet->getPropertyValue(FM_PROP_NAVIGATION) >>= m_eNavigate; + + switch (m_eNavigate) + { + case NavigationBarMode_PARENT: + { + // suchen des Controllers, ueber den eine Navigation moeglich ist + Reference< XChild> xChild(m_xActiveController, UNO_QUERY); + Reference< runtime::XFormController > xParent; + while (xChild.is()) + { + xChild = Reference< XChild>(xChild->getParent(), UNO_QUERY); + xParent = Reference< runtime::XFormController >(xChild, UNO_QUERY); + Reference< XPropertySet> xParentSet; + if (xParent.is()) + xParentSet = Reference< XPropertySet>(xParent->getModel(), UNO_QUERY); + if (xParentSet.is()) + { + xParentSet->getPropertyValue(FM_PROP_NAVIGATION) >>= m_eNavigate; + if (m_eNavigate == NavigationBarMode_CURRENT) + break; + } + } + m_xNavigationController = xParent; + } + break; + + case NavigationBarMode_CURRENT: + m_xNavigationController = m_xActiveController; + break; + + default: + m_xNavigationController = NULL; + m_bDatabaseBar = sal_False; + } + + m_aNavControllerFeatures.dispose(); + if ( m_xNavigationController.is() && ( m_xNavigationController != m_xActiveController ) ) + m_aNavControllerFeatures.assign( m_xNavigationController ); + + // an dem Controller, der die Navigation regelt, wg. RecordCount lauschen + Reference< XPropertySet> xNavigationSet; + if (m_xNavigationController.is()) + { + xNavigationSet = Reference< XPropertySet>(m_xNavigationController->getModel(), UNO_QUERY); + if (xNavigationSet.is()) + xNavigationSet->addPropertyChangeListener(FM_PROP_ROWCOUNT,this); + } + return; + } + } + } + + m_eNavigate = NavigationBarMode_NONE; + m_bDatabaseBar = sal_False; + m_xNavigationController = NULL; +} + +//------------------------------------------------------------------------------ +void FmXFormShell::stopListening() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::stopListening" ); + if ( impl_checkDisposed() ) + return; + + Reference< XRowSet> xDatabaseForm(m_xActiveForm, UNO_QUERY); + if ( xDatabaseForm.is() ) + { + if (m_xNavigationController.is()) + { + Reference< XPropertySet> xSet(m_xNavigationController->getModel(), UNO_QUERY); + if (xSet.is()) + xSet->removePropertyChangeListener(FM_PROP_ROWCOUNT, this); + + } + } + + m_bDatabaseBar = sal_False; + m_eNavigate = NavigationBarMode_NONE; + m_xNavigationController = NULL; +} + +//------------------------------------------------------------------------------ +void FmXFormShell::ShowSelectionProperties( sal_Bool bShow ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::ShowSelectionProperties" ); + if ( impl_checkDisposed() ) + return; + + // if the window is already visible, only update the state + sal_Bool bHasChild = m_pShell->GetViewShell()->GetViewFrame()->HasChildWindow( SID_FM_SHOW_PROPERTIES ); + if ( bHasChild && bShow ) + UpdateSlot( SID_FM_PROPERTY_CONTROL ); + + // else toggle state + else + m_pShell->GetViewShell()->GetViewFrame()->ToggleChildWindow(SID_FM_SHOW_PROPERTIES); + + InvalidateSlot( SID_FM_PROPERTIES, sal_False ); + InvalidateSlot( SID_FM_CTL_PROPERTIES, sal_False ); +} + +//------------------------------------------------------------------------------ +IMPL_LINK(FmXFormShell, OnFoundData, FmFoundRecordInformation*, pfriWhere) +{ + if ( impl_checkDisposed() ) + return 0; + + DBG_ASSERT((pfriWhere->nContext >= 0) && (pfriWhere->nContext < (sal_Int16)m_aSearchForms.size()), + "FmXFormShell::OnFoundData : ungueltiger Kontext !"); + Reference< XForm> xForm( m_aSearchForms.at(pfriWhere->nContext)); + DBG_ASSERT(xForm.is(), "FmXFormShell::OnFoundData : ungueltige Form !"); + + Reference< XRowLocate> xCursor(xForm, UNO_QUERY); + if (!xCursor.is()) + return 0; // was soll ich da machen ? + + // zum Datensatz + try + { + xCursor->moveToBookmark(pfriWhere->aPosition); + } + catch(const SQLException&) + { + OSL_ENSURE(0,"Can position on bookmark!"); + } + + LoopGrids(GA_FORCE_SYNC); + + // und zum Feld (dazu habe ich vor dem Start des Suchens die XVclComponent-Interfaces eingesammelt) + DBG_ASSERT(pfriWhere->nFieldPos < m_arrSearchedControls.Count(), "FmXFormShell::OnFoundData : ungueltige Daten uebergeben !"); + SdrObject* pObject = m_arrSearchedControls.GetObject(pfriWhere->nFieldPos); + DBG_ASSERT(pObject != NULL, "FmXFormShell::OnFoundData : unerwartet : ungueltiges VclControl-Interface"); + + m_pShell->GetFormView()->UnMarkAll(m_pShell->GetFormView()->GetSdrPageView()); + m_pShell->GetFormView()->MarkObj(pObject, m_pShell->GetFormView()->GetSdrPageView()); + + FmFormObj* pFormObject = FmFormObj::GetFormObject( pObject ); + Reference< XControlModel > xControlModel( pFormObject ? pFormObject->GetUnoControlModel() : Reference< XControlModel >() ); + DBG_ASSERT( xControlModel.is(), "FmXFormShell::OnFoundData: invalid control!" ); + if ( !xControlModel.is() ) + return 0; + + // disable the permanent cursor for the last grid we found a record + if (m_xLastGridFound.is() && (m_xLastGridFound != xControlModel)) + { + Reference< XPropertySet> xOldSet(m_xLastGridFound, UNO_QUERY); + xOldSet->setPropertyValue(FM_PROP_ALWAYSSHOWCURSOR, makeAny( (sal_Bool)sal_False ) ); + Reference< XPropertyState> xOldSetState(xOldSet, UNO_QUERY); + if (xOldSetState.is()) + xOldSetState->setPropertyToDefault(FM_PROP_CURSORCOLOR); + else + xOldSet->setPropertyValue(FM_PROP_CURSORCOLOR, Any()); + } + + // wenn das Feld sich in einem GridControl befindet, muss ich dort noch in die entsprechende Spalte gehen + sal_Int32 nGridColumn = m_arrRelativeGridColumn.GetObject(pfriWhere->nFieldPos); + if (nGridColumn != -1) + { // dummer weise muss ich mir das Control erst wieder besorgen + Reference< XControl> xControl( impl_getControl( xControlModel, *pFormObject ) ); + Reference< XGrid> xGrid(xControl, UNO_QUERY); + DBG_ASSERT(xGrid.is(), "FmXFormShell::OnFoundData : ungueltiges Control !"); + // wenn eine der Asserts anschlaegt, habe ich beim Aufbauen von m_arrSearchedControls wohl was falsch gemacht + + // enable a permanent cursor for the grid so we can see the found text + Reference< XPropertySet> xModelSet(xControlModel, UNO_QUERY); + DBG_ASSERT(xModelSet.is(), "FmXFormShell::OnFoundData : invalid control model (no property set) !"); + xModelSet->setPropertyValue( FM_PROP_ALWAYSSHOWCURSOR, makeAny( (sal_Bool)sal_True ) ); + xModelSet->setPropertyValue( FM_PROP_CURSORCOLOR, makeAny( sal_Int32( COL_LIGHTRED ) ) ); + m_xLastGridFound = xControlModel; + + if ( xGrid.is() ) + xGrid->setCurrentColumnPosition((sal_Int16)nGridColumn); + } + + // als der Cursor neu positioniert wurde, habe ich (in positioned) meine Formularleisten-Slots invalidiert, aber das greift + // hier dummerweise nicht, da i.A. ja der (modale) Suchdialog oben ist ... also Gewalt ... + sal_uInt16 nPos = 0; + while (DatabaseSlotMap[nPos]) + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Update(DatabaseSlotMap[nPos++]); + // leider geht das Update im Gegensatz zum Invalidate nur mit einzelnen Slots) + + return 0; +} + +//------------------------------------------------------------------------------ +IMPL_LINK(FmXFormShell, OnCanceledNotFound, FmFoundRecordInformation*, pfriWhere) +{ + if ( impl_checkDisposed() ) + return 0; + + DBG_ASSERT((pfriWhere->nContext >= 0) && (pfriWhere->nContext < (sal_Int16)m_aSearchForms.size()), + "FmXFormShell::OnCanceledNotFound : ungueltiger Kontext !"); + Reference< XForm> xForm( m_aSearchForms.at(pfriWhere->nContext)); + DBG_ASSERT(xForm.is(), "FmXFormShell::OnCanceledNotFound : ungueltige Form !"); + + Reference< XRowLocate> xCursor(xForm, UNO_QUERY); + if (!xCursor.is()) + return 0; // was soll ich da machen ? + + // zum Datensatz + try + { + xCursor->moveToBookmark(pfriWhere->aPosition); + } + catch(const SQLException&) + { + OSL_ENSURE(0,"Can position on bookmark!"); + } + + + m_pShell->GetFormView()->UnMarkAll(m_pShell->GetFormView()->GetSdrPageView()); + return 0L; +} + +//------------------------------------------------------------------------------ +IMPL_LINK(FmXFormShell, OnSearchContextRequest, FmSearchContext*, pfmscContextInfo) +{ + if ( impl_checkDisposed() ) + return 0; + + DBG_ASSERT(pfmscContextInfo->nContext < (sal_Int16)m_aSearchForms.size(), "FmXFormShell::OnSearchContextRequest : invalid parameter !"); + Reference< XForm> xForm( m_aSearchForms.at(pfmscContextInfo->nContext)); + DBG_ASSERT(xForm.is(), "FmXFormShell::OnSearchContextRequest : unexpected : invalid context !"); + + Reference< XResultSet> xIter(xForm, UNO_QUERY); + DBG_ASSERT(xIter.is(), "FmXFormShell::OnSearchContextRequest : unexpected : context has no iterator !"); + + // -------------------------------------------------------------------------------------------- + // die Liste der zu involvierenden Felder zusammenstellen (sind die ControlSources aller Felder, die eine solche Eigenschaft habe) + UniString strFieldList, sFieldDisplayNames; + m_arrSearchedControls.Remove(0, m_arrSearchedControls.Count()); + m_arrRelativeGridColumn.Remove(0, m_arrRelativeGridColumn.Count()); + + // folgendes kleines Problem : Ich brauche, um gefundene Felder zu markieren, SdrObjekte. Um hier festzustellen, welche Controls + // ich in die Suche einbeziehen soll, brauche ich Controls (also XControl-Interfaces). Ich muss also ueber eines von beiden + // iterieren und mir das jeweils andere besorgen. Dummerweise gibt es keine direkte Verbindung zwischen beiden Welten (abgesehen + // von einem GetUnoControl an SdrUnoObject, das aber ein OutputDevice verlangt, womit ich nichts anfangen kann). + // Allerdings komme ich sowohl von einem Control als auch von einem SdrObject zum Model, und damit ist mir mit einer doppelten + // Schleife die Zuordnung SdrObject<->Control moeglich. + // Die Alternative zu dieser (unschoenen und sicher auch nicht ganz fixen) Loesung waere, auf das Cachen der SdrObjects zu + // verzichten, was dann aber in OnFoundData zu wesentlicher Mehrarbeit fuehren wuerde (da ich mir dort jedesmal das SdrObject + // erst besorgen muesste). Da aber OnFoundData i.d.R. oefter aufgerufen wird als ExecuteSearch, erledige ich das hier. + + Reference< XNameAccess> xValidFormFields; + Reference< XColumnsSupplier> xSupplyCols(xIter, UNO_QUERY); + DBG_ASSERT(xSupplyCols.is(), "FmXFormShell::OnSearchContextRequest : invalid cursor : no columns supplier !"); + if (xSupplyCols.is()) + xValidFormFields = xSupplyCols->getColumns(); + DBG_ASSERT(xValidFormFields.is(), "FmXFormShell::OnSearchContextRequest : form has no fields !"); + + // aktuelle(r) Page/Controller + FmFormPage* pCurrentPage = m_pShell->GetCurPage(); + DBG_ASSERT(pCurrentPage!=NULL, "FmXFormShell::OnSearchContextRequest : no page !"); + // alle Sdr-Controls dieser Seite durchsuchen ... + ::rtl::OUString sControlSource, aName; + + SdrObjListIter aPageIter( *pCurrentPage ); + while ( aPageIter.IsMore() ) + { + SdrObject* pCurrent = aPageIter.Next(); + FmFormObj* pFormObject = FmFormObj::GetFormObject( pCurrent ); + // note that in case pCurrent is a virtual object, pFormObject points to the referenced object + + if ( !pFormObject ) + continue; + + // the current object's model, in different tastes + Reference< XControlModel> xControlModel( pFormObject->GetUnoControlModel() ); + Reference< XFormComponent > xCurrentFormComponent( xControlModel, UNO_QUERY ); + DBG_ASSERT( xCurrentFormComponent.is(), "FmXFormShell::OnSearchContextRequest: invalid objects!" ); + if ( !xCurrentFormComponent.is() ) + continue; + + // does the component belong to the form which we're interested in? + if ( xCurrentFormComponent->getParent() != xForm ) + continue; + + // ... nach der ControlSource-Eigenschaft fragen + SearchableControlIterator iter( xCurrentFormComponent ); + Reference< XControl> xControl; + // das Control, das als Model xControlModel hat + // (das folgende while kann mehrmals durchlaufen werden, ohne dass das Control sich aendert, dann muss + // ich nicht jedesmal neu suchen) + + Reference< XInterface > xSearchable( iter.Next() ); + while ( xSearchable.is() ) + { + sControlSource = iter.getCurrentValue(); + if ( sControlSource.getLength() == 0 ) + { // das aktuelle Element hat keine ControlSource, also ist es ein GridControl (das ist das einzige, was + // der SearchableControlIterator noch zulaesst) + xControl = impl_getControl( xControlModel, *pFormObject ); + DBG_ASSERT(xControl.is(), "FmXFormShell::OnSearchContextRequest : didn't ::std::find a control with requested model !"); + + Reference< XGridPeer> xGridPeer; + if ( xControl.is() ) + xGridPeer.set( xControl->getPeer(), UNO_QUERY ); + do + { + if (!xGridPeer.is()) + break; + + Reference< XIndexAccess> xPeerContainer(xGridPeer, UNO_QUERY); + if (!xPeerContainer.is()) + break; + + Reference< XIndexAccess> xModelColumns(xGridPeer->getColumns(), UNO_QUERY); + DBG_ASSERT(xModelColumns.is(), "FmXFormShell::OnSearchContextRequest : there is a grid control without columns !"); + // the case 'no columns' should be indicated with an empty container, I think ... + DBG_ASSERT(xModelColumns->getCount() >= xPeerContainer->getCount(), "FmXFormShell::OnSearchContextRequest : impossible : have more view than model columns !"); + + Reference< XInterface> xCurrentColumn; + for (sal_Int16 nViewPos=0; nViewPos<xPeerContainer->getCount(); ++nViewPos) + { + xPeerContainer->getByIndex(nViewPos) >>= xCurrentColumn; + if (!xCurrentColumn.is()) + continue; + + // can we use this column control fo searching ? + if (!IsSearchableControl(xCurrentColumn)) + continue; + + sal_Int16 nModelPos = GridView2ModelPos(xModelColumns, nViewPos); + Reference< XPropertySet> xCurrentColModel; + xModelColumns->getByIndex(nModelPos) >>= xCurrentColModel; + aName = ::comphelper::getString(xCurrentColModel->getPropertyValue(FM_PROP_CONTROLSOURCE)); + // the cursor has a field matching the control source ? + if (xValidFormFields->hasByName(aName)) + { + strFieldList += aName.getStr(); + strFieldList += ';'; + + sFieldDisplayNames += ::comphelper::getString(xCurrentColModel->getPropertyValue(FM_PROP_LABEL)).getStr(); + sFieldDisplayNames += ';'; + + pfmscContextInfo->arrFields.push_back(xCurrentColumn); + + // und das SdrObjekt zum Feld + m_arrSearchedControls.C40_INSERT(SdrObject, pCurrent, m_arrSearchedControls.Count()); + // die Nummer der Spalte + m_arrRelativeGridColumn.Insert(nViewPos, m_arrRelativeGridColumn.Count()); + } + } + } while (sal_False); + } + else + { + if (sControlSource.getLength() && xValidFormFields->hasByName(sControlSource)) + { + // jetzt brauche ich das Control zum SdrObject + if (!xControl.is()) + { + xControl = impl_getControl( xControlModel, *pFormObject ); + DBG_ASSERT(xControl.is(), "FmXFormShell::OnSearchContextRequest : didn't ::std::find a control with requested model !"); + } + + if (IsSearchableControl(xControl)) + { // alle Tests ueberstanden -> in die Liste mit aufnehmen + strFieldList += sControlSource.getStr(); + strFieldList += ';'; + + // the label which should appear for the control : + sFieldDisplayNames += getLabelName(Reference< XPropertySet>(xControlModel, UNO_QUERY)).getStr(); + sFieldDisplayNames += ';'; + + // das SdrObjekt merken (beschleunigt die Behandlung in OnFoundData) + m_arrSearchedControls.C40_INSERT(SdrObject, pCurrent, m_arrSearchedControls.Count()); + + // die Nummer der Spalte (hier ein Dummy, nur fuer GridControls interesant) + m_arrRelativeGridColumn.Insert(-1, m_arrRelativeGridColumn.Count()); + + // und fuer die formatierte Suche ... + pfmscContextInfo->arrFields.push_back(Reference< XInterface>(xControl, UNO_QUERY)); + } + } + } + + xSearchable = iter.Next(); + } + } + + strFieldList.EraseTrailingChars(';'); + sFieldDisplayNames.EraseTrailingChars(';'); + + if (!pfmscContextInfo->arrFields.size()) + { + pfmscContextInfo->arrFields.clear(); + pfmscContextInfo->xCursor = NULL; + pfmscContextInfo->strUsedFields.Erase(); + return 0L; + } + + pfmscContextInfo->xCursor = xIter; + pfmscContextInfo->strUsedFields = strFieldList; + pfmscContextInfo->sFieldDisplayNames = sFieldDisplayNames; + + // 66463 - 31.05.99 - FS + // wenn der Cursor sich in einem anderen RecordMode als STANDARD befindet, ruecksetzen + Reference< XPropertySet> xCursorSet(pfmscContextInfo->xCursor, UNO_QUERY); + Reference< XResultSetUpdate> xUpdateCursor(pfmscContextInfo->xCursor, UNO_QUERY); + if (xUpdateCursor.is() && xCursorSet.is() && xCursorSet.is()) + { + if (::comphelper::getBOOL(xCursorSet->getPropertyValue(FM_PROP_ISNEW))) + xUpdateCursor->moveToCurrentRow(); + else if (::comphelper::getBOOL(xCursorSet->getPropertyValue(FM_PROP_ISMODIFIED))) + xUpdateCursor->cancelRowUpdates(); + } + + return pfmscContextInfo->arrFields.size(); +} + + // XContainerListener +//------------------------------------------------------------------------------ +void FmXFormShell::elementInserted(const ContainerEvent& evt) throw(::com::sun::star::uno::RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::elementInserted" ); + if ( impl_checkDisposed() ) + return; + + // neues Object zum lauschen + Reference< XInterface> xTemp; + evt.Element >>= xTemp; + AddElement(xTemp); + m_pShell->DetermineForms(sal_True); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::elementReplaced(const ContainerEvent& evt) throw(::com::sun::star::uno::RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::elementReplaced" ); + if ( impl_checkDisposed() ) + return; + + Reference< XInterface> xTemp; + evt.ReplacedElement >>= xTemp; + RemoveElement(xTemp); + evt.Element >>= xTemp; + AddElement(xTemp); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::elementRemoved(const ContainerEvent& evt) throw(::com::sun::star::uno::RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::elementRemoved" ); + if ( impl_checkDisposed() ) + return; + + Reference< XInterface> xTemp; + evt.Element >>= xTemp; + RemoveElement(xTemp); + m_pShell->DetermineForms(sal_True); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::UpdateForms( sal_Bool _bInvalidate ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::UpdateForms" ); + if ( impl_checkDisposed() ) + return; + + Reference< XIndexAccess > xForms; + + FmFormPage* pPage = m_pShell->GetCurPage(); + if ( pPage ) + { + if ( m_pShell->m_bDesignMode ) + xForms = xForms.query( pPage->GetForms( false ) ); + } + + if ( m_xForms != xForms ) + { + RemoveElement( m_xForms ); + m_xForms = xForms; + AddElement( m_xForms ); + } + + m_pShell->DetermineForms( _bInvalidate ); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::AddElement(const Reference< XInterface>& _xElement) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::AddElement" ); + if ( impl_checkDisposed() ) + return; + impl_AddElement_nothrow(_xElement); +} +// ----------------------------------------------------------------------------- +void FmXFormShell::impl_AddElement_nothrow(const Reference< XInterface>& Element) +{ + // am Container horchen + const Reference< XIndexContainer> xContainer(Element, UNO_QUERY); + if (xContainer.is()) + { + const sal_uInt32 nCount = xContainer->getCount(); + Reference< XInterface> xElement; + for (sal_uInt32 i = 0; i < nCount; ++i) + { + xElement.set(xContainer->getByIndex(i),UNO_QUERY); + impl_AddElement_nothrow(xElement); + } + + const Reference< XContainer> xCont(Element, UNO_QUERY); + if (xCont.is()) + xCont->addContainerListener(this); + } + + const Reference< ::com::sun::star::view::XSelectionSupplier> xSelSupplier(Element, UNO_QUERY); + if (xSelSupplier.is()) + xSelSupplier->addSelectionChangeListener(this); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::RemoveElement(const Reference< XInterface>& Element) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::RemoveElement" ); + if ( impl_checkDisposed() ) + return; + impl_RemoveElement_nothrow(Element); +} +//------------------------------------------------------------------------------ +void FmXFormShell::impl_RemoveElement_nothrow(const Reference< XInterface>& Element) +{ + const Reference< ::com::sun::star::view::XSelectionSupplier> xSelSupplier(Element, UNO_QUERY); + if (xSelSupplier.is()) + xSelSupplier->removeSelectionChangeListener(this); + + // Verbindung zu Kindern aufheben + const Reference< XIndexContainer> xContainer(Element, UNO_QUERY); + if (xContainer.is()) + { + const Reference< XContainer> xCont(Element, UNO_QUERY); + if (xCont.is()) + xCont->removeContainerListener(this); + + const sal_uInt32 nCount = xContainer->getCount(); + Reference< XInterface> xElement; + for (sal_uInt32 i = 0; i < nCount; i++) + { + xElement.set(xContainer->getByIndex(i),UNO_QUERY); + impl_RemoveElement_nothrow(xElement); + } + } + + InterfaceBag::iterator wasSelectedPos = m_aCurrentSelection.find( Element ); + if ( wasSelectedPos != m_aCurrentSelection.end() ) + m_aCurrentSelection.erase( wasSelectedPos ); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::selectionChanged(const EventObject& rEvent) throw(::com::sun::star::uno::RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::selectionChanged" ); + if ( impl_checkDisposed() ) + return; + + Reference< XSelectionSupplier > xSupplier( rEvent.Source, UNO_QUERY ); + Reference< XInterface > xSelObj( xSupplier->getSelection(), UNO_QUERY ); + // es wurde eine Selektion weggenommen, dieses kann nur durch die Shell vorgenommen werden + if ( !xSelObj.is() ) + return; + + EnableTrackProperties(sal_False); + + sal_Bool bMarkChanged = m_pShell->GetFormView()->checkUnMarkAll(rEvent.Source); + Reference< XForm > xNewForm( GetForm( rEvent.Source ) ); + + InterfaceBag aNewSelection; + aNewSelection.insert( Reference< XInterface >( xSelObj, UNO_QUERY ) ); + + if ( setCurrentSelection( aNewSelection ) && IsPropBrwOpen() ) + ShowSelectionProperties( sal_True ); + + EnableTrackProperties(sal_True); + + if ( bMarkChanged ) + m_pShell->NotifyMarkListChanged( m_pShell->GetFormView() ); +} + +//------------------------------------------------------------------------------ +IMPL_LINK(FmXFormShell, OnTimeOut, void*, /*EMPTYTAG*/) +{ + if ( impl_checkDisposed() ) + return 0; + + if (m_pShell->IsDesignMode() && m_pShell->GetFormView()) + SetSelection(m_pShell->GetFormView()->GetMarkedObjectList()); + + return 0; +} + +//------------------------------------------------------------------------ +void FmXFormShell::SetSelectionDelayed() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::SetSelectionDelayed" ); + if ( impl_checkDisposed() ) + return; + + if (m_pShell->IsDesignMode() && IsTrackPropertiesEnabled() && !m_aMarkTimer.IsActive()) + m_aMarkTimer.Start(); +} + +//------------------------------------------------------------------------ +void FmXFormShell::SetSelection(const SdrMarkList& rMarkList) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::SetSelection" ); + if ( impl_checkDisposed() ) + return; + + DetermineSelection(rMarkList); + m_pShell->NotifyMarkListChanged(m_pShell->GetFormView()); +} + +//------------------------------------------------------------------------ +void FmXFormShell::DetermineSelection(const SdrMarkList& rMarkList) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::DetermineSelection" ); + if ( setCurrentSelectionFromMark( rMarkList ) && IsPropBrwOpen() ) + ShowSelectionProperties( sal_True ); +} + +//------------------------------------------------------------------------------ +sal_Bool FmXFormShell::IsPropBrwOpen() const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::IsPropBrwOpen" ); + if ( impl_checkDisposed() ) + return sal_False; + + return( ( m_pShell->GetViewShell() && m_pShell->GetViewShell()->GetViewFrame() ) ? + m_pShell->GetViewShell()->GetViewFrame()->HasChildWindow(SID_FM_SHOW_PROPERTIES) : sal_False ); +} + +//------------------------------------------------------------------------------ +class FmXFormShell::SuspendPropertyTracking +{ +private: + FmXFormShell& m_rShell; + sal_Bool m_bEnabled; + +public: + SuspendPropertyTracking( FmXFormShell& _rShell ) + :m_rShell( _rShell ) + ,m_bEnabled( sal_False ) + { + if ( m_rShell.IsTrackPropertiesEnabled() ) + { + m_rShell.EnableTrackProperties( sal_False ); + m_bEnabled = sal_True; + } + } + + ~SuspendPropertyTracking( ) + { + if ( m_bEnabled ) // note that ( sal_False != m_bEnabled ) implies ( NULL != m_pShell ) + m_rShell.EnableTrackProperties( sal_True ); + } +}; + +//------------------------------------------------------------------------------ +void FmXFormShell::SetDesignMode(sal_Bool bDesign) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::SetDesignMode" ); + if ( impl_checkDisposed() ) + return; + + DBG_ASSERT(m_pShell->GetFormView(), "FmXFormShell::SetDesignMode : invalid call (have no shell or no view) !"); + m_bChangingDesignMode = sal_True; + + // 67506 - 15.07.99 - FS + // if we're switching off the design mode we have to force the property browser to be closed + // so it can commit it's changes _before_ we load the forms + if (!bDesign) + { + m_bHadPropertyBrowserInDesignMode = m_pShell->GetViewShell()->GetViewFrame()->HasChildWindow(SID_FM_SHOW_PROPERTIES); + if (m_bHadPropertyBrowserInDesignMode) + m_pShell->GetViewShell()->GetViewFrame()->ToggleChildWindow(SID_FM_SHOW_PROPERTIES); + } + + FmFormView* pFormView = m_pShell->GetFormView(); + if (bDesign) + { + // we are currently filtering, so stop filtering + if (m_bFilterMode) + stopFiltering(sal_False); + + // an den Objekten meiner MarkList als Listener abmelden + pFormView->GetImpl()->stopMarkListWatching(); + } + else + { + m_aMarkTimer.Stop(); + + SuspendPropertyTracking aSuspend( *this ); + pFormView->GetImpl()->saveMarkList( sal_True ); + } + + if (bDesign && m_xExternalViewController.is()) + CloseExternalFormViewer(); + + pFormView->ChangeDesignMode(bDesign); + + // Listener benachrichtigen + FmDesignModeChangedHint aChangedHint( bDesign ); + m_pShell->Broadcast(aChangedHint); + + m_pShell->m_bDesignMode = bDesign; + UpdateForms( sal_False ); + + m_pTextShell->designModeChanged( m_pShell->m_bDesignMode ); + + if (bDesign) + { + SdrMarkList aList; + { + // during changing the mark list, don't track the selected objects in the property browser + SuspendPropertyTracking aSuspend( *this ); + // restore the marks + pFormView->GetImpl()->restoreMarkList( aList ); + } + + // synchronize with the restored mark list + if ( aList.GetMarkCount() ) + SetSelection( aList ); + } + else + { + // am Model der View als Listener anmelden (damit ich mitbekomme, wenn jemand waehrend des Alive-Modus + // Controls loescht, die ich eigentlich mit saveMarkList gespeichert habe) (60343) + pFormView->GetImpl()->startMarkListWatching(); + } + + m_pShell->UIFeatureChanged(); + + // 67506 - 15.07.99 - FS + if (bDesign && m_bHadPropertyBrowserInDesignMode) + { + // The UIFeatureChanged performes an update (a check of the available features) asynchronously. + // So we can't call ShowSelectionProperties directly as the according feature isn't enabled yet. + // That's why we use an asynchron execution on the dispatcher. + // (And that's why this has to be done AFTER the UIFeatureChanged.) + m_pShell->GetViewShell()->GetViewFrame()->GetDispatcher()->Execute( SID_FM_SHOW_PROPERTY_BROWSER, SFX_CALLMODE_ASYNCHRON ); + } + m_bChangingDesignMode = sal_False; +} + +//------------------------------------------------------------------------------ +Reference< XControl> FmXFormShell::impl_getControl( const Reference< XControlModel >& i_rxModel, const FmFormObj& i_rKnownFormObj ) +{ + if ( impl_checkDisposed() ) + return NULL; + + Reference< XControl > xControl; + try + { + Reference< XControlContainer> xControlContainer( getControlContainerForView(), UNO_SET_THROW ); + + Sequence< Reference< XControl > > seqControls( xControlContainer->getControls() ); + const Reference< XControl >* pControls = seqControls.getArray(); + // ... die ich dann durchsuchen kann + for (sal_Int32 i=0; i<seqControls.getLength(); ++i) + { + xControl.set( pControls[i], UNO_SET_THROW ); + Reference< XControlModel > xCurrentModel( xControl->getModel() ); + if ( xCurrentModel == i_rxModel ) + break; + xControl.clear(); + } + + if ( !xControl.is() ) + { + // fallabck (some controls might not have been created, yet, since they were never visible so far) + Reference< XControl > xContainerControl( xControlContainer, UNO_QUERY_THROW ); + const Window* pContainerWindow = VCLUnoHelper::GetWindow( xContainerControl->getPeer() ); + ENSURE_OR_THROW( pContainerWindow, "unexpected control container implementation" ); + + const SdrView* pSdrView = m_pShell ? m_pShell->GetFormView() : NULL; + ENSURE_OR_THROW( pSdrView, "no current view" ); + + xControl.set( i_rKnownFormObj.GetUnoControl( *pSdrView, *pContainerWindow ), UNO_QUERY_THROW ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + OSL_ENSURE( xControl.is(), "FmXFormShell::impl_getControl: no control found!" ); + return xControl; +} + +//------------------------------------------------------------------------------ +void FmXFormShell::impl_collectFormSearchContexts_nothrow( const Reference< XInterface>& _rxStartingPoint, + const ::rtl::OUString& _rCurrentLevelPrefix, FmFormArray& _out_rForms, ::std::vector< String >& _out_rNames ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::impl_collectFormSearchContexts_nothrow" ); + try + { + Reference< XIndexAccess> xContainer( _rxStartingPoint, UNO_QUERY ); + if ( !xContainer.is() ) + return; + + sal_Int32 nCount( xContainer->getCount() ); + if ( nCount == 0 ) + return; + + ::rtl::OUString sCurrentFormName; + ::rtl::OUStringBuffer aNextLevelPrefix; + for ( sal_Int32 i=0; i<nCount; ++i ) + { + // is the current child a form? + Reference< XForm > xCurrentAsForm( xContainer->getByIndex(i), UNO_QUERY ); + if ( !xCurrentAsForm.is() ) + continue; + + Reference< XNamed > xNamed( xCurrentAsForm, UNO_QUERY_THROW ); + sCurrentFormName = xNamed->getName(); + + // the name of the current form + ::rtl::OUStringBuffer sCompleteCurrentName( sCurrentFormName ); + if ( _rCurrentLevelPrefix.getLength() ) + { + sCompleteCurrentName.appendAscii( " (" ); + sCompleteCurrentName.append ( _rCurrentLevelPrefix ); + sCompleteCurrentName.appendAscii( ")" ); + } + + // the prefix for the next level + aNextLevelPrefix = _rCurrentLevelPrefix; + if ( _rCurrentLevelPrefix.getLength() ) + aNextLevelPrefix.append( (sal_Unicode)'/' ); + aNextLevelPrefix.append( sCurrentFormName ); + + // remember both the form and it's "display name" + _out_rForms.push_back( xCurrentAsForm ); + _out_rNames.push_back( sCompleteCurrentName.makeStringAndClear() ); + + // und absteigen + impl_collectFormSearchContexts_nothrow( xCurrentAsForm, aNextLevelPrefix.makeStringAndClear(), _out_rForms, _out_rNames ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +//------------------------------------------------------------------------------ +void FmXFormShell::startFiltering() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::startFiltering" ); + if ( impl_checkDisposed() ) + return; + + // setting all forms in filter mode + FmXFormView* pXView = m_pShell->GetFormView()->GetImpl(); + + // if the active controller is our external one we have to use the trigger controller + Reference< XControlContainer> xContainer; + if (getActiveController() == m_xExternalViewController) + { + DBG_ASSERT(m_xExtViewTriggerController.is(), "FmXFormShell::startFiltering : inconsistent : active external controller, but noone triggered this !"); + xContainer = m_xExtViewTriggerController->getContainer(); + } + else + xContainer = getActiveController()->getContainer(); + + FmWinRecList::iterator i = pXView->findWindow(xContainer); + if (i != pXView->getWindowList().end()) + { + const ::std::vector< Reference< runtime::XFormController> >& rControllerList = (*i)->GetList(); + for (::std::vector< Reference< runtime::XFormController> >::const_iterator j = rControllerList.begin(); + j != rControllerList.end(); ++j) + { + Reference< XModeSelector> xModeSelector(*j, UNO_QUERY); + if (xModeSelector.is()) + xModeSelector->setMode( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterMode" ) ) ); + } + } + + m_bFilterMode = sal_True; + + m_pShell->UIFeatureChanged(); + SfxViewFrame* pViewFrame = m_pShell->GetViewShell()->GetViewFrame(); + pViewFrame->GetBindings().InvalidateShell( *m_pShell ); + + if ( pViewFrame->KnowsChildWindow( SID_FM_FILTER_NAVIGATOR ) + && !pViewFrame->HasChildWindow( SID_FM_FILTER_NAVIGATOR ) + ) + { + pViewFrame->ToggleChildWindow( SID_FM_FILTER_NAVIGATOR ); + } +} + +//------------------------------------------------------------------------------ +void saveFilter(const Reference< runtime::XFormController >& _rxController) +{ + Reference< XPropertySet> xFormAsSet(_rxController->getModel(), UNO_QUERY); + Reference< XPropertySet> xControllerAsSet(_rxController, UNO_QUERY); + Reference< XIndexAccess> xControllerAsIndex(_rxController, UNO_QUERY); + + // call the subcontroller + Reference< runtime::XFormController > xController; + for (sal_Int32 i = 0, nCount = xControllerAsIndex->getCount(); i < nCount; ++i) + { + xControllerAsIndex->getByIndex(i) >>= xController; + saveFilter(xController); + } + + try + { + + xFormAsSet->setPropertyValue(FM_PROP_FILTER, xControllerAsSet->getPropertyValue(FM_PROP_FILTER)); + xFormAsSet->setPropertyValue(FM_PROP_APPLYFILTER, makeAny( (sal_Bool)sal_True ) ); + } + catch (const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + +} + +//------------------------------------------------------------------------------ +void FmXFormShell::stopFiltering(sal_Bool bSave) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::stopFiltering" ); + if ( impl_checkDisposed() ) + return; + + m_bFilterMode = sal_False; + + FmXFormView* pXView = m_pShell->GetFormView()->GetImpl(); + + // if the active controller is our external one we have to use the trigger controller + Reference< XControlContainer> xContainer; + if (getActiveController() == m_xExternalViewController) + { + DBG_ASSERT(m_xExtViewTriggerController.is(), "FmXFormShell::stopFiltering : inconsistent : active external controller, but noone triggered this !"); + xContainer = m_xExtViewTriggerController->getContainer(); + } + else + xContainer = getActiveController()->getContainer(); + + FmWinRecList::iterator i = pXView->findWindow(xContainer); + if (i != pXView->getWindowList().end()) + { + const ::std::vector< Reference< runtime::XFormController > >& rControllerList = (*i)->GetList(); + ::std::vector < ::rtl::OUString > aOriginalFilters; + ::std::vector < sal_Bool > aOriginalApplyFlags; + + if (bSave) + { + for (::std::vector< Reference< runtime::XFormController > > ::const_iterator j = rControllerList.begin(); + j != rControllerList.end(); ++j) + { + if (bSave) + { // remember the current filter settings in case we're goin to reload the forms below (which may fail) + try + { + Reference< XPropertySet > xFormAsSet((*j)->getModel(), UNO_QUERY); + aOriginalFilters.push_back(::comphelper::getString(xFormAsSet->getPropertyValue(FM_PROP_FILTER))); + aOriginalApplyFlags.push_back(::comphelper::getBOOL(xFormAsSet->getPropertyValue(FM_PROP_APPLYFILTER))); + } + catch(Exception&) + { + DBG_ERROR("FmXFormShell::stopFiltering : could not get the original filter !"); + // put dummies into the arrays so the they have the right size + + if (aOriginalFilters.size() == aOriginalApplyFlags.size()) + // the first getPropertyValue failed -> use two dummies + aOriginalFilters.push_back( ::rtl::OUString() ); + aOriginalApplyFlags.push_back( sal_False ); + } + } + saveFilter(*j); + } + } + for (::std::vector< Reference< runtime::XFormController > > ::const_iterator j = rControllerList.begin(); + j != rControllerList.end(); ++j) + { + + Reference< XModeSelector> xModeSelector(*j, UNO_QUERY); + if (xModeSelector.is()) + xModeSelector->setMode( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DataMode" ) ) ); + } + if (bSave) // execute the filter + { + const ::std::vector< Reference< runtime::XFormController > > & rControllers = (*i)->GetList(); + for (::std::vector< Reference< runtime::XFormController > > ::const_iterator j = rControllers.begin(); + j != rControllers.end(); ++j) + { + Reference< XLoadable> xReload((*j)->getModel(), UNO_QUERY); + if (!xReload.is()) + continue; + Reference< XPropertySet > xFormSet(xReload, UNO_QUERY); + + try + { + xReload->reload(); + } + catch(Exception&) + { + DBG_ERROR("FmXFormShell::stopFiltering: Exception occurred!"); + } + + if (!isRowSetAlive(xFormSet)) + { // something went wrong -> restore the original state + ::rtl::OUString sOriginalFilter = aOriginalFilters[ j - rControllers.begin() ]; + sal_Bool bOriginalApplyFlag = aOriginalApplyFlags[ j - rControllers.begin() ]; + try + { + xFormSet->setPropertyValue(FM_PROP_FILTER, makeAny(sOriginalFilter)); + xFormSet->setPropertyValue(FM_PROP_APPLYFILTER, makeAny(bOriginalApplyFlag)); + xReload->reload(); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + } + } + } + + m_pShell->UIFeatureChanged(); + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().InvalidateShell(*m_pShell); +} + +//------------------------------------------------------------------------------ +void clearFilter(const Reference< runtime::XFormController >& _rxController) +{ + Reference< XPropertySet> xControllerAsSet(_rxController, UNO_QUERY); + Reference< XIndexAccess> xControllerAsIndex(_rxController, UNO_QUERY); + + // call the subcontroller + Reference< runtime::XFormController > xController; + for (sal_Int32 i = 0, nCount = xControllerAsIndex->getCount(); + i < nCount; i++) + { + xControllerAsIndex->getByIndex(i) >>= xController; + clearFilter(xController); + } + + // clear the filter + Reference< XIndexContainer> xContainer; + xControllerAsSet->getPropertyValue(FM_PROP_FILTERSUPPLIER) >>= xContainer; + if (xContainer.is()) + { + // clear the current filter + Sequence< PropertyValue> aCondition; + + // as there is always an empty row, if we have a filter: + if (xContainer->getCount()) + { + xControllerAsSet->setPropertyValue(FM_PROP_CURRENTFILTER, makeAny(sal_Int32(xContainer->getCount() - 1))); + while (xContainer->getCount() > 1) + xContainer->removeByIndex(0); + } + } +} + +//------------------------------------------------------------------------------ +void FmXFormShell::clearFilter() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::clearFilter" ); + if ( impl_checkDisposed() ) + return; + + FmXFormView* pXView = m_pShell->GetFormView()->GetImpl(); + + // if the active controller is our external one we have to use the trigger controller + Reference< XControlContainer> xContainer; + if (getActiveController() == m_xExternalViewController) + { + DBG_ASSERT(m_xExtViewTriggerController.is(), "FmXFormShell::clearFilter : inconsistent : active external controller, but noone triggered this !"); + xContainer = m_xExtViewTriggerController->getContainer(); + } + else + xContainer = getActiveController()->getContainer(); + + FmWinRecList::iterator i = pXView->findWindow(xContainer); + if (i != pXView->getWindowList().end()) + { + const ::std::vector< Reference< runtime::XFormController > > & rControllerList = (*i)->GetList(); + for (::std::vector< Reference< runtime::XFormController > > ::const_iterator j = rControllerList.begin(); + j != rControllerList.end(); ++j) + { + ::clearFilter(*j); + } + } +} + +//------------------------------------------------------------------------------ +void FmXFormShell::CreateExternalView() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::CreateExternalView" ); + if ( impl_checkDisposed() ) + return; + + DBG_ASSERT(m_xAttachedFrame.is(), "FmXFormShell::CreateExternalView : no frame !"); + + // the frame the external view is displayed in + sal_Bool bAlreadyExistent = m_xExternalViewController.is(); + Reference< ::com::sun::star::frame::XFrame> xExternalViewFrame; + ::rtl::OUString sFrameName(RTL_CONSTASCII_USTRINGPARAM("_beamer")); + sal_Int32 nSearchFlags = ::com::sun::star::frame::FrameSearchFlag::CHILDREN | ::com::sun::star::frame::FrameSearchFlag::CREATE; + + Reference< runtime::XFormController > xCurrentNavController( getNavController()); + // the creation of the "partwindow" may cause a deactivate of the document which will result in our nav controller to be set to NULL + + // _first_ check if we have any valid fields we can use for the grid view + // FS - 21.10.99 - 69219 + { + FmXBoundFormFieldIterator aModelIterator(xCurrentNavController->getModel()); + Reference< XPropertySet> xCurrentModelSet; + sal_Bool bHaveUsableControls = sal_False; + while ((xCurrentModelSet = Reference< XPropertySet>(aModelIterator.Next(), UNO_QUERY)).is()) + { + // the FmXBoundFormFieldIterator only supplies controls with a valid control source + // so we just have to check the field type + sal_Int16 nClassId = ::comphelper::getINT16(xCurrentModelSet->getPropertyValue(FM_PROP_CLASSID)); + switch (nClassId) + { + case FormComponentType::IMAGECONTROL: + case FormComponentType::CONTROL: + continue; + } + bHaveUsableControls = sal_True; + break; + } + + if (!bHaveUsableControls) + { + ErrorBox(NULL, WB_OK, SVX_RESSTR(RID_STR_NOCONTROLS_FOR_EXTERNALDISPLAY)).Execute(); + return; + } + } + + // load the component for external form views + if (!bAlreadyExistent) + { + URL aWantToDispatch; + aWantToDispatch.Complete = FMURL_COMPONENT_FORMGRIDVIEW; + + Reference< ::com::sun::star::frame::XDispatchProvider> xProv(m_xAttachedFrame, UNO_QUERY); + Reference< ::com::sun::star::frame::XDispatch> xDisp; + if (xProv.is()) + xDisp = xProv->queryDispatch(aWantToDispatch, sFrameName, nSearchFlags); + if (xDisp.is()) + { + xDisp->dispatch(aWantToDispatch, Sequence< PropertyValue>()); + } + + // with this the component should be loaded, now search the frame where it resides in + xExternalViewFrame = m_xAttachedFrame->findFrame(sFrameName, ::com::sun::star::frame::FrameSearchFlag::CHILDREN); + if (xExternalViewFrame.is()) + { + m_xExternalViewController = xExternalViewFrame->getController(); + Reference< ::com::sun::star::lang::XComponent> xComp(m_xExternalViewController, UNO_QUERY); + if (xComp.is()) + xComp->addEventListener((XEventListener*)(XPropertyChangeListener*)this); + } + } + else + { + xExternalViewFrame = m_xExternalViewController->getFrame(); + Reference< ::com::sun::star::frame::XDispatchProvider> xCommLink(xExternalViewFrame, UNO_QUERY); + + // if we display the active form we interpret the slot as "remove it" + Reference< XForm> xCurrentModel(xCurrentNavController->getModel(), UNO_QUERY); + if ((xCurrentModel == m_xExternalDisplayedForm) || (getInternalForm(xCurrentModel) == m_xExternalDisplayedForm)) + { + if ( m_xExternalViewController == getActiveController() ) + { + Reference< runtime::XFormController > xAsFormController( m_xExternalViewController, UNO_QUERY ); + ControllerFeatures aHelper( ::comphelper::getProcessServiceFactory(), xAsFormController, NULL ); + aHelper->commitCurrentControl(); + } + + Reference< runtime::XFormController > xNewController(m_xExtViewTriggerController); + CloseExternalFormViewer(); + setActiveController(xNewController); + return; + } + + URL aClearURL; + aClearURL.Complete = FMURL_GRIDVIEW_CLEARVIEW; + + Reference< ::com::sun::star::frame::XDispatch> xClear( xCommLink->queryDispatch(aClearURL, ::rtl::OUString(), 0)); + if (xClear.is()) + xClear->dispatch(aClearURL, Sequence< PropertyValue>()); + } + + // TODO: We need an interceptor at the xSupplier, which forwards all queryDispatch requests to the FormController + // instance for which this "external view" was triggered + + // get the dispatch interface of the frame so we can communicate (interceptable) with the controller + Reference< ::com::sun::star::frame::XDispatchProvider> xCommLink(xExternalViewFrame, UNO_QUERY); + + if (m_xExternalViewController.is()) + { + DBG_ASSERT(xCommLink.is(), "FmXFormShell::CreateExternalView : the component doesn't have the necessary interfaces !"); + // collect the dispatchers we will need + URL aAddColumnURL; + aAddColumnURL.Complete = FMURL_GRIDVIEW_ADDCOLUMN; + Reference< ::com::sun::star::frame::XDispatch> xAddColumnDispatch( xCommLink->queryDispatch(aAddColumnURL, ::rtl::OUString(), 0)); + URL aAttachURL; + aAttachURL.Complete = FMURL_GRIDVIEW_ATTACHTOFORM; + Reference< ::com::sun::star::frame::XDispatch> xAttachDispatch( xCommLink->queryDispatch(aAttachURL, ::rtl::OUString(), 0)); + + if (xAddColumnDispatch.is() && xAttachDispatch.is()) + { + DBG_ASSERT(xCurrentNavController.is(), "FmXFormShell::CreateExternalView : invalid call : have no nav controller !"); + // first : dispatch the descriptions for the columns to add + Sequence< Reference< XControl> > aCurrentControls(xCurrentNavController->getControls()); + + sal_Int16 nAddedColumns = 0; + + // for radio buttons we need some special structures + DECLARE_STL_USTRINGACCESS_MAP(Sequence< ::rtl::OUString>, MapUString2UstringSeq); + DECLARE_STL_ITERATORS(MapUString2UstringSeq); + DECLARE_STL_USTRINGACCESS_MAP(::rtl::OUString, FmMapUString2UString); + DECLARE_STL_USTRINGACCESS_MAP(sal_Int16, FmMapUString2Int16); + DECLARE_STL_ITERATORS(FmMapUString2Int16); + + MapUString2UstringSeq aRadioValueLists; + MapUString2UstringSeq aRadioListSources; + FmMapUString2UString aRadioControlSources; + FmMapUString2Int16 aRadioPositions; + + FmXBoundFormFieldIterator aModelIterator(xCurrentNavController->getModel()); + Reference< XPropertySet> xCurrentModelSet; + Any aCurrentBoundField; + ::rtl::OUString sColumnType,aGroupName,sControlSource; + Sequence< Property> aProps; + Reference< XPropertySet> xCurrentBoundField; + while ((xCurrentModelSet = Reference< XPropertySet>(aModelIterator.Next(), UNO_QUERY)).is()) + { + xCurrentModelSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xCurrentBoundField; + OSL_ENSURE(xCurrentModelSet.is(),"xCurrentModelSet is null!"); + // create a description of the column to be created + // first : determine it's type + + sal_Int16 nClassId = ::comphelper::getINT16(xCurrentModelSet->getPropertyValue(FM_PROP_CLASSID)); + switch (nClassId) + { + case FormComponentType::RADIOBUTTON: + { + // get the label of the button (this is the access key for our structures) + aGroupName = getLabelName(xCurrentModelSet); + + // add the reference value of the radio button to the list source sequence + Sequence< ::rtl::OUString>& aThisGroupLabels = aRadioListSources[aGroupName]; + sal_Int32 nNewSizeL = aThisGroupLabels.getLength() + 1; + aThisGroupLabels.realloc(nNewSizeL); + aThisGroupLabels.getArray()[nNewSizeL - 1] = ::comphelper::getString(xCurrentModelSet->getPropertyValue(FM_PROP_REFVALUE)); + + // add the label to the value list sequence + Sequence< ::rtl::OUString>& aThisGroupControlSources = aRadioValueLists[aGroupName]; + sal_Int32 nNewSizeC = aThisGroupControlSources.getLength() + 1; + aThisGroupControlSources.realloc(nNewSizeC); + aThisGroupControlSources.getArray()[nNewSizeC - 1] = ::comphelper::getString(xCurrentModelSet->getPropertyValue(FM_PROP_LABEL)); + + // remember the controls source of the radio group + sControlSource = ::comphelper::getString(xCurrentModelSet->getPropertyValue(FM_PROP_CONTROLSOURCE)); + if (aRadioControlSources.find(aGroupName) == aRadioControlSources.end()) + aRadioControlSources[aGroupName] = sControlSource; +#ifdef DBG_UTIL + else + DBG_ASSERT(aRadioControlSources[aGroupName] == sControlSource, + "FmXFormShell::CreateExternalView : inconsistent radio buttons detected !"); + // (radio buttons with the same name should have the same control source) +#endif + // remember the position within the columns + if (aRadioPositions.find(aGroupName) == aRadioPositions.end()) + aRadioPositions[aGroupName] = (sal_Int16)nAddedColumns; + + // any further handling is done below + } + continue; + + case FormComponentType::IMAGECONTROL: + case FormComponentType::CONTROL: + // no grid columns for these types (though they have a control source) + continue; + case FormComponentType::CHECKBOX: + sColumnType = FM_COL_CHECKBOX; break; + case FormComponentType::LISTBOX: + sColumnType = FM_COL_LISTBOX; break; + case FormComponentType::COMBOBOX: + sColumnType = FM_COL_COMBOBOX; break; + case FormComponentType::DATEFIELD: + sColumnType = FM_COL_DATEFIELD; break; + case FormComponentType::TIMEFIELD: + sColumnType = FM_COL_TIMEFIELD; break; + case FormComponentType::NUMERICFIELD: + sColumnType = FM_COL_NUMERICFIELD; break; + case FormComponentType::CURRENCYFIELD: + sColumnType = FM_COL_CURRENCYFIELD; break; + case FormComponentType::PATTERNFIELD: + sColumnType = FM_COL_PATTERNFIELD; break; + + case FormComponentType::TEXTFIELD: + { + sColumnType = FM_COL_TEXTFIELD; + // we know at least two different controls which are TextFields : the basic edit field and the formatted + // field. we distinguish them by their service name + Reference< XServiceInfo> xInfo(xCurrentModelSet, UNO_QUERY); + if (xInfo.is()) + { + sal_Int16 nObjectType = getControlTypeByObject(xInfo); + if (OBJ_FM_FORMATTEDFIELD == nObjectType) + sColumnType = FM_COL_FORMATTEDFIELD; + } + } + break; + default: + sColumnType = FM_COL_TEXTFIELD; break; + } + + const sal_Int16 nDispatchArgs = 3; + Sequence< PropertyValue> aDispatchArgs(nDispatchArgs); + PropertyValue* pDispatchArgs = aDispatchArgs.getArray(); + + // properties describing "meta data" about the column + // the type + pDispatchArgs->Name = FMARG_ADDCOL_COLUMNTYPE; + pDispatchArgs->Value <<= sColumnType; + ++pDispatchArgs; + + // the pos : append the col + pDispatchArgs->Name = FMARG_ADDCOL_COLUMNPOS; + pDispatchArgs->Value <<= nAddedColumns; + ++pDispatchArgs; + + // the properties to forward to the new column + Sequence< PropertyValue> aColumnProps(1); + PropertyValue* pColumnProps = aColumnProps.getArray(); + + // the label + pColumnProps->Name = FM_PROP_LABEL; + pColumnProps->Value <<= getLabelName(xCurrentModelSet); + ++pColumnProps; + + // for all other props : transfer them + Reference< XPropertySetInfo> xControlModelInfo( xCurrentModelSet->getPropertySetInfo()); + DBG_ASSERT(xControlModelInfo.is(), "FmXFormShell::CreateExternalView : the control model has no property info ! This will crash !"); + aProps = xControlModelInfo->getProperties(); + const Property* pProps = aProps.getConstArray(); + + // realloc the control description sequence + sal_Int32 nExistentDescs = pColumnProps - aColumnProps.getArray(); + aColumnProps.realloc(nExistentDescs + aProps.getLength()); + pColumnProps = aColumnProps.getArray() + nExistentDescs; + + for (sal_Int32 i=0; i<aProps.getLength(); ++i, ++pProps) + { + if (pProps->Name.equals(FM_PROP_LABEL)) + // already set + continue; + if (pProps->Name.equals(FM_PROP_DEFAULTCONTROL)) + // allow the column's own "default control" + continue; + if (pProps->Attributes & PropertyAttribute::READONLY) + // assume that properties which are readonly for the control are ro for the column to be created, too + continue; + + pColumnProps->Name = pProps->Name; + pColumnProps->Value = xCurrentModelSet->getPropertyValue(pProps->Name); + ++pColumnProps; + } + aColumnProps.realloc(pColumnProps - aColumnProps.getArray()); + + // columns props are a dispatch argument + pDispatchArgs->Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ColumnProperties")); // TODO : fmurl.* + pDispatchArgs->Value = makeAny(aColumnProps); + ++pDispatchArgs; + DBG_ASSERT(nDispatchArgs == (pDispatchArgs - aDispatchArgs.getConstArray()), + "FmXFormShell::CreateExternalView : forgot to adjust nDispatchArgs ?"); + + // dispatch the "add column" + xAddColumnDispatch->dispatch(aAddColumnURL, aDispatchArgs); + ++nAddedColumns; + } + + // now for the radio button handling + sal_Int16 nOffset(0); + // properties describing the "direct" column properties + const sal_Int16 nListBoxDescription = 6; + Sequence< PropertyValue> aListBoxDescription(nListBoxDescription); + for ( ConstFmMapUString2UStringIterator aCtrlSource = aRadioControlSources.begin(); + aCtrlSource != aRadioControlSources.end(); + ++aCtrlSource, ++nOffset + ) + { + + PropertyValue* pListBoxDescription = aListBoxDescription.getArray(); + // label + pListBoxDescription->Name = FM_PROP_LABEL; + pListBoxDescription->Value <<= (*aCtrlSource).first; + ++pListBoxDescription; + + // control source + pListBoxDescription->Name = FM_PROP_CONTROLSOURCE; + pListBoxDescription->Value <<= (*aCtrlSource).second; + ++pListBoxDescription; + + // bound column + pListBoxDescription->Name = FM_PROP_BOUNDCOLUMN; + pListBoxDescription->Value <<= (sal_Int16)1; + ++pListBoxDescription; + + // content type + pListBoxDescription->Name = FM_PROP_LISTSOURCETYPE; + ListSourceType eType = ListSourceType_VALUELIST; + pListBoxDescription->Value = makeAny(eType); + ++pListBoxDescription; + + // list source + MapUString2UstringSeq::const_iterator aCurrentListSource = aRadioListSources.find((*aCtrlSource).first); + DBG_ASSERT(aCurrentListSource != aRadioListSources.end(), + "FmXFormShell::CreateExternalView : inconsistent radio descriptions !"); + pListBoxDescription->Name = FM_PROP_LISTSOURCE; + pListBoxDescription->Value = makeAny((*aCurrentListSource).second); + ++pListBoxDescription; + + // value list + MapUString2UstringSeq::const_iterator aCurrentValueList = aRadioValueLists.find((*aCtrlSource).first); + DBG_ASSERT(aCurrentValueList != aRadioValueLists.end(), + "FmXFormShell::CreateExternalView : inconsistent radio descriptions !"); + pListBoxDescription->Name = FM_PROP_STRINGITEMLIST; + pListBoxDescription->Value = makeAny(((*aCurrentValueList).second)); + ++pListBoxDescription; + + DBG_ASSERT(nListBoxDescription == (pListBoxDescription - aListBoxDescription.getConstArray()), + "FmXFormShell::CreateExternalView : forgot to adjust nListBoxDescription ?"); + + // properties describing the column "meta data" + const sal_Int16 nDispatchArgs = 3; + Sequence< PropertyValue> aDispatchArgs(nDispatchArgs); + PropertyValue* pDispatchArgs = aDispatchArgs.getArray(); + + // column type : listbox + pDispatchArgs->Name = FMARG_ADDCOL_COLUMNTYPE; + ::rtl::OUString fColName = FM_COL_LISTBOX; + pDispatchArgs->Value <<= fColName; +// pDispatchArgs->Value <<= (::rtl::OUString)FM_COL_LISTBOX; + ++pDispatchArgs; + + // column position + pDispatchArgs->Name = FMARG_ADDCOL_COLUMNPOS; + FmMapUString2Int16::const_iterator aOffset = aRadioPositions.find((*aCtrlSource).first); + DBG_ASSERT(aOffset != aRadioPositions.end(), + "FmXFormShell::CreateExternalView : inconsistent radio descriptions !"); + sal_Int16 nPosition = (*aOffset).second; + nPosition = nPosition + nOffset; + // we alread inserted nOffset additinal columns .... + pDispatchArgs->Value <<= nPosition; + ++pDispatchArgs; + + // the + pDispatchArgs->Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ColumnProperties")); // TODO : fmurl.* + pDispatchArgs->Value = makeAny(aListBoxDescription); + ++pDispatchArgs; + DBG_ASSERT(nDispatchArgs == (pDispatchArgs - aDispatchArgs.getConstArray()), + "FmXFormShell::CreateExternalView : forgot to adjust nDispatchArgs ?"); + + // dispatch the "add column" + xAddColumnDispatch->dispatch(aAddColumnURL, aDispatchArgs); + ++nAddedColumns; + } + + + DBG_ASSERT(nAddedColumns > 0, "FmXFormShell::CreateExternalView : no controls (inconsistent) !"); + // we should have checked if we have any usable controls (see above). + + // "load" the "form" of the external view + PropertyValue aArg; + aArg.Name = FMARG_ATTACHTO_MASTERFORM; + Reference< XResultSet> xForm(xCurrentNavController->getModel(), UNO_QUERY); + aArg.Value <<= xForm; + + m_xExternalDisplayedForm = Reference< XResultSet>(xForm, UNO_QUERY); + // do this before dispatching the "attach" command, as the atach may result in a call to our queryDispatch (for the FormSlots) + // whichs needs the m_xExternalDisplayedForm + + xAttachDispatch->dispatch(aAttachURL, Sequence< PropertyValue>(&aArg, 1)); + + m_xExtViewTriggerController = xCurrentNavController; + + // we want to know modifications done in the external view + // if the external controller is a XFormController we can use all our default handlings for it + Reference< runtime::XFormController > xFormController( m_xExternalViewController, UNO_QUERY ); + OSL_ENSURE( xFormController.is(), "FmXFormShell::CreateExternalView:: invalid external view controller!" ); + if (xFormController.is()) + xFormController->addActivateListener((XFormControllerListener*)this); + } + } +#ifdef DBG_UTIL + else + { + DBG_ERROR("FmXFormShell::CreateExternalView : could not create the external form view !"); + } +#endif + InvalidateSlot( SID_FM_VIEW_AS_GRID, sal_False ); +} + +//------------------------------------------------------------------------ +void FmXFormShell::implAdjustConfigCache() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::implAdjustConfigCache" ); + // get (cache) the wizard usage flag + Sequence< ::rtl::OUString > aNames(1); + aNames[0] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("FormControlPilotsEnabled")); + Sequence< Any > aFlags = GetProperties(aNames); + if (1 == aFlags.getLength()) + m_bUseWizards = ::cppu::any2bool(aFlags[0]); +} + +//------------------------------------------------------------------------ +void FmXFormShell::Notify( const com::sun::star::uno::Sequence< rtl::OUString >& _rPropertyNames) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::Notify" ); + if ( impl_checkDisposed() ) + return; + + const ::rtl::OUString* pSearch = _rPropertyNames.getConstArray(); + const ::rtl::OUString* pSearchTil = pSearch + _rPropertyNames.getLength(); + for (;pSearch < pSearchTil; ++pSearch) + if (0 == pSearch->compareToAscii("FormControlPilotsEnabled")) + { + implAdjustConfigCache(); + InvalidateSlot( SID_FM_USE_WIZARDS, sal_True ); + } +} + +void FmXFormShell::Commit() +{ +} + +//------------------------------------------------------------------------ +void FmXFormShell::SetWizardUsing(sal_Bool _bUseThem) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::SetWizardUsing" ); + m_bUseWizards = _bUseThem; + + Sequence< ::rtl::OUString > aNames(1); + aNames[0] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("FormControlPilotsEnabled")); + Sequence< Any > aValues(1); + aValues[0] = ::cppu::bool2any(m_bUseWizards); + PutProperties(aNames, aValues); +} + +//------------------------------------------------------------------------ +void FmXFormShell::viewDeactivated( FmFormView& _rCurrentView, sal_Bool _bDeactivateController /* = sal_True */ ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::viewDeactivated" ); + + if ( _rCurrentView.GetImpl() && !_rCurrentView.IsDesignMode() ) + { + _rCurrentView.GetImpl()->Deactivate( _bDeactivateController ); + } + + // if we have an async load operation pending for the 0-th page for this view, + // we need to cancel this + // 103727 - 2002-09-26 - fs@openoffice.org + FmFormPage* pPage = _rCurrentView.GetCurPage(); + if ( pPage ) + { + // move all events from our queue to a new one, omit the events for the deactivated + // page + ::std::queue< FmLoadAction > aNewEvents; + while ( m_aLoadingPages.size() ) + { + FmLoadAction aAction = m_aLoadingPages.front(); + m_aLoadingPages.pop(); + if ( pPage != aAction.pPage ) + { + aNewEvents.push( aAction ); + } + else + { + Application::RemoveUserEvent( aAction.nEventId ); + } + } + m_aLoadingPages = aNewEvents; + } + + // remove callbacks at the page + if ( pPage ) + { + pPage->GetImpl().SetFormsCreationHdl( Link() ); + } + UpdateForms( sal_True ); +} + +//------------------------------------------------------------------------ +IMPL_LINK( FmXFormShell, OnFirstTimeActivation, void*, /*NOTINTERESTEDIN*/ ) +{ + if ( impl_checkDisposed() ) + return 0L; + + m_nActivationEvent = 0; + SfxObjectShell* pDocument = m_pShell->GetObjectShell(); + + if ( pDocument && !pDocument->HasName() ) + { + if ( isEnhancedForm() ) + { + // show the data navigator + if ( !m_pShell->GetViewShell()->GetViewFrame()->HasChildWindow( SID_FM_SHOW_DATANAVIGATOR ) ) + m_pShell->GetViewShell()->GetViewFrame()->ToggleChildWindow( SID_FM_SHOW_DATANAVIGATOR ); + } + } + + return 0L; +} + +//------------------------------------------------------------------------ +IMPL_LINK( FmXFormShell, OnFormsCreated, FmFormPage*, /*_pPage*/ ) +{ + UpdateForms( sal_True ); + return 0L; +} + +//------------------------------------------------------------------------ +void FmXFormShell::viewActivated( FmFormView& _rCurrentView, sal_Bool _bSyncAction /* = sal_False */ ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::viewActivated" ); + + FmFormPage* pPage = _rCurrentView.GetCurPage(); + + // activate our view if we are activated ourself + // FS - 30.06.99 - 67308 + if ( _rCurrentView.GetImpl() && !_rCurrentView.IsDesignMode() ) + { + // load forms for the page the current view belongs to + if ( pPage ) + { + if ( !pPage->GetImpl().hasEverBeenActivated() ) + loadForms( pPage, FORMS_LOAD | ( _bSyncAction ? FORMS_SYNC : FORMS_ASYNC ) ); + pPage->GetImpl().setHasBeenActivated( ); + } + + // first-time initializations for the views + if ( !_rCurrentView.GetImpl()->hasEverBeenActivated( ) ) + { + _rCurrentView.GetImpl()->onFirstViewActivation( PTR_CAST( FmFormModel, _rCurrentView.GetModel() ) ); + _rCurrentView.GetImpl()->setHasBeenActivated( ); + } + + // activate the current view + _rCurrentView.GetImpl()->Activate( _bSyncAction ); + } + + // set callbacks at the page + if ( pPage ) + { + pPage->GetImpl().SetFormsCreationHdl( LINK( this, FmXFormShell, OnFormsCreated ) ); + } + + UpdateForms( sal_True ); + + if ( !hasEverBeenActivated() ) + { + m_nActivationEvent = Application::PostUserEvent( LINK( this, FmXFormShell, OnFirstTimeActivation ) ); + setHasBeenActivated(); + } + + // find a default "current form", if there is none, yet + // #i88186# / 2008-04-12 / frank.schoenheit@sun.com + impl_defaultCurrentForm_nothrow(); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::impl_defaultCurrentForm_nothrow() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::impl_defaultCurrentForm_nothrow" ); + if ( impl_checkDisposed() ) + return; + + if ( m_xCurrentForm.is() ) + // no action required + return; + + FmFormView* pFormView = m_pShell->GetFormView(); + FmFormPage* pPage = pFormView ? pFormView->GetCurPage() : NULL; + if ( !pPage ) + return; + + try + { + Reference< XIndexAccess > xForms( pPage->GetForms( false ), UNO_QUERY ); + if ( !xForms.is() || !xForms->hasElements() ) + return; + + Reference< XForm > xNewCurrentForm( xForms->getByIndex(0), UNO_QUERY_THROW ); + impl_updateCurrentForm( xNewCurrentForm ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +//------------------------------------------------------------------------------ +void FmXFormShell::smartControlReset( const Reference< XIndexAccess >& _rxModels ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::smartControlReset" ); + if (!_rxModels.is()) + { + DBG_ERROR("FmXFormShell::smartControlReset: invalid container!"); + return; + } + + static const ::rtl::OUString sClassIdPropertyName = FM_PROP_CLASSID; + static const ::rtl::OUString sBoundFieldPropertyName = FM_PROP_BOUNDFIELD; + sal_Int32 nCount = _rxModels->getCount(); + Reference< XPropertySet > xCurrent; + Reference< XPropertySetInfo > xCurrentInfo; + Reference< XPropertySet > xBoundField; + + for (sal_Int32 i=0; i<nCount; ++i) + { + _rxModels->getByIndex(i) >>= xCurrent; + if (xCurrent.is()) + xCurrentInfo = xCurrent->getPropertySetInfo(); + else + xCurrentInfo.clear(); + if (!xCurrentInfo.is()) + continue; + + if (xCurrentInfo->hasPropertyByName(sClassIdPropertyName)) + { // it's a control model + + // check if this control is bound to a living database field + if (xCurrentInfo->hasPropertyByName(sBoundFieldPropertyName)) + xCurrent->getPropertyValue(sBoundFieldPropertyName) >>= xBoundField; + else + xBoundField.clear(); + + // reset only if it's *not* bound + bool bReset = !xBoundField.is(); + + // and additionally, check if it has an external value binding + Reference< XBindableValue > xBindable( xCurrent, UNO_QUERY ); + if ( xBindable.is() && xBindable->getValueBinding().is() ) + bReset = false; + + if ( bReset ) + { + Reference< XReset > xControlReset( xCurrent, UNO_QUERY ); + if ( xControlReset.is() ) + xControlReset->reset(); + } + } + else + { + Reference< XIndexAccess > xContainer(xCurrent, UNO_QUERY); + if (xContainer.is()) + smartControlReset(xContainer); + } + } +} + +//------------------------------------------------------------------------ +IMPL_LINK( FmXFormShell, OnLoadForms, FmFormPage*, /*_pPage*/ ) +{ + FmLoadAction aAction = m_aLoadingPages.front(); + m_aLoadingPages.pop(); + + loadForms( aAction.pPage, aAction.nFlags & ~FORMS_ASYNC ); + return 0L; +} + +//------------------------------------------------------------------------------ +namespace +{ + sal_Bool lcl_isLoadable( const Reference< XInterface >& _rxLoadable ) + { + // determines whether a form should be loaded or not + // if there is no datasource or connection there is no reason to load a form + Reference< XPropertySet > xSet( _rxLoadable, UNO_QUERY ); + if ( !xSet.is() ) + return sal_False; + try + { + Reference< XConnection > xConn; + if ( OStaticDataAccessTools().isEmbeddedInDatabase( _rxLoadable.get(), xConn ) ) + return sal_True; + + // is there already a active connection + xSet->getPropertyValue(FM_PROP_ACTIVE_CONNECTION) >>= xConn; + if ( xConn.is() ) + return sal_True; + + ::rtl::OUString sPropertyValue; + OSL_VERIFY( xSet->getPropertyValue( FM_PROP_DATASOURCE ) >>= sPropertyValue ); + if ( sPropertyValue.getLength() ) + return sal_True; + + OSL_VERIFY( xSet->getPropertyValue( FM_PROP_URL ) >>= sPropertyValue ); + if ( sPropertyValue.getLength() ) + return sal_True; + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + return sal_False; + } +} + +//------------------------------------------------------------------------ +void FmXFormShell::loadForms( FmFormPage* _pPage, const sal_uInt16 _nBehaviour /* FORMS_LOAD | FORMS_SYNC */ ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::loadForms" ); + DBG_ASSERT( ( _nBehaviour & ( FORMS_ASYNC | FORMS_UNLOAD ) ) != ( FORMS_ASYNC | FORMS_UNLOAD ), + "FmXFormShell::loadForms: async loading not supported - this will heavily fail!" ); + + if ( _nBehaviour & FORMS_ASYNC ) + { + m_aLoadingPages.push( FmLoadAction( + _pPage, + _nBehaviour, + Application::PostUserEvent( LINK( this, FmXFormShell, OnLoadForms ), _pPage ) + ) ); + return; + } + + DBG_ASSERT( _pPage, "FmXFormShell::loadForms: invalid page!" ); + if ( _pPage ) + { + // lock the undo env so the forms can change non-transient properties while loading + // (without this my doc's modified flag would be set) + FmFormModel* pModel = PTR_CAST( FmFormModel, _pPage->GetModel() ); + DBG_ASSERT( pModel, "FmXFormShell::loadForms: invalid model!" ); + if ( pModel ) + pModel->GetUndoEnv().Lock(); + + // load all forms + Reference< XIndexAccess > xForms; + xForms = xForms.query( _pPage->GetForms( false ) ); + + if ( xForms.is() ) + { + Reference< XLoadable > xForm; + sal_Bool bFormWasLoaded = sal_False; + for ( sal_Int32 j = 0, nCount = xForms->getCount(); j < nCount; ++j ) + { + xForms->getByIndex( j ) >>= xForm; + bFormWasLoaded = sal_False; + // a database form must be loaded for + try + { + if ( 0 == ( _nBehaviour & FORMS_UNLOAD ) ) + { + if ( lcl_isLoadable( xForm ) && !xForm->isLoaded() ) + xForm->load(); + } + else + { + if ( xForm->isLoaded() ) + { + bFormWasLoaded = sal_True; + xForm->unload(); + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + // reset the form if it was loaded + if ( bFormWasLoaded ) + { + Reference< XIndexAccess > xContainer( xForm, UNO_QUERY ); + DBG_ASSERT( xContainer.is(), "FmXFormShell::loadForms: the form is no container!" ); + if ( xContainer.is() ) + smartControlReset( xContainer ); + } + } + } + + if ( pModel ) + // unlock the environment + pModel->GetUndoEnv().UnLock(); + } +} + +//------------------------------------------------------------------------ +void FmXFormShell::ExecuteTextAttribute( SfxRequest& _rReq ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::ExecuteTextAttribute" ); + m_pTextShell->ExecuteTextAttribute( _rReq ); +} + +//------------------------------------------------------------------------ +void FmXFormShell::GetTextAttributeState( SfxItemSet& _rSet ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::GetTextAttributeState" ); + m_pTextShell->GetTextAttributeState( _rSet ); +} + +//------------------------------------------------------------------------ +bool FmXFormShell::IsActiveControl( bool _bCountRichTextOnly ) const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::IsActiveControl" ); + return m_pTextShell->IsActiveControl( _bCountRichTextOnly ); +} + +//------------------------------------------------------------------------ +void FmXFormShell::ForgetActiveControl() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::ForgetActiveControl" ); + m_pTextShell->ForgetActiveControl(); +} + +//------------------------------------------------------------------------ +void FmXFormShell::SetControlActivationHandler( const Link& _rHdl ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::SetControlActivationHandler" ); + m_pTextShell->SetControlActivationHandler( _rHdl ); +} +//------------------------------------------------------------------------ +void FmXFormShell::handleShowPropertiesRequest() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::handleShowPropertiesRequest" ); + if ( onlyControlsAreMarked() ) + ShowSelectionProperties( sal_True ); +} + +//------------------------------------------------------------------------ +void FmXFormShell::handleMouseButtonDown( const SdrViewEvent& _rViewEvent ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::handleMouseButtonDown" ); + // catch simple double clicks + if ( ( _rViewEvent.nMouseClicks == 2 ) && ( _rViewEvent.nMouseCode == MOUSE_LEFT ) ) + { + if ( _rViewEvent.eHit == SDRHIT_MARKEDOBJECT ) + { + if ( onlyControlsAreMarked() ) + ShowSelectionProperties( sal_True ); + } + } +} + +//------------------------------------------------------------------------------ +bool FmXFormShell::HasControlFocus() const +{ + bool bHasControlFocus = false; + + try + { + Reference< XFormController > xController( getActiveController() ); + Reference< XControl > xCurrentControl; + if ( xController.is() ) + xCurrentControl.set( xController->getCurrentControl() ); + if ( xCurrentControl.is() ) + { + Reference< XWindow2 > xPeerWindow( xCurrentControl->getPeer(), UNO_QUERY_THROW ); + bHasControlFocus = xPeerWindow->hasFocus(); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + return bHasControlFocus; +} + +//============================================================================== +//============================================================================== +SearchableControlIterator::SearchableControlIterator(Reference< XInterface> xStartingPoint) + :IndexAccessIterator(xStartingPoint) +{ +} + +//------------------------------------------------------------------------------ +sal_Bool SearchableControlIterator::ShouldHandleElement(const Reference< XInterface>& xElement) +{ + // wenn das Ding eine ControlSource und einen BoundField-Property hat + Reference< XPropertySet> xProperties(xElement, UNO_QUERY); + if (::comphelper::hasProperty(FM_PROP_CONTROLSOURCE, xProperties) && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xProperties)) + { + // und das BoundField gueltig ist + Reference< XPropertySet> xField; + xProperties->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField; + if (xField.is()) + { + // nehmen wir's + m_sCurrentValue = ::comphelper::getString(xProperties->getPropertyValue(FM_PROP_CONTROLSOURCE)); + return sal_True; + } + } + + // wenn es ein Grid-Control ist + if (::comphelper::hasProperty(FM_PROP_CLASSID, xProperties)) + { + Any aClassId( xProperties->getPropertyValue(FM_PROP_CLASSID) ); + if (::comphelper::getINT16(aClassId) == FormComponentType::GRIDCONTROL) + { + m_sCurrentValue = ::rtl::OUString(); + return sal_True; + } + } + + return sal_False; +} + +//------------------------------------------------------------------------------ +sal_Bool SearchableControlIterator::ShouldStepInto(const Reference< XInterface>& /*xContainer*/) const +{ + return sal_True; +} + +//============================================================================== +//============================================================================== + +SV_IMPL_PTRARR(StatusForwarderArray, SfxStatusForwarder*) + +SFX_IMPL_MENU_CONTROL(ControlConversionMenuController, SfxBoolItem); + +//------------------------------------------------------------------------------ +ControlConversionMenuController::ControlConversionMenuController( sal_uInt16 _nId, Menu& _rMenu, SfxBindings& _rBindings ) + :SfxMenuControl( _nId, _rBindings ) + ,m_pMainMenu( &_rMenu ) + ,m_pConversionMenu( NULL ) +{ + if ( _nId == SID_FM_CHANGECONTROLTYPE ) + { + m_pConversionMenu = FmXFormShell::GetConversionMenu(); + _rMenu.SetPopupMenu( _nId, m_pConversionMenu ); + + for (sal_Int16 i=0; i<m_pConversionMenu->GetItemCount(); ++i) + { + _rBindings.Invalidate(m_pConversionMenu->GetItemId(i)); + SfxStatusForwarder* pForwarder = new SfxStatusForwarder(m_pConversionMenu->GetItemId(i), *this); + m_aStatusForwarders.C40_INSERT(SfxStatusForwarder, pForwarder, m_aStatusForwarders.Count()); + } + } +} + +//------------------------------------------------------------------------------ +ControlConversionMenuController::~ControlConversionMenuController() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "ControlConversionMenuController::~ControlConversionMenuController" ); + m_pMainMenu->SetPopupMenu(SID_FM_CHANGECONTROLTYPE, NULL); + delete m_pConversionMenu; +} + +//------------------------------------------------------------------------------ +void ControlConversionMenuController::StateChanged(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState) +{ + if (nSID == GetId()) + SfxMenuControl::StateChanged(nSID, eState, pState); + else if (FmXFormShell::isControlConversionSlot(nSID)) + { + if ((m_pConversionMenu->GetItemPos(nSID) != MENU_ITEM_NOTFOUND) && (eState == SFX_ITEM_DISABLED)) + { + m_pConversionMenu->RemoveItem(m_pConversionMenu->GetItemPos(nSID)); + } + else if ((m_pConversionMenu->GetItemPos(nSID) == MENU_ITEM_NOTFOUND) && (eState != SFX_ITEM_DISABLED)) + { + // We can't simply re-insert the item because we have a clear order for all the our items. + // So first we have to determine the position of the item to insert. + PopupMenu* pSource = FmXFormShell::GetConversionMenu(); + USHORT nSourcePos = pSource->GetItemPos(nSID); + DBG_ASSERT(nSourcePos != MENU_ITEM_NOTFOUND, "ControlConversionMenuController::StateChanged : FmXFormShell supplied an invalid menu !"); + USHORT nPrevInSource = nSourcePos; + USHORT nPrevInConversion = MENU_ITEM_NOTFOUND; + while (nPrevInSource>0) + { + sal_Int16 nPrevId = pSource->GetItemId(--nPrevInSource); + + // do we have the source's predecessor in our conversion menu, too ? + nPrevInConversion = m_pConversionMenu->GetItemPos(nPrevId); + if (nPrevInConversion != MENU_ITEM_NOTFOUND) + break; + } + if (MENU_ITEM_NOTFOUND == nPrevInConversion) + // none of the items which precede the nSID-slot in the source menu are present in our conversion menu + nPrevInConversion = sal::static_int_cast< USHORT >(-1); // put the item at the first position + m_pConversionMenu->InsertItem(nSID, pSource->GetItemText(nSID), pSource->GetItemBits(nSID), ++nPrevInConversion); + m_pConversionMenu->SetItemImage(nSID, pSource->GetItemImage(nSID)); + m_pConversionMenu->SetHelpId(nSID, pSource->GetHelpId(nSID)); + + delete pSource; + } + m_pMainMenu->EnableItem(SID_FM_CHANGECONTROLTYPE, m_pConversionMenu->GetItemCount() > 0); + } + else + { + DBG_ERROR("ControlConversionMenuController::StateChanged : unknown id !"); + } +} + +//============================================================================== + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmsrccfg.cxx b/svx/source/form/fmsrccfg.cxx new file mode 100644 index 000000000000..089c123f5e78 --- /dev/null +++ b/svx/source/form/fmsrccfg.cxx @@ -0,0 +1,321 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include "fmsrccfg.hxx" +#include <svl/filerec.hxx> +#include <com/sun/star/i18n/TransliterationModules.hpp> +#include <comphelper/processfactory.hxx> + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::i18n; + +//........................................................................ +namespace svxform +{ +//........................................................................ + + // ==================================================================== + // = struct FmSearchParams - Parameter einer Suche + // ==================================================================== + + FmSearchParams::FmSearchParams() + :nTransliterationFlags( 0 ) + ,nSearchForType ( 0 ) + ,nPosition ( MATCHING_ANYWHERE ) + ,nLevOther ( 2 ) + ,nLevShorter ( 2 ) + ,nLevLonger ( 2 ) + ,bLevRelaxed ( sal_True ) + ,bAllFields ( sal_False ) + ,bUseFormatter ( sal_True ) + ,bBackwards ( sal_False ) + ,bWildcard ( sal_False ) + ,bRegular ( sal_False ) + ,bApproxSearch ( sal_False ) + ,bSoundsLikeCJK ( sal_False ) + { + nTransliterationFlags = + TransliterationModules_ignoreSpace_ja_JP + | TransliterationModules_ignoreMiddleDot_ja_JP + | TransliterationModules_ignoreProlongedSoundMark_ja_JP + | TransliterationModules_ignoreSeparator_ja_JP + | TransliterationModules_IGNORE_CASE; + } + + sal_Bool FmSearchParams::isIgnoreWidthCJK( ) const + { + return 0 != (nTransliterationFlags & TransliterationModules_IGNORE_WIDTH); + } + + void FmSearchParams::setIgnoreWidthCJK( sal_Bool _bIgnore ) + { + if ( _bIgnore ) + nTransliterationFlags |= TransliterationModules_IGNORE_WIDTH; + else + nTransliterationFlags &= ~TransliterationModules_IGNORE_WIDTH; + } + + sal_Bool FmSearchParams::isCaseSensitive( ) const + { + return 0 == (nTransliterationFlags & TransliterationModules_IGNORE_CASE); + } + + void FmSearchParams::setCaseSensitive( sal_Bool _bCase ) + { + if ( _bCase ) + nTransliterationFlags &= ~TransliterationModules_IGNORE_CASE; + else + nTransliterationFlags |= TransliterationModules_IGNORE_CASE; + } + + // ==================================================================== + // = maps from ascii values to int values + // ==================================================================== + + struct Ascii2Int16 + { + const sal_Char* pAscii; + sal_Int16 nValue; + }; + + static const Ascii2Int16* lcl_getSearchForTypeValueMap() + { + static const Ascii2Int16 s_aSearchForTypeMap[] = + { + { "text", 0 }, + { "null", 1 }, + { "non-null", 2 }, + { NULL, -1 } + }; + return s_aSearchForTypeMap; + } + + static const Ascii2Int16* lcl_getSearchPositionValueMap() + { + static const Ascii2Int16 s_aSearchPositionMap[] = + { + { "anywhere-in-field", MATCHING_ANYWHERE }, + { "beginning-of-field", MATCHING_BEGINNING }, + { "end-of-field", MATCHING_END }, + { "complete-field", MATCHING_WHOLETEXT }, + { NULL, -1 } + }; + return s_aSearchPositionMap; + } + + static sal_Int16 lcl_implMapAsciiValue( const ::rtl::OUString& _rAsciiValue, const Ascii2Int16* _pMap ) + { + // search the map for the given ascii value + const Ascii2Int16* pSearch = _pMap; + while ( pSearch && pSearch->pAscii ) + { + if ( 0 == _rAsciiValue.compareToAscii( pSearch->pAscii ) ) + // found + return pSearch->nValue; + ++pSearch; + } + + DBG_ERROR( + ( ::rtl::OString( "lcl_implMapAsciiValue: could not convert the ascii value " ) + += ::rtl::OString( _rAsciiValue.getStr(), _rAsciiValue.getLength(), RTL_TEXTENCODING_ASCII_US ) + += ::rtl::OString( " !" ) + ).getStr() + ); + return -1; + } + + static const sal_Char* lcl_implMapIntValue( const sal_Int16 _nValue, const Ascii2Int16* _pMap ) + { + // search the map for the given integer value + const Ascii2Int16* pSearch = _pMap; + while ( pSearch && pSearch->pAscii ) + { + if ( _nValue == pSearch->nValue ) + // found + return pSearch->pAscii; + ++pSearch; + } + + DBG_ERROR( + ( ::rtl::OString( "lcl_implMapIntValue: could not convert the integer value " ) + += ::rtl::OString::valueOf( (sal_Int32)_nValue ) + += ::rtl::OString( " !" ) + ).getStr() + ); + static const sal_Char* s_pDummy = ""; + // just as a fallback .... + return s_pDummy; + } + + // ==================================================================== + // = class FmSearchConfigItem - ein ConfigItem, dass sich Suchparameter merkt + // ==================================================================== + +#define TA( c ) &c, getCppuType( &c ) + + FmSearchConfigItem::FmSearchConfigItem() + :OConfigurationValueContainer( ::comphelper::getProcessServiceFactory(), m_aMutex, "/org.openoffice.Office.DataAccess/FormSearchOptions", CVC_UPDATE_ACCESS | CVC_LAZY_UPDATE, 2 ) + { + // register our members so the data exchange with the node values is done automatically + + registerExchangeLocation( "SearchHistory", TA( aHistory ) ); + registerExchangeLocation( "LevenshteinOther", TA( nLevOther ) ); + registerExchangeLocation( "LevenshteinShorter", TA( nLevShorter ) ); + registerExchangeLocation( "LevenshteinLonger", TA( nLevLonger ) ); + registerExchangeLocation( "IsLevenshteinRelaxed", TA( bLevRelaxed ) ); + registerExchangeLocation( "IsSearchAllFields", TA( bAllFields ) ); + registerExchangeLocation( "IsUseFormatter", TA( bUseFormatter ) ); + registerExchangeLocation( "IsBackwards", TA( bBackwards ) ); + registerExchangeLocation( "IsWildcardSearch", TA( bWildcard ) ); + registerExchangeLocation( "IsUseRegularExpression", TA( bRegular ) ); + registerExchangeLocation( "IsSimilaritySearch", TA( bApproxSearch ) ); + registerExchangeLocation( "IsUseAsianOptions", TA( bSoundsLikeCJK ) ); + + // the properties which need to be translated + registerExchangeLocation( "SearchType", TA( m_sSearchForType ) ); + registerExchangeLocation( "SearchPosition", TA( m_sSearchPosition ) ); + + registerExchangeLocation( "IsMatchCase", TA( m_bIsMatchCase ) ); + registerExchangeLocation( "Japanese/IsMatchFullHalfWidthForms", TA( m_bIsMatchFullHalfWidthForms ) ); + registerExchangeLocation( "Japanese/IsMatchHiraganaKatakana", TA( m_bIsMatchHiraganaKatakana ) ); + registerExchangeLocation( "Japanese/IsMatchContractions", TA( m_bIsMatchContractions ) ); + registerExchangeLocation( "Japanese/IsMatchMinusDashCho-on", TA( m_bIsMatchMinusDashCho_on ) ); + registerExchangeLocation( "Japanese/IsMatchRepeatCharMarks", TA( m_bIsMatchRepeatCharMarks ) ); + registerExchangeLocation( "Japanese/IsMatchVariantFormKanji", TA( m_bIsMatchVariantFormKanji ) ); + registerExchangeLocation( "Japanese/IsMatchOldKanaForms", TA( m_bIsMatchOldKanaForms ) ); + registerExchangeLocation( "Japanese/IsMatch_DiZi_DuZu", TA( m_bIsMatch_DiZi_DuZu ) ); + registerExchangeLocation( "Japanese/IsMatch_BaVa_HaFa", TA( m_bIsMatch_BaVa_HaFa ) ); + registerExchangeLocation( "Japanese/IsMatch_TsiThiChi_DhiZi", TA( m_bIsMatch_TsiThiChi_DhiZi ) ); + registerExchangeLocation( "Japanese/IsMatch_HyuIyu_ByuVyu", TA( m_bIsMatch_HyuIyu_ByuVyu ) ); + registerExchangeLocation( "Japanese/IsMatch_SeShe_ZeJe", TA( m_bIsMatch_SeShe_ZeJe ) ); + registerExchangeLocation( "Japanese/IsMatch_IaIya", TA( m_bIsMatch_IaIya ) ); + registerExchangeLocation( "Japanese/IsMatch_KiKu", TA( m_bIsMatch_KiKu ) ); + registerExchangeLocation( "Japanese/IsIgnorePunctuation", TA( m_bIsIgnorePunctuation ) ); + registerExchangeLocation( "Japanese/IsIgnoreWhitespace", TA( m_bIsIgnoreWhitespace ) ); + registerExchangeLocation( "Japanese/IsIgnoreProlongedSoundMark",TA( m_bIsIgnoreProlongedSoundMark ) ); + registerExchangeLocation( "Japanese/IsIgnoreMiddleDot", TA( m_bIsIgnoreMiddleDot ) ); + + read( ); + } + + FmSearchConfigItem::~FmSearchConfigItem() + { + commit( ); + } + + void FmSearchConfigItem::implTranslateFromConfig( ) + { + // the search-for string + nSearchForType = lcl_implMapAsciiValue( m_sSearchForType, lcl_getSearchForTypeValueMap() ); + + // the search position + nPosition = lcl_implMapAsciiValue( m_sSearchPosition, lcl_getSearchPositionValueMap() ); + + // the transliteration flags + nTransliterationFlags = 0; + + if ( !m_bIsMatchCase ) nTransliterationFlags |= TransliterationModules_IGNORE_CASE; + if ( m_bIsMatchFullHalfWidthForms ) nTransliterationFlags |= TransliterationModules_IGNORE_WIDTH; + if ( m_bIsMatchHiraganaKatakana ) nTransliterationFlags |= TransliterationModules_IGNORE_KANA; + if ( m_bIsMatchContractions ) nTransliterationFlags |= TransliterationModules_ignoreSize_ja_JP; + if ( m_bIsMatchMinusDashCho_on ) nTransliterationFlags |= TransliterationModules_ignoreMinusSign_ja_JP; + if ( m_bIsMatchRepeatCharMarks ) nTransliterationFlags |= TransliterationModules_ignoreIterationMark_ja_JP; + if ( m_bIsMatchVariantFormKanji ) nTransliterationFlags |= TransliterationModules_ignoreTraditionalKanji_ja_JP; + if ( m_bIsMatchOldKanaForms ) nTransliterationFlags |= TransliterationModules_ignoreTraditionalKana_ja_JP; + if ( m_bIsMatch_DiZi_DuZu ) nTransliterationFlags |= TransliterationModules_ignoreZiZu_ja_JP; + if ( m_bIsMatch_BaVa_HaFa ) nTransliterationFlags |= TransliterationModules_ignoreBaFa_ja_JP; + if ( m_bIsMatch_TsiThiChi_DhiZi ) nTransliterationFlags |= TransliterationModules_ignoreTiJi_ja_JP; + if ( m_bIsMatch_HyuIyu_ByuVyu ) nTransliterationFlags |= TransliterationModules_ignoreHyuByu_ja_JP; + if ( m_bIsMatch_SeShe_ZeJe ) nTransliterationFlags |= TransliterationModules_ignoreSeZe_ja_JP; + if ( m_bIsMatch_IaIya ) nTransliterationFlags |= TransliterationModules_ignoreIandEfollowedByYa_ja_JP; + if ( m_bIsMatch_KiKu ) nTransliterationFlags |= TransliterationModules_ignoreKiKuFollowedBySa_ja_JP; + + if ( m_bIsIgnorePunctuation ) nTransliterationFlags |= TransliterationModules_ignoreSeparator_ja_JP; + if ( m_bIsIgnoreWhitespace ) nTransliterationFlags |= TransliterationModules_ignoreSpace_ja_JP; + if ( m_bIsIgnoreProlongedSoundMark ) nTransliterationFlags |= TransliterationModules_ignoreProlongedSoundMark_ja_JP; + if ( m_bIsIgnoreMiddleDot ) nTransliterationFlags |= TransliterationModules_ignoreMiddleDot_ja_JP; + } + + void FmSearchConfigItem::implTranslateToConfig( ) + { + // the search-for string + m_sSearchForType = ::rtl::OUString::createFromAscii( lcl_implMapIntValue( nSearchForType, lcl_getSearchForTypeValueMap() ) ); + + // the search position + m_sSearchPosition = ::rtl::OUString::createFromAscii( lcl_implMapIntValue( nPosition, lcl_getSearchPositionValueMap() ) ); + + // the transliteration flags + + m_bIsMatchCase = ( 0 == ( nTransliterationFlags & TransliterationModules_IGNORE_CASE ) ); + m_bIsMatchFullHalfWidthForms = ( 0 != ( nTransliterationFlags & TransliterationModules_IGNORE_WIDTH ) ); + m_bIsMatchHiraganaKatakana = ( 0 != ( nTransliterationFlags & TransliterationModules_IGNORE_KANA ) ); + m_bIsMatchContractions = ( 0 != ( nTransliterationFlags & TransliterationModules_ignoreSize_ja_JP ) ); + m_bIsMatchMinusDashCho_on = ( 0 != ( nTransliterationFlags & TransliterationModules_ignoreMinusSign_ja_JP ) ); + m_bIsMatchRepeatCharMarks = ( 0 != ( nTransliterationFlags & TransliterationModules_ignoreIterationMark_ja_JP ) ); + m_bIsMatchVariantFormKanji = ( 0 != ( nTransliterationFlags & TransliterationModules_ignoreTraditionalKanji_ja_JP ) ); + m_bIsMatchOldKanaForms = ( 0 != ( nTransliterationFlags & TransliterationModules_ignoreTraditionalKana_ja_JP ) ); + m_bIsMatch_DiZi_DuZu = ( 0 != ( nTransliterationFlags & TransliterationModules_ignoreZiZu_ja_JP ) ); + m_bIsMatch_BaVa_HaFa = ( 0 != ( nTransliterationFlags & TransliterationModules_ignoreBaFa_ja_JP ) ); + m_bIsMatch_TsiThiChi_DhiZi = ( 0 != ( nTransliterationFlags & TransliterationModules_ignoreTiJi_ja_JP ) ); + m_bIsMatch_HyuIyu_ByuVyu = ( 0 != ( nTransliterationFlags & TransliterationModules_ignoreHyuByu_ja_JP ) ); + m_bIsMatch_SeShe_ZeJe = ( 0 != ( nTransliterationFlags & TransliterationModules_ignoreSeZe_ja_JP ) ); + m_bIsMatch_IaIya = ( 0 != ( nTransliterationFlags & TransliterationModules_ignoreIandEfollowedByYa_ja_JP ) ); + m_bIsMatch_KiKu = ( 0 != ( nTransliterationFlags & TransliterationModules_ignoreKiKuFollowedBySa_ja_JP ) ); + + m_bIsIgnorePunctuation = ( 0 != ( nTransliterationFlags & TransliterationModules_ignoreSeparator_ja_JP ) ); + m_bIsIgnoreWhitespace = ( 0 != ( nTransliterationFlags & TransliterationModules_ignoreSpace_ja_JP ) ); + m_bIsIgnoreProlongedSoundMark = ( 0 != ( nTransliterationFlags & TransliterationModules_ignoreProlongedSoundMark_ja_JP ) ); + m_bIsIgnoreMiddleDot = ( 0 != ( nTransliterationFlags & TransliterationModules_ignoreMiddleDot_ja_JP ) ); + } + + const FmSearchParams& FmSearchConfigItem::getParams() const + { + // ensure that the properties which are not stored directly are up-to-date + const_cast< FmSearchConfigItem* >( this )->implTranslateFromConfig( ); + + // and return our FmSearchParams part + return *this; + } + + void FmSearchConfigItem::setParams( const FmSearchParams& _rParams ) + { + // copy the FmSearchParams part + *static_cast< FmSearchParams* >( this ) = _rParams; + + // translate the settings not represented by a direct config value + implTranslateToConfig(); + } + +//........................................................................ +} // namespace svxform +//........................................................................ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmsrcimp.cxx b/svx/source/form/fmsrcimp.cxx new file mode 100644 index 000000000000..18c045e32b27 --- /dev/null +++ b/svx/source/form/fmsrcimp.cxx @@ -0,0 +1,1300 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include "fmresids.hrc" +#include "svx/fmtools.hxx" +#include "fmsrccfg.hxx" +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <tools/wldcrd.hxx> +#include <vcl/msgbox.hxx> +#include <tools/shl.hxx> +#include <svx/dialmgr.hxx> +#include <cppuhelper/servicefactory.hxx> +#include <vcl/svapp.hxx> +#include <unotools/textsearch.hxx> +#include <com/sun/star/util/SearchOptions.hpp> +#include <com/sun/star/util/SearchAlgorithms.hpp> +#include <com/sun/star/util/SearchResult.hpp> +#include <com/sun/star/util/SearchFlags.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/i18n/TransliterationModules.hpp> +#include <com/sun/star/i18n/CollatorOptions.hpp> + +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/util/XNumberFormatter.hpp> +#include <com/sun/star/util/NumberFormat.hpp> +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> +#include <com/sun/star/util/XNumberFormats.hpp> +#include <comphelper/processfactory.hxx> + +#include "fmprop.hrc" +#include "fmservs.hxx" +#include "fmsrcimp.hxx" +#include <svx/fmsearch.hxx> + +#include <comphelper/numbers.hxx> +#include <unotools/syslocale.hxx> + +#define EQUAL_BOOKMARKS(a, b) a == b + +#define IFACECAST(c) ((const Reference< XInterface >&)c) + // SUN C52 has some ambiguities without this cast .... + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::i18n; +using namespace ::com::sun::star::beans; +using namespace ::svxform; + +// *************************************************************************************************** + +// *************************************************************************************************** + +SV_IMPL_OBJARR(SvInt32Array, sal_Int32); + +//======================================================================== +// = FmSearchThread +//------------------------------------------------------------------------ +void FmSearchThread::run() +{ + m_pEngine->SearchNextImpl(); +}; + +//------------------------------------------------------------------------ +void FmSearchThread::onTerminated() +{ + if (m_aTerminationHdl.IsSet()) + m_aTerminationHdl.Call(this); + delete this; +} + +//======================================================================== +// = FmRecordCountListener + +// SMART_UNO_IMPLEMENTATION(FmRecordCountListener, UsrObject); + +DBG_NAME(FmRecordCountListener); +//------------------------------------------------------------------------ +FmRecordCountListener::FmRecordCountListener(const Reference< ::com::sun::star::sdbc::XResultSet > & dbcCursor) +{ + DBG_CTOR(FmRecordCountListener,NULL); + + m_xListening = Reference< ::com::sun::star::beans::XPropertySet > (dbcCursor, UNO_QUERY); + if (!m_xListening.is()) + return; + + if (::comphelper::getBOOL(m_xListening->getPropertyValue(FM_PROP_ROWCOUNTFINAL))) + { + m_xListening = NULL; + // there's nothing to do as the record count is already known + return; + } + + m_xListening->addPropertyChangeListener(FM_PROP_ROWCOUNT, (::com::sun::star::beans::XPropertyChangeListener*)this); +} + +//------------------------------------------------------------------------ +Link FmRecordCountListener::SetPropChangeHandler(const Link& lnk) +{ + Link lnkReturn = m_lnkWhoWantsToKnow; + m_lnkWhoWantsToKnow = lnk; + + if (m_xListening.is()) + NotifyCurrentCount(); + + return lnkReturn; +} + +//------------------------------------------------------------------------ +FmRecordCountListener::~FmRecordCountListener() +{ + + DBG_DTOR(FmRecordCountListener,NULL); +} + +//------------------------------------------------------------------------ +void FmRecordCountListener::DisConnect() +{ + if(m_xListening.is()) + m_xListening->removePropertyChangeListener(FM_PROP_ROWCOUNT, (::com::sun::star::beans::XPropertyChangeListener*)this); + m_xListening = NULL; +} + +//------------------------------------------------------------------------ +void SAL_CALL FmRecordCountListener::disposing(const ::com::sun::star::lang::EventObject& /*Source*/) throw( RuntimeException ) +{ + DBG_ASSERT(m_xListening.is(), "FmRecordCountListener::disposing should never have been called without a propset !"); + DisConnect(); +} + +//------------------------------------------------------------------------ +void FmRecordCountListener::NotifyCurrentCount() +{ + if (m_lnkWhoWantsToKnow.IsSet()) + { + DBG_ASSERT(m_xListening.is(), "FmRecordCountListener::NotifyCurrentCount : I have no propset ... !?"); + void* pTheCount = (void*)::comphelper::getINT32(m_xListening->getPropertyValue(FM_PROP_ROWCOUNT)); + m_lnkWhoWantsToKnow.Call(pTheCount); + } +} + +//------------------------------------------------------------------------ +void FmRecordCountListener::propertyChange(const ::com::sun::star::beans::PropertyChangeEvent& /*evt*/) throw(::com::sun::star::uno::RuntimeException) +{ + NotifyCurrentCount(); +} + +//======================================================================== +// FmSearchEngine - local classes +//------------------------------------------------------------------------ +SimpleTextWrapper::SimpleTextWrapper(const Reference< ::com::sun::star::awt::XTextComponent > & _xText) + :ControlTextWrapper(_xText.get()) + ,m_xText(_xText) +{ + DBG_ASSERT(m_xText.is(), "FmSearchEngine::SimpleTextWrapper::SimpleTextWrapper : invalid argument !"); +} + +//------------------------------------------------------------------------ +::rtl::OUString SimpleTextWrapper::getCurrentText() const +{ + return m_xText->getText(); +} + +//------------------------------------------------------------------------ +ListBoxWrapper::ListBoxWrapper(const Reference< ::com::sun::star::awt::XListBox > & _xBox) + :ControlTextWrapper(_xBox.get()) + ,m_xBox(_xBox) +{ + DBG_ASSERT(m_xBox.is(), "FmSearchEngine::ListBoxWrapper::ListBoxWrapper : invalid argument !"); +} + +//------------------------------------------------------------------------ +::rtl::OUString ListBoxWrapper::getCurrentText() const +{ + return m_xBox->getSelectedItem(); +} + +//------------------------------------------------------------------------ +CheckBoxWrapper::CheckBoxWrapper(const Reference< ::com::sun::star::awt::XCheckBox > & _xBox) + :ControlTextWrapper(_xBox.get()) + ,m_xBox(_xBox) +{ + DBG_ASSERT(m_xBox.is(), "FmSearchEngine::CheckBoxWrapper::CheckBoxWrapper : invalid argument !"); +} + +//------------------------------------------------------------------------ +::rtl::OUString CheckBoxWrapper::getCurrentText() const +{ + switch ((TriState)m_xBox->getState()) + { + case STATE_NOCHECK: return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("0")); + case STATE_CHECK: return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("1")); + default: break; + } + return rtl::OUString(); +} + +//======================================================================== +// = FmSearchEngine +//------------------------------------------------------------------------ +sal_Bool FmSearchEngine::MoveCursor() +{ + sal_Bool bSuccess = sal_True; + try + { + if (m_bForward) + if (m_xSearchCursor.isLast()) + m_xSearchCursor.first(); + else + m_xSearchCursor.next(); + else + if (m_xSearchCursor.isFirst()) + { + FmRecordCountListener* prclListener = new FmRecordCountListener(m_xSearchCursor); + prclListener->acquire(); + prclListener->SetPropChangeHandler(LINK(this, FmSearchEngine, OnNewRecordCount)); + + m_xSearchCursor.last(); + + prclListener->DisConnect(); + prclListener->release(); + } + else + m_xSearchCursor.previous(); + } + catch(::com::sun::star::sdbc::SQLException const& e) + { +#if OSL_DEBUG_LEVEL > 0 + String sDebugMessage; + sDebugMessage.AssignAscii("FmSearchEngine::MoveCursor : catched a DatabaseException ("); + sDebugMessage += (const sal_Unicode*)e.SQLState; + sDebugMessage.AppendAscii(") !"); + DBG_ERROR(ByteString(sDebugMessage, RTL_TEXTENCODING_ASCII_US).GetBuffer()); +#endif + bSuccess = sal_False; + } + catch(Exception const& e) + { +#if OSL_DEBUG_LEVEL > 0 + UniString sDebugMessage; + sDebugMessage.AssignAscii("FmSearchEngine::MoveCursor : catched an Exception ("); + sDebugMessage += (const sal_Unicode*)e.Message; + sDebugMessage.AppendAscii(") !"); + DBG_ERROR(ByteString(sDebugMessage, RTL_TEXTENCODING_ASCII_US).GetBuffer()); +#endif + bSuccess = sal_False; + } + catch(...) + { + DBG_ERROR("FmSearchEngine::MoveCursor : catched an unknown Exception !"); + bSuccess = sal_False; + } + + return bSuccess; +} + +//------------------------------------------------------------------------ +sal_Bool FmSearchEngine::MoveField(sal_Int32& nPos, FieldCollectionIterator& iter, const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd) +{ + sal_Bool bSuccess(sal_True); + if (m_bForward) + { + ++iter; + ++nPos; + if (iter == iterEnd) + { + bSuccess = MoveCursor(); + iter = iterBegin; + nPos = 0; + } + } else + { + if (iter == iterBegin) + { + bSuccess = MoveCursor(); + iter = iterEnd; + nPos = iter-iterBegin; + } + --iter; + --nPos; + } + return bSuccess; +} + +//------------------------------------------------------------------------ +void FmSearchEngine::BuildAndInsertFieldInfo(const Reference< ::com::sun::star::container::XIndexAccess > & xAllFields, sal_Int32 nField) +{ + DBG_ASSERT( xAllFields.is() && ( nField >= 0 ) && ( nField < xAllFields->getCount() ), + "FmSearchEngine::BuildAndInsertFieldInfo: invalid field descriptor!" ); + + // das Feld selber + Reference< XInterface > xCurrentField; + xAllFields->getByIndex(nField) >>= xCurrentField; + + // von dem weiss ich jetzt, dass es den DatabaseRecord-Service unterstuetzt (hoffe ich) + // fuer den FormatKey und den Typ brauche ich das PropertySet + Reference< ::com::sun::star::beans::XPropertySet > xProperties(xCurrentField, UNO_QUERY); + + // die FieldInfo dazu aufbauen + FieldInfo fiCurrent; + fiCurrent.xContents = Reference< ::com::sun::star::sdb::XColumn > (xCurrentField, UNO_QUERY); + fiCurrent.nFormatKey = ::comphelper::getINT32(xProperties->getPropertyValue(FM_PROP_FORMATKEY)); + fiCurrent.bDoubleHandling = sal_False; + if (m_xFormatSupplier.is()) + { + Reference< ::com::sun::star::util::XNumberFormats > xNumberFormats(m_xFormatSupplier->getNumberFormats()); + + sal_Int16 nFormatType = ::comphelper::getNumberFormatType(xNumberFormats, fiCurrent.nFormatKey) & ~((sal_Int16)::com::sun::star::util::NumberFormat::DEFINED); + fiCurrent.bDoubleHandling = (nFormatType != ::com::sun::star::util::NumberFormat::TEXT); + } + + // und merken + m_arrUsedFields.insert(m_arrUsedFields.end(), fiCurrent); + +} +//------------------------------------------------------------------------ +::rtl::OUString FmSearchEngine::FormatField(const FieldInfo& rField) +{ + DBG_ASSERT(!m_bUsingTextComponents, "FmSearchEngine::FormatField : im UsingTextComponents-Mode bitte FormatField(sal_Int32) benutzen !"); + + if (!m_xFormatter.is()) + return ::rtl::OUString(); + // sonst werden Datumsflder zum Beispiel zu irgendeinem Default-Wert formatiert + + ::rtl::OUString sReturn; + try + { + if (rField.bDoubleHandling) + { + double fValue = rField.xContents->getDouble(); + if (!rField.xContents->wasNull()) + sReturn = m_xFormatter->convertNumberToString(rField.nFormatKey, fValue); + } + else + { + ::rtl::OUString sValue = rField.xContents->getString(); + if (!rField.xContents->wasNull()) + sReturn = m_xFormatter->formatString(rField.nFormatKey, sValue); + } + } + catch(...) + { + } + + + return sReturn; +} + +//------------------------------------------------------------------------ +::rtl::OUString FmSearchEngine::FormatField(sal_Int32 nWhich) +{ + if (m_bUsingTextComponents) + { + DBG_ASSERT((sal_uInt32)nWhich < m_aControlTexts.size(), "FmSearchEngine::FormatField(sal_Int32) : invalid position !"); + DBG_ASSERT(m_aControlTexts[nWhich] != NULL, "FmSearchEngine::FormatField(sal_Int32) : invalid object in array !"); + DBG_ASSERT(m_aControlTexts[nWhich]->getControl().is(), "FmSearchEngine::FormatField : invalid control !"); + + if (m_nCurrentFieldIndex != -1) + { + DBG_ASSERT((nWhich == 0) || (nWhich == m_nCurrentFieldIndex), "FmSearchEngine::FormatField : Parameter nWhich ist ungueltig"); + // analoge Situation wie unten + nWhich = m_nCurrentFieldIndex; + } + + DBG_ASSERT((nWhich >= 0) && ((sal_uInt32)nWhich < m_aControlTexts.size()), + "FmSearchEngine::FormatField : invalid argument nWhich !"); + return m_aControlTexts[m_nCurrentFieldIndex == -1 ? nWhich : m_nCurrentFieldIndex]->getCurrentText(); + } + else + { + if (m_nCurrentFieldIndex != -1) + { + DBG_ASSERT((nWhich == 0) || (nWhich == m_nCurrentFieldIndex), "FmSearchEngine::FormatField : Parameter nWhich ist ungueltig"); + // ich bin im single-field-modus, da ist auch die richtige Feld-Nummer erlaubt, obwohl dann der richtige ::com::sun::star::sdbcx::Index + // fuer meinen Array-Zugriff natuerlich 0 ist + nWhich = 0; + } + + DBG_ASSERT((nWhich>=0) && (nWhich < (m_arrUsedFields.end() - m_arrUsedFields.begin())), + "FmSearchEngine::FormatField : Parameter nWhich ist ungueltig"); + return FormatField(m_arrUsedFields[nWhich]); + } +} + +//------------------------------------------------------------------------ +FmSearchEngine::SEARCH_RESULT FmSearchEngine::SearchSpecial(sal_Bool _bSearchForNull, sal_Int32& nFieldPos, + FieldCollectionIterator& iterFieldLoop, const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd) +{ + // die Startposition merken + Any aStartMark; + try { aStartMark = m_xSearchCursor.getBookmark(); } + catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; } + FieldCollectionIterator iterInitialField = iterFieldLoop; + + // -------------------------------------------------------------- + sal_Bool bFound(sal_False); + sal_Bool bMovedAround(sal_False); + do + { + if (m_eMode == SM_ALLOWSCHEDULE) + { + Application::Reschedule(); + Application::Reschedule(); + // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event + // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings + // or anything like that. So within each loop we create one user event and handle one user event (and no + // paintings and these), so the office seems to be frozen while searching. + // FS - 70226 - 02.12.99 + } + + // der aktuell zu vergleichende Inhalt + iterFieldLoop->xContents->getString(); // needed for wasNull + bFound = _bSearchForNull == iterFieldLoop->xContents->wasNull(); + if (bFound) + break; + + // naechstes Feld (implizit naechster Datensatz, wenn noetig) + if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd)) + { // beim Bewegen auf das naechste Feld ging was schief ... weitermachen ist nicht drin, da das naechste Mal genau + // das selbe bestimmt wieder schief geht, also Abbruch + // vorher aber noch, damit das Weitersuchen an der aktuellen Position weitermacht : + try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); } + catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } + m_iterPreviousLocField = iterFieldLoop; + // und wech + return SR_ERROR; + } + + Any aCurrentBookmark; + try { aCurrentBookmark = m_xSearchCursor.getBookmark(); } + catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; } + + bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField); + + if (nFieldPos == 0) + // das heisst, ich habe mich auf einen neuen Datensatz bewegt + PropagateProgress(bMovedAround); + // if we moved to the starting position we don't have to propagate an 'overflow' message + // FS - 07.12.99 - 68530 + + // abbrechen gefordert ? + if (CancelRequested()) + return SR_CANCELED; + + } while (!bMovedAround); + + return bFound ? SR_FOUND : SR_NOTFOUND; +} + +//------------------------------------------------------------------------ +FmSearchEngine::SEARCH_RESULT FmSearchEngine::SearchWildcard(const ::rtl::OUString& strExpression, sal_Int32& nFieldPos, + FieldCollectionIterator& iterFieldLoop, const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd) +{ + // die Startposition merken + Any aStartMark; + try { aStartMark = m_xSearchCursor.getBookmark(); } + catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; } + FieldCollectionIterator iterInitialField = iterFieldLoop; + + WildCard aSearchExpression(strExpression); + + // -------------------------------------------------------------- + sal_Bool bFound(sal_False); + sal_Bool bMovedAround(sal_False); + do + { + if (m_eMode == SM_ALLOWSCHEDULE) + { + Application::Reschedule(); + Application::Reschedule(); + // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event + // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings + // or anything like that. So within each loop we create one user event and hanel one user event (and no + // paintings and these), so the office seems to be frozen while searching. + // FS - 70226 - 02.12.99 + } + + // der aktuell zu vergleichende Inhalt + ::rtl::OUString sCurrentCheck; + if (m_bFormatter) + sCurrentCheck = FormatField(nFieldPos); + else + sCurrentCheck = iterFieldLoop->xContents->getString(); + + if (!GetCaseSensitive()) + // norm the string + m_aCharacterClassficator.toLower_rtl(sCurrentCheck); + + // jetzt ist der Test einfach ... + bFound = aSearchExpression.Matches(sCurrentCheck); + + if (bFound) + break; + + // naechstes Feld (implizit naechster Datensatz, wenn noetig) + if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd)) + { // beim Bewegen auf das naechste Feld ging was schief ... weitermachen ist nicht drin, da das naechste Mal genau + // das selbe bestimmt wieder schief geht, also Abbruch + // vorher aber noch, damit das Weitersuchen an der aktuellen Position weitermacht : + try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); } + catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } + m_iterPreviousLocField = iterFieldLoop; + // und wech + return SR_ERROR; + } + + Any aCurrentBookmark; + try { aCurrentBookmark = m_xSearchCursor.getBookmark(); } + catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; } + + bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField); + + if (nFieldPos == 0) + // das heisst, ich habe mich auf einen neuen Datensatz bewegt + PropagateProgress(bMovedAround); + // if we moved to the starting position we don't have to propagate an 'overflow' message + // FS - 07.12.99 - 68530 + + // abbrechen gefordert ? + if (CancelRequested()) + return SR_CANCELED; + + } while (!bMovedAround); + + return bFound ? SR_FOUND : SR_NOTFOUND; +} + +//------------------------------------------------------------------------ +FmSearchEngine::SEARCH_RESULT FmSearchEngine::SearchRegularApprox(const ::rtl::OUString& strExpression, sal_Int32& nFieldPos, + FieldCollectionIterator& iterFieldLoop, const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd) +{ + DBG_ASSERT(m_bLevenshtein || m_bRegular, + "FmSearchEngine::SearchRegularApprox : ungueltiger Suchmodus !"); + DBG_ASSERT(!m_bLevenshtein || !m_bRegular, + "FmSearchEngine::SearchRegularApprox : kann nicht nach regulaeren Ausdruecken und nach Aehnlichkeiten gleichzeitig suchen !"); + + // Startposition merken + Any aStartMark; + try { aStartMark = m_xSearchCursor.getBookmark(); } + catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; } + FieldCollectionIterator iterInitialField = iterFieldLoop; + + // Parameter sammeln + SearchOptions aParam; + aParam.algorithmType = m_bRegular ? SearchAlgorithms_REGEXP : SearchAlgorithms_APPROXIMATE; + aParam.searchFlag = 0; + aParam.transliterateFlags = GetTransliterationFlags(); + if ( !GetTransliteration() ) + { // if transliteration is not enabled, the only flags which matter are IGNORE_CASE and IGNORE_WIDTH + aParam.transliterateFlags &= TransliterationModules_IGNORE_CASE | TransliterationModules_IGNORE_WIDTH; + } + if (m_bLevenshtein) + { + if (m_bLevRelaxed) + aParam.searchFlag |= SearchFlags::LEV_RELAXED; + aParam.changedChars = m_nLevOther; + aParam.deletedChars = m_nLevShorter; + aParam.insertedChars = m_nLevLonger; + } + aParam.searchString = strExpression; + aParam.Locale = SvtSysLocale().GetLocaleData().getLocale(); + ::utl::TextSearch aLocalEngine(aParam); + + // -------------------------------------------------------------- + bool bFound = false; + sal_Bool bMovedAround(sal_False); + do + { + if (m_eMode == SM_ALLOWSCHEDULE) + { + Application::Reschedule(); + Application::Reschedule(); + // do 2 reschedules because of #70226# : some things done within this loop's body may cause an user event + // to be posted (deep within vcl), and these user events will be handled before any keyinput or paintings + // or anything like that. So within each loop we create one user event and handle one user event (and no + // paintings and these), so the office seems to be frozen while searching. + // FS - 70226 - 02.12.99 + } + + // der aktuell zu vergleichende Inhalt + ::rtl::OUString sCurrentCheck; + if (m_bFormatter) + sCurrentCheck = FormatField(nFieldPos); + else + sCurrentCheck = iterFieldLoop->xContents->getString(); + + // (don't care about case here, this is done by the TextSearch object, 'cause we passed our case parameter to it) + + xub_StrLen nStart = 0, nEnd = (xub_StrLen)sCurrentCheck.getLength(); + bFound = aLocalEngine.SearchFrwrd(sCurrentCheck, &nStart, &nEnd); + // das heisst hier 'forward' aber das bezieht sich nur auf die Suche innerhalb von sCurrentCheck, hat also mit + // der Richtung meines Datensatz-Durchwanderns nix zu tun (darum kuemmert sich MoveField) + + // checken, ob die Position stimmt + if (bFound) + { + switch (m_nPosition) + { + case MATCHING_WHOLETEXT : + if (nEnd != sCurrentCheck.getLength()) + { + bFound = false; + break; + } + // laeuft in den naechsten Case rein ! + case MATCHING_BEGINNING : + if (nStart != 0) + bFound = false; + break; + case MATCHING_END : + if (nEnd != sCurrentCheck.getLength()) + bFound = false; + break; + } + } + + if (bFound) // immer noch ? + break; + + // naechstes Feld (implizit naechster Datensatz, wenn noetig) + if (!MoveField(nFieldPos, iterFieldLoop, iterBegin, iterEnd)) + { // beim Bewegen auf das naechste Feld ging was schief ... weitermachen ist nicht drin, da das naechste Mal genau + // das selbe bestimmt wieder schief geht, also Abbruch (ohne Fehlermeldung, von der erwarte ich, dass sie im Move + // angezeigt wurde) + // vorher aber noch, damit das Weitersuchen an der aktuellen Position weitermacht : + try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); } + catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } + m_iterPreviousLocField = iterFieldLoop; + // und wech + return SR_ERROR; + } + + Any aCurrentBookmark; + try { aCurrentBookmark = m_xSearchCursor.getBookmark(); } + catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); return SR_ERROR; } + bMovedAround = EQUAL_BOOKMARKS(aStartMark, aCurrentBookmark) && (iterFieldLoop == iterInitialField); + + if (nFieldPos == 0) + // das heisst, ich habe mich auf einen neuen Datensatz bewegt + PropagateProgress(bMovedAround); + // if we moved to the starting position we don't have to propagate an 'overflow' message + // FS - 07.12.99 - 68530 + + // abbrechen gefordert ? + if (CancelRequested()) + return SR_CANCELED; + + } while (!bMovedAround); + + return bFound ? SR_FOUND : SR_NOTFOUND; +} + + +DBG_NAME(FmSearchEngine); +//------------------------------------------------------------------------ +FmSearchEngine::FmSearchEngine(const Reference< XMultiServiceFactory >& _rxORB, + const Reference< XResultSet > & xCursor, const ::rtl::OUString& sVisibleFields, + const Reference< XNumberFormatsSupplier > & xFormatSupplier, FMSEARCH_MODE eMode) + + :m_xSearchCursor(xCursor) + ,m_xFormatSupplier(xFormatSupplier) + ,m_aCharacterClassficator( _rxORB, SvtSysLocale().GetLocaleData().getLocale() ) + ,m_aStringCompare( _rxORB ) + ,m_nCurrentFieldIndex(-2) // -1 hat schon eine Bedeutung, also nehme ich -2 fuer 'ungueltig' + ,m_bUsingTextComponents(sal_False) + ,m_eSearchForType(SEARCHFOR_STRING) + ,m_srResult(SR_FOUND) + ,m_bSearchingCurrently(sal_False) + ,m_bCancelAsynchRequest(sal_False) + ,m_eMode(eMode) + ,m_bFormatter(sal_False) + ,m_bForward(sal_False) + ,m_bWildcard(sal_False) + ,m_bRegular(sal_False) + ,m_bLevenshtein(sal_False) + ,m_bTransliteration(sal_False) + ,m_bLevRelaxed(sal_False) + ,m_nLevOther(0) + ,m_nLevShorter(0) + ,m_nLevLonger(0) + ,m_nPosition(MATCHING_ANYWHERE) + ,m_nTransliterationFlags(0) +{ + DBG_CTOR(FmSearchEngine,NULL); + + m_xFormatter = Reference< ::com::sun::star::util::XNumberFormatter > (::comphelper::getProcessServiceFactory() + ->createInstance(FM_NUMBER_FORMATTER), UNO_QUERY); + if (m_xFormatter.is()) + m_xFormatter->attachNumberFormatsSupplier(m_xFormatSupplier); + + Init(sVisibleFields); +} + +//------------------------------------------------------------------------ +FmSearchEngine::FmSearchEngine(const Reference< XMultiServiceFactory >& _rxORB, + const Reference< XResultSet > & xCursor, const ::rtl::OUString& sVisibleFields, + const InterfaceArray& arrFields, FMSEARCH_MODE eMode) + :m_xSearchCursor(xCursor) + ,m_aCharacterClassficator( _rxORB, SvtSysLocale().GetLocaleData().getLocale() ) + ,m_aStringCompare( _rxORB ) + ,m_nCurrentFieldIndex(-2) // -1 hat schon eine Bedeutung, also nehme ich -2 fuer 'ungueltig' + ,m_bUsingTextComponents(sal_True) + ,m_xOriginalIterator(xCursor) + ,m_xClonedIterator(m_xOriginalIterator, sal_True) + ,m_eSearchForType(SEARCHFOR_STRING) + ,m_srResult(SR_FOUND) + ,m_bSearchingCurrently(sal_False) + ,m_bCancelAsynchRequest(sal_False) + ,m_eMode(eMode) + ,m_bFormatter(sal_True) // das muss konsistent sein mit m_xSearchCursor, der i.A. == m_xOriginalIterator ist + ,m_bForward(sal_False) + ,m_bWildcard(sal_False) + ,m_bRegular(sal_False) + ,m_bLevenshtein(sal_False) + ,m_bTransliteration(sal_False) + ,m_bLevRelaxed(sal_False) + ,m_nLevOther(0) + ,m_nLevShorter(0) + ,m_nLevLonger(0) + ,m_nPosition(MATCHING_ANYWHERE) + ,m_nTransliterationFlags(0) +{ + DBG_CTOR(FmSearchEngine,NULL); + + fillControlTexts(arrFields); + Init(sVisibleFields); +} + +//------------------------------------------------------------------------ +FmSearchEngine::~FmSearchEngine() +{ + clearControlTexts(); + + DBG_DTOR(FmSearchEngine,NULL); +} + +//------------------------------------------------------------------------ +void FmSearchEngine::SetIgnoreWidthCJK(sal_Bool bSet) +{ + if (bSet) + m_nTransliterationFlags |= TransliterationModules_IGNORE_WIDTH; + else + m_nTransliterationFlags &= ~TransliterationModules_IGNORE_WIDTH; +} + +//------------------------------------------------------------------------ +sal_Bool FmSearchEngine::GetIgnoreWidthCJK() const +{ + return 0 != (m_nTransliterationFlags & TransliterationModules_IGNORE_WIDTH); +} + +//------------------------------------------------------------------------ +void FmSearchEngine::SetCaseSensitive(sal_Bool bSet) +{ + if (bSet) + m_nTransliterationFlags &= ~TransliterationModules_IGNORE_CASE; + else + m_nTransliterationFlags |= TransliterationModules_IGNORE_CASE; +} + +//------------------------------------------------------------------------ +sal_Bool FmSearchEngine::GetCaseSensitive() const +{ + return 0 == (m_nTransliterationFlags & TransliterationModules_IGNORE_CASE); +} + +//------------------------------------------------------------------------ +void FmSearchEngine::clearControlTexts() +{ + for ( ControlTextSuppliersIterator aIter = m_aControlTexts.begin(); + aIter < m_aControlTexts.end(); + ++aIter + ) + { + delete *aIter; + } + m_aControlTexts.clear(); +} + +//------------------------------------------------------------------------ +void FmSearchEngine::fillControlTexts(const InterfaceArray& arrFields) +{ + clearControlTexts(); + Reference< XInterface > xCurrent; + for (sal_uInt32 i=0; i<arrFields.size(); ++i) + { + xCurrent = arrFields.at(i); + DBG_ASSERT(xCurrent.is(), "FmSearchEngine::fillControlTexts : invalid field interface !"); + // check which type of control this is + Reference< ::com::sun::star::awt::XTextComponent > xAsText(xCurrent, UNO_QUERY); + if (xAsText.is()) + { + m_aControlTexts.insert(m_aControlTexts.end(), new SimpleTextWrapper(xAsText)); + continue; + } + + Reference< ::com::sun::star::awt::XListBox > xAsListBox(xCurrent, UNO_QUERY); + if (xAsListBox.is()) + { + m_aControlTexts.insert(m_aControlTexts.end(), new ListBoxWrapper(xAsListBox)); + continue; + } + + Reference< ::com::sun::star::awt::XCheckBox > xAsCheckBox(xCurrent, UNO_QUERY); + DBG_ASSERT(xAsCheckBox.is(), "FmSearchEngine::fillControlTexts : invalid field interface (no supported type) !"); + // we don't have any more options ... + m_aControlTexts.insert(m_aControlTexts.end(), new CheckBoxWrapper(xAsCheckBox)); + } +} + +//------------------------------------------------------------------------ +void FmSearchEngine::Init(const ::rtl::OUString& sVisibleFields) +{ + // analyze the fields + // additionally, create the mapping: because the list of used columns can be shorter than the list + // of columns of the cursor, we need a mapping: "used column numer n" -> "cursor column m" + m_arrFieldMapping.Remove(0, m_arrFieldMapping.Count()); + + // important: The case of the columns does not need to be exact - for instance: + // - a user created a form which works on a table, for which the driver returns a column name "COLUMN" + // - the driver itself works case-insensitve with column names + // - a control in the form is bound to "column" - not the different case + // In such a scenario, the form and the field would work okay, but we here need to case for the different case + // explicitly + // 2003-01-09 - #i8755# - fs@openoffice.org + + // so first of all, check if the database handles identifiers case sensitive + Reference< XConnection > xConn; + Reference< XDatabaseMetaData > xMeta; + Reference< XPropertySet > xCursorProps( IFACECAST( m_xSearchCursor ), UNO_QUERY ); + if ( xCursorProps.is() ) + { + try + { + xCursorProps->getPropertyValue( FM_PROP_ACTIVE_CONNECTION ) >>= xConn; + } + catch( Exception& ) { /* silent this - will be asserted below */ } + } + if ( xConn.is() ) + xMeta = xConn->getMetaData(); + OSL_ENSURE( xMeta.is(), "FmSearchEngine::Init: very strange cursor (could not derive connection meta data from it)!" ); + + sal_Bool bCaseSensitiveIdentifiers = sal_True; // assume case sensivity + if ( xMeta.is() ) + bCaseSensitiveIdentifiers = xMeta->supportsMixedCaseQuotedIdentifiers(); + + // now that we have this information, we need a collator which is able to case (in)sentively compare strings + m_aStringCompare.loadDefaultCollator( SvtSysLocale().GetLocaleData().getLocale(), + bCaseSensitiveIdentifiers ? 0 : ::com::sun::star::i18n::CollatorOptions::CollatorOptions_IGNORE_CASE ); + + try + { + // der Cursor kann mir einen Record (als PropertySet) liefern, dieser unterstuetzt den DatabaseRecord-Service + Reference< ::com::sun::star::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY); + DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::Init : invalid cursor (no columns supplier) !"); + Reference< ::com::sun::star::container::XNameAccess > xAllFieldNames = xSupplyCols->getColumns(); + Sequence< ::rtl::OUString > seqFieldNames = xAllFieldNames->getElementNames(); + ::rtl::OUString* pFieldNames = seqFieldNames.getArray(); + + + ::rtl::OUString sCurrentField; + UniString sVis(sVisibleFields.getStr()); + xub_StrLen nLen = sVis.GetTokenCount(); + for (xub_StrLen i=0; i<nLen; ++i) + { + sCurrentField = sVis.GetToken(i); + + // in der Feld-Sammlung suchen + sal_Int32 nFoundIndex = -1; + for (sal_Int32 j=0; j<seqFieldNames.getLength(); ++j, ++pFieldNames) + { + if ( 0 == m_aStringCompare.compareString( *pFieldNames, sCurrentField ) ) + { + nFoundIndex = j; + break; + } + } + // set the field selection back to the first + pFieldNames = seqFieldNames.getArray();; + DBG_ASSERT(nFoundIndex != -1, "FmSearchEngine::Init : Es wurden ungueltige Feldnamen angegeben !"); + m_arrFieldMapping.Insert(nFoundIndex, m_arrFieldMapping.Count()); + } + } + catch(Exception&) + { + DBG_ERROR("Exception occurred!"); + } + +} + +//------------------------------------------------------------------------ +void FmSearchEngine::SetFormatterUsing(sal_Bool bSet) +{ + if (m_bFormatter == bSet) + return; + m_bFormatter = bSet; + + if (m_bUsingTextComponents) + { + // ich benutzte keinen Formatter, sondern TextComponents -> der SearchIterator muss angepasst werden + try + { + if (m_bFormatter) + { + DBG_ASSERT(m_xSearchCursor == m_xClonedIterator, "FmSearchEngine::SetFormatterUsing : inkonsistenter Zustand !"); + m_xSearchCursor = m_xOriginalIterator; + m_xSearchCursor.moveToBookmark(m_xClonedIterator.getBookmark()); + // damit ich mit dem neuen Iterator wirklich dort weitermache, wo ich vorher aufgehoert habe + } + else + { + DBG_ASSERT(m_xSearchCursor == m_xOriginalIterator, "FmSearchEngine::SetFormatterUsing : inkonsistenter Zustand !"); + m_xSearchCursor = m_xClonedIterator; + m_xSearchCursor.moveToBookmark(m_xOriginalIterator.getBookmark()); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + // ich muss die Fields neu binden, da der Textaustausch eventuell ueber diese Fields erfolgt und sich der unterliegende Cursor + // geaendert hat + RebuildUsedFields(m_nCurrentFieldIndex, sal_True); + } + else + InvalidatePreviousLoc(); +} + +//------------------------------------------------------------------------ +void FmSearchEngine::PropagateProgress(sal_Bool _bDontPropagateOverflow) +{ + if (m_aProgressHandler.IsSet()) + { + FmSearchProgress aProgress; + try + { + aProgress.aSearchState = FmSearchProgress::STATE_PROGRESS; + aProgress.nCurrentRecord = m_xSearchCursor.getRow() - 1; + if (m_bForward) + aProgress.bOverflow = !_bDontPropagateOverflow && m_xSearchCursor.isFirst(); + else + aProgress.bOverflow = !_bDontPropagateOverflow && m_xSearchCursor.isLast(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + m_aProgressHandler.Call(&aProgress); + } +} + +//------------------------------------------------------------------------ +void FmSearchEngine::SearchNextImpl() +{ + DBG_ASSERT(!(m_bWildcard && m_bRegular) && !(m_bRegular && m_bLevenshtein) && !(m_bLevenshtein && m_bWildcard), + "FmSearchEngine::SearchNextImpl : Suchparameter schliessen sich gegenseitig aus !"); + + DBG_ASSERT(m_xSearchCursor.is(), "FmSearchEngine::SearchNextImpl : habe ungueltigen Iterator !"); + + // die Parameter der Suche + ::rtl::OUString strSearchExpression(m_strSearchExpression); // brauche ich non-const + if (!GetCaseSensitive()) + // norm the string + m_aCharacterClassficator.toLower_rtl(strSearchExpression); + + if (!m_bRegular && !m_bLevenshtein) + { // 'normale' Suche fuehre ich auf jeden Fall ueber WildCards durch, muss aber vorher je nach Modus den ::rtl::OUString anpassen + + if (!m_bWildcard) + { // da natuerlich in allen anderen Faellen auch * und ? im Suchstring erlaubt sind, aber nicht als WildCards zaehlen + // sollen, muss ich normieren + UniString aTmp(strSearchExpression.getStr()); + static const UniString s_sStar = UniString::CreateFromAscii("\\*"); + static const UniString s_sQuotation = UniString::CreateFromAscii("\\?"); + aTmp.SearchAndReplaceAll('*', s_sStar); + aTmp.SearchAndReplaceAll('?', s_sQuotation); + strSearchExpression = aTmp; + + switch (m_nPosition) + { + case MATCHING_ANYWHERE : + strSearchExpression = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")) + strSearchExpression + + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")); + break; + case MATCHING_BEGINNING : + strSearchExpression = strSearchExpression + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")); + break; + case MATCHING_END : + strSearchExpression = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")) + strSearchExpression; + break; + case MATCHING_WHOLETEXT : + break; + default : + DBG_ERROR("FmSearchEngine::SearchNextImpl() : die Methoden-Listbox duerfte nur 4 Eintraege enthalten ..."); + } + } + } + + // fuer Arbeit auf Feldliste + FieldCollectionIterator iterBegin = m_arrUsedFields.begin(); + FieldCollectionIterator iterEnd = m_arrUsedFields.end(); + FieldCollectionIterator iterFieldCheck; + + sal_Int32 nFieldPos; + + if (HasPreviousLoc()) + { + DBG_ASSERT(EQUAL_BOOKMARKS(m_aPreviousLocBookmark, m_xSearchCursor.getBookmark()), + "FmSearchEngine::SearchNextImpl : ungueltige Position !"); + iterFieldCheck = m_iterPreviousLocField; + // im Feld nach (oder vor) der letzten Fundstelle weitermachen + nFieldPos = iterFieldCheck - iterBegin; + MoveField(nFieldPos, iterFieldCheck, iterBegin, iterEnd); + } + else + { + if (m_bForward) + iterFieldCheck = iterBegin; + else + { + iterFieldCheck = iterEnd; + --iterFieldCheck; + } + nFieldPos = iterFieldCheck - iterBegin; + } + + PropagateProgress(sal_True); + SEARCH_RESULT srResult; + if (m_eSearchForType != SEARCHFOR_STRING) + srResult = SearchSpecial(m_eSearchForType == SEARCHFOR_NULL, nFieldPos, iterFieldCheck, iterBegin, iterEnd); + else if (!m_bRegular && !m_bLevenshtein) + srResult = SearchWildcard(strSearchExpression, nFieldPos, iterFieldCheck, iterBegin, iterEnd); + else + srResult = SearchRegularApprox(strSearchExpression, nFieldPos, iterFieldCheck, iterBegin, iterEnd); + + m_srResult = srResult; + + if (SR_ERROR == m_srResult) + return; + + // gefunden ? + if (SR_FOUND == m_srResult) + { + // die Pos merken + try { m_aPreviousLocBookmark = m_xSearchCursor.getBookmark(); } + catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } + m_iterPreviousLocField = iterFieldCheck; + } + else + // die "letzte Fundstelle" invalidieren + InvalidatePreviousLoc(); +} + +//------------------------------------------------------------------------ +IMPL_LINK(FmSearchEngine, OnSearchTerminated, FmSearchThread*, /*pThread*/) +{ + if (!m_aProgressHandler.IsSet()) + return 0L; + + FmSearchProgress aProgress; + try + { + switch (m_srResult) + { + case SR_ERROR : + aProgress.aSearchState = FmSearchProgress::STATE_ERROR; + break; + case SR_FOUND : + aProgress.aSearchState = FmSearchProgress::STATE_SUCCESSFULL; + aProgress.aBookmark = m_aPreviousLocBookmark; + aProgress.nFieldIndex = m_iterPreviousLocField - m_arrUsedFields.begin(); + break; + case SR_NOTFOUND : + aProgress.aSearchState = FmSearchProgress::STATE_NOTHINGFOUND; + aProgress.aBookmark = m_xSearchCursor.getBookmark(); + break; + case SR_CANCELED : + aProgress.aSearchState = FmSearchProgress::STATE_CANCELED; + aProgress.aBookmark = m_xSearchCursor.getBookmark(); + break; + } + aProgress.nCurrentRecord = m_xSearchCursor.getRow() - 1; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + // per definitionem muss der Link Thread-sicher sein (das verlange ich einfach), so dass ich mich um so etwas hier nicht kuemmern muss + m_aProgressHandler.Call(&aProgress); + + m_bSearchingCurrently = sal_False; + return 0L; +} + +//------------------------------------------------------------------------ +IMPL_LINK(FmSearchEngine, OnNewRecordCount, void*, pCounterAsVoid) +{ + if (!m_aProgressHandler.IsSet()) + return 0L; + + FmSearchProgress aProgress; + aProgress.nCurrentRecord = (sal_uIntPtr)pCounterAsVoid; + aProgress.aSearchState = FmSearchProgress::STATE_PROGRESS_COUNTING; + m_aProgressHandler.Call(&aProgress); + + return 0L; +} + +//------------------------------------------------------------------------ +sal_Bool FmSearchEngine::CancelRequested() +{ + m_aCancelAsynchAccess.acquire(); + sal_Bool bReturn = m_bCancelAsynchRequest; + m_aCancelAsynchAccess.release(); + return bReturn; +} + +//------------------------------------------------------------------------ +void FmSearchEngine::CancelSearch() +{ + m_aCancelAsynchAccess.acquire(); + m_bCancelAsynchRequest = sal_True; + m_aCancelAsynchAccess.release(); +} + +//------------------------------------------------------------------------ +sal_Bool FmSearchEngine::SwitchToContext(const Reference< ::com::sun::star::sdbc::XResultSet > & xCursor, const ::rtl::OUString& sVisibleFields, const InterfaceArray& arrFields, + sal_Int32 nFieldIndex) +{ + DBG_ASSERT(!m_bSearchingCurrently, "FmSearchEngine::SwitchToContext : please do not call while I'm searching !"); + if (m_bSearchingCurrently) + return sal_False; + + m_xSearchCursor = xCursor; + m_xOriginalIterator = xCursor; + m_xClonedIterator = CursorWrapper(m_xOriginalIterator, sal_True); + m_bUsingTextComponents = sal_True; + + fillControlTexts(arrFields); + + Init(sVisibleFields); + RebuildUsedFields(nFieldIndex, sal_True); + + return sal_True; +} + +//------------------------------------------------------------------------ +void FmSearchEngine::ImplStartNextSearch() +{ + m_bCancelAsynchRequest = sal_False; + m_bSearchingCurrently = sal_True; + + if (m_eMode == SM_USETHREAD) + { + FmSearchThread* pSearcher = new FmSearchThread(this); + // der loescht sich nach Beendigung selber ... + pSearcher->setTerminationHandler(LINK(this, FmSearchEngine, OnSearchTerminated)); + + pSearcher->createSuspended(); + pSearcher->setPriority(osl_Thread_PriorityLowest); + pSearcher->resume(); + } + else + { + SearchNextImpl(); + LINK(this, FmSearchEngine, OnSearchTerminated).Call(NULL); + } +} + +//------------------------------------------------------------------------ +void FmSearchEngine::SearchNext(const ::rtl::OUString& strExpression) +{ + m_strSearchExpression = strExpression; + m_eSearchForType = SEARCHFOR_STRING; + ImplStartNextSearch(); +} + +//------------------------------------------------------------------------ +void FmSearchEngine::SearchNextSpecial(sal_Bool _bSearchForNull) +{ + m_eSearchForType = _bSearchForNull ? SEARCHFOR_NULL : SEARCHFOR_NOTNULL; + ImplStartNextSearch(); +} + +//------------------------------------------------------------------------ +void FmSearchEngine::StartOver(const ::rtl::OUString& strExpression) +{ + try + { + if (m_bForward) + m_xSearchCursor.first(); + else + m_xSearchCursor.last(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + return; + } + + InvalidatePreviousLoc(); + SearchNext(strExpression); +} + +//------------------------------------------------------------------------ +void FmSearchEngine::StartOverSpecial(sal_Bool _bSearchForNull) +{ + try + { + if (m_bForward) + m_xSearchCursor.first(); + else + m_xSearchCursor.last(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + return; + } + + InvalidatePreviousLoc(); + SearchNextSpecial(_bSearchForNull); +} + +//------------------------------------------------------------------------ +void FmSearchEngine::InvalidatePreviousLoc() +{ + m_aPreviousLocBookmark.setValue(0,getVoidCppuType()); + m_iterPreviousLocField = m_arrUsedFields.end(); +} + +//------------------------------------------------------------------------ +void FmSearchEngine::RebuildUsedFields(sal_Int32 nFieldIndex, sal_Bool bForce) +{ + if (!bForce && (nFieldIndex == m_nCurrentFieldIndex)) + return; + // (da ich keinen Wechsel des Iterators von aussen zulasse, heisst selber ::com::sun::star::sdbcx::Index auch immer selbe Spalte, also habe ich nix zu tun) + + DBG_ASSERT((nFieldIndex >= -1) && (nFieldIndex<m_arrFieldMapping.Count()), "FmSearchEngine::RebuildUsedFields : nFieldIndex ist ungueltig !"); + // alle Felder, die ich durchsuchen muss, einsammeln + m_arrUsedFields.clear(); + if (nFieldIndex == -1) + { + Reference< ::com::sun::star::container::XIndexAccess > xFields; + for (sal_uInt16 i=0; i<m_arrFieldMapping.Count(); ++i) + { + Reference< ::com::sun::star::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY); + DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::RebuildUsedFields : invalid cursor (no columns supplier) !"); + xFields = Reference< ::com::sun::star::container::XIndexAccess > (xSupplyCols->getColumns(), UNO_QUERY); + BuildAndInsertFieldInfo(xFields, m_arrFieldMapping.GetObject(i)); + } + } + else + { + Reference< ::com::sun::star::container::XIndexAccess > xFields; + Reference< ::com::sun::star::sdbcx::XColumnsSupplier > xSupplyCols(IFACECAST(m_xSearchCursor), UNO_QUERY); + DBG_ASSERT(xSupplyCols.is(), "FmSearchEngine::RebuildUsedFields : invalid cursor (no columns supplier) !"); + xFields = Reference< ::com::sun::star::container::XIndexAccess > (xSupplyCols->getColumns(), UNO_QUERY); + BuildAndInsertFieldInfo(xFields, m_arrFieldMapping.GetObject((sal_uInt16)nFieldIndex)); + } + + m_nCurrentFieldIndex = nFieldIndex; + // und natuerlich beginne ich die naechste Suche wieder jungfraeulich + InvalidatePreviousLoc(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmstring.src b/svx/source/form/fmstring.src new file mode 100644 index 000000000000..8e3df1a8cdf5 --- /dev/null +++ b/svx/source/form/fmstring.src @@ -0,0 +1,491 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "fmresids.hrc" +/* Strings fuer Uebersetzung */ +String RID_ERR_CONTEXT_ADDFORM +{ + Text [ en-US ] = "Error while creating form"; +}; +String RID_ERR_FIELDREQUIRED +{ + Text [ en-US ] = "Input required in field '#'. Please enter a value."; +}; +String RID_ERR_DUPLICATE_NAME +{ + Text [ en-US ] = "Entry already exists.\nPlease choose another name."; +}; +String RID_STR_FORMS +{ + Text [ en-US ] = "Forms"; +}; +String RID_STR_NO_PROPERTIES +{ + Text [ en-US ] = "No control selected"; +}; +String RID_STR_PROPERTIES_CONTROL +{ + /* ### ACHTUNG: Neuer Text in Resource? Eigenschaften: : Kontrollelement Eigenschaften */ + Text [ en-US ] = "Properties: "; +}; +String RID_STR_PROPERTIES_FORM +{ + Text [ en-US ] = "Form Properties"; +}; +String RID_STR_FMEXPLORER +{ + Text [ en-US ] = "Form Navigator"; +}; +String RID_STR_FORM +{ + Text [ en-US ] = "Form"; +}; +Resource RID_RSC_TABWIN_PREFIX +{ + String 1 + { + Text [ en-US ] = "Table"; + }; + String 2 + { + Text [ en-US ] = "Query"; + }; + String 3 + { + Text [ en-US ] = "SQL"; + }; +}; +String RID_STR_FORMSHELL +{ + Text = "Form Shell"; +}; +String RID_STR_STDFORMNAME +{ + Text [ en-US ]= "Form"; +}; +String RID_STR_PROPTITLE_HIDDEN +{ + Text [ en-US ] = "Hidden Control"; +}; +String RID_STR_CONTROL +{ + Text [ en-US ] = "Control"; +}; +String RID_STR_REC_TEXT +{ + Text [ en-US ] = "Record"; +}; +String RID_STR_REC_FROM_TEXT +{ + Text [ en-US ] = "of"; +}; +String RID_STR_FIELDSELECTION +{ + Text [ en-US ] = "Add field:"; +}; +String RID_STR_WRITEERROR +{ + Text [ en-US ] = "Error writing data to database"; +}; + +String RID_STR_SYNTAXERROR +{ + Text [ en-US ] = "Syntax error in query expression"; +}; + +String RID_STR_DELETECONFIRM_RECORD +{ + Text [ en-US ] = "You intend to delete 1 record."; +}; +String RID_STR_DELETECONFIRM_RECORDS +{ + Text [ en-US ] = "# records will be deleted."; +}; +String RID_STR_DELETECONFIRM +{ + Text [ en-US ] = "If you click Yes, you won't be able to undo this operation.\nDo you want to continue anyway?"; +}; + +String RID_ERR_NO_ELEMENT +{ + Text [ en-US ] = "Choose an entry from the list or enter a text corresponding to one of the list items."; +}; +String RID_STR_GROUPBOX +{ + Text [ en-US ] = "Frame element"; +}; +String RID_STR_NAVIGATION +{ + Text [ en-US ] = "Navigation"; +}; +String RID_STR_NAVIGATIONBAR +{ + Text [ en-US ] = "Navigation bar"; +}; +String RID_STR_COLUMN +{ + Text [ en-US ] = "Col"; +}; +String RID_STR_UNDO_PROPERTY +{ + Text [ en-US ] = "Set property '#'"; +}; +String RID_STR_UNDO_CONTAINER_INSERT +{ + Text [ en-US ] = "Insert in container"; +}; +String RID_STR_UNDO_CONTAINER_REMOVE +{ + Text [ en-US ] = "Delete #"; +}; +String RID_STR_UNDO_CONTAINER_REMOVE_MULTIPLE +{ + Text [ en-US ] = "Delete # objects"; +}; +String RID_STR_UNDO_CONTAINER_REPLACE +{ + Text [ en-US ] = "Replace a container element"; +}; +String RID_STR_UNDO_DELETE_LOGICAL +{ + Text [ en-US ] = "Delete structure"; +}; +String RID_STR_UNDO_MODEL_REPLACE +{ + Text [ en-US ] = "Replace Control"; +}; +String RID_STR_DATE +{ + Text [ en-US ] = "Date"; +}; +String RID_STR_TIME +{ + Text [ en-US ] = "Time"; +}; +String RID_STR_PROPTITLE_PUSHBUTTON +{ + Text [ en-US ] = "Push Button"; +}; +String RID_STR_PROPTITLE_RADIOBUTTON +{ + Text [ en-US ] = "Option Button"; +}; +String RID_STR_PROPTITLE_CHECKBOX +{ + Text [ en-US ] = "Check Box"; +}; +String RID_STR_PROPTITLE_FIXEDTEXT +{ + Text [ en-US ] = "Label Field"; +}; +String RID_STR_PROPTITLE_GROUPBOX +{ + Text [ en-US ] = "Group Box"; +}; +String RID_STR_PROPTITLE_EDIT +{ + Text [ en-US ] = "Text Box"; +}; +String RID_STR_PROPTITLE_FORMATTED +{ + Text [ en-US ] = "Formatted Field"; +}; +String RID_STR_PROPTITLE_LISTBOX +{ + Text [ en-US ] = "List Box"; +}; +String RID_STR_PROPTITLE_COMBOBOX +{ + Text [ en-US ] = "Combo Box"; +}; +String RID_STR_PROPTITLE_IMAGEBUTTON +{ + Text [ en-US ] = "Image Button"; +}; +String RID_STR_PROPTITLE_IMAGECONTROL +{ + Text [ en-US ] = "Image Control"; +}; +String RID_STR_PROPTITLE_FILECONTROL +{ + Text [ en-US ] = "File Selection"; +}; +String RID_STR_PROPTITLE_DATEFIELD +{ + Text [ en-US ] = "Date Field"; +}; +String RID_STR_PROPTITLE_TIMEFIELD +{ + Text [ en-US ] = "Time Field"; +}; +String RID_STR_PROPTITLE_NUMERICFIELD +{ + Text [ en-US ] = "Numeric Field"; +}; +String RID_STR_PROPTITLE_CURRENCYFIELD +{ + Text [ en-US ] = "Currency Field"; +}; +String RID_STR_PROPTITLE_PATTERNFIELD +{ + Text [ en-US ] = "Pattern Field"; +}; +String RID_STR_PROPTITLE_DBGRID +{ + Text [ en-US ] = "Table Control "; +}; +String RID_STR_PROPTITLE_SCROLLBAR +{ + Text [ en-US ] = "Scrollbar"; +}; +String RID_STR_PROPTITLE_SPINBUTTON +{ + Text [ en-US ] = "Spin Button"; +}; +String RID_STR_PROPTITLE_NAVBAR +{ + Text [ en-US ] = "Navigation Bar"; +}; +String RID_STR_PROPTITLE_MULTISELECT +{ + Text [ en-US ] = "Multiselection"; +}; +String RID_STR_NODATACONTROLS +{ + Text [ en-US ] = "No data-related controls in the current form!"; +}; +String RID_STR_POSTFIX_DATE +{ + Text [ en-US ] = " (Date)"; +}; +String RID_STR_POSTFIX_TIME +{ + Text [ en-US ] = " (Time)"; +}; +String RID_STR_FILTER_NAVIGATOR +{ + Text [ en-US ] = "Filter navigator"; +}; + +String RID_STR_FILTER_FILTER_FOR +{ + Text [ en-US ] = "Filter for"; +}; + +String RID_STR_FILTER_FILTER_OR +{ + Text [ en-US ] = "Or"; +}; + +String RID_STR_NOCONTROLS_FOR_EXTERNALDISPLAY +{ + Text [ en-US ] = "Valid bound controls which can be used in the table view do not exist in the current form."; +}; +String RID_STR_AUTOFIELD +{ + Text [ en-US ] = "<AutoField>"; +}; + +QueryBox RID_QRY_SAVEMODIFIED +{ + Buttons = WB_YES_NO_CANCEL ; + DefButton = WB_DEF_YES ; + Message [ en-US ] = "The content of the current form has been modified.\nDo you want to save your changes?"; +}; +Resource RID_RSC_SQL_INTERNATIONAL +{ + String 1 + { + Text [ en-US ] = "LIKE"; + }; + String 2 + { + Text [ en-US ] = "NOT"; + }; + String 3 + { + Text [ en-US ] = "EMPTY"; + }; + String 4 + { + Text [ en-US ] = "TRUE"; + }; + String 5 + { + Text [ en-US ] = "FALSE"; + }; + String 6 + { + Text [ en-US ] = "IS"; + }; + String 7 + { + Text [ en-US ] = "BETWEEN"; + }; + String 8 + { + Text [ en-US ] = "OR"; + }; + String 9 + { + Text [ en-US ] = "AND"; + }; + String 10 + { + Text [ en-US ] = "Average"; + }; + String 11 + { + Text [ en-US ] = "Count"; + }; + String 12 + { + Text [ en-US ] = "Maximum"; + }; + String 13 + { + Text [ en-US ] = "Minimum"; + }; + String 14 + { + Text [ en-US ] = "Sum"; + }; + String 15 + { + Text [ en-US ] = "Every"; + }; + String 16 + { + Text [ en-US ] = "Any"; + }; + String 17 + { + Text [ en-US ] = "Some"; + }; + String 18 + { + Text [ en-US ] = "STDDEV_POP"; + }; + String 19 + { + Text [ en-US ] = "STDDEV_SAMP"; + }; + String 20 + { + Text [ en-US ] = "VAR_SAMP"; + }; + String 21 + { + Text [ en-US ] = "VAR_POP"; + }; + String 22 + { + Text [ en-US ] = "Collect"; + }; + String 23 + { + Text [ en-US ] = "Fusion"; + }; + String 24 + { + Text [ en-US ] = "Intersection"; + }; +}; + +String RID_STR_SVT_SQL_SYNTAX_ERROR +{ + /* ### ACHTUNG: Neuer Text in Resource? Syntaxfehler im SQL-Ausdruck : Fehlerhafte Syntax */ + Text [ en-US ] = "Syntax error in SQL statement"; +}; + +String RID_STR_SVT_SQL_SYNTAX_VALUE_NO_LIKE +{ + Text [ en-US ] = "The value #1 cannot be used with LIKE."; +}; + +String RID_STR_SVT_SQL_SYNTAX_FIELD_NO_LIKE +{ + Text [ en-US ] = "LIKE cannot be used with this field."; +}; + +String RID_STR_SVT_SQL_SYNTAX_ACCESS_DAT_NO_VALID +{ + Text [ en-US ] = "The value entered is not a valid date. Please enter a date in a valid format, for example, MM/DD/YY."; +}; + +String RID_STR_SVT_SQL_SYNTAX_INT_NO_VALID +{ + Text [ en-US ] = "The field cannot be compared with an integer."; +}; +String RID_STR_SVT_SQL_SYNTAX_TABLE +{ + Text [ en-US ] = "The database does not contain a table named \"#\"."; +}; +String RID_STR_SVT_SQL_SYNTAX_TABLE_OR_QUERY +{ + Text [ en-US ] = "The database does contain neither a table nor a query named \"#\"."; +}; +String RID_STR_SVT_SQL_SYNTAX_TABLE_EXISTS +{ + Text [ en-US ] = "The database already contains a table or view with name \"#\"."; +}; +String RID_STR_SVT_SQL_SYNTAX_QUERY_EXISTS +{ + Text [ en-US ] = "The database already contains a query with name \"#\"."; +}; +String RID_STR_SVT_SQL_SYNTAX_COLUMN +{ + Text [ en-US ] = "The column \"#1\" is unknown in the table \"#2\"."; +}; +String RID_STR_SVT_SQL_SYNTAX_REAL_NO_VALID +{ + Text [ en-US ] = "The field cannot be compared with a floating point number."; +}; + +String RID_STR_SVT_SQL_SYNTAX_CRIT_NO_COMPARE +{ + Text [ en-US ] = "The entered criterion cannot be compared with this field."; +}; + +String RID_STR_DATANAVIGATOR +{ + Text [ en-US ] = "Data Navigator"; +}; + +String RID_STR_READONLY_VIEW +{ + Text [ en-US ] = " (read-only)"; +}; + +String RID_STR_ALREADYEXISTOVERWRITE +{ + Text [ en-US ] = "The file already exists. Overwrite?" ; +}; +String RID_STR_OBJECT_LABEL +{ + Text [ en-US ] = "#object# label"; +}; diff --git a/svx/source/form/fmtextcontroldialogs.cxx b/svx/source/form/fmtextcontroldialogs.cxx new file mode 100644 index 000000000000..388371ea7b49 --- /dev/null +++ b/svx/source/form/fmtextcontroldialogs.cxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include "fmtextcontroldialogs.hxx" +#include <svx/dialmgr.hxx> +#include <svx/dialogs.hrc> + +#include <editeng/eeitem.hxx> + +#include "flagsdef.hxx" +#include <svl/intitem.hxx> + +#include <com/sun/star/uno/Sequence.hxx> +#include <svl/cjkoptions.hxx> + +//........................................................................ +namespace svx +{ +//........................................................................ + + //==================================================================== + //= TextControlCharAttribDialog + //==================================================================== + //-------------------------------------------------------------------- + TextControlCharAttribDialog::TextControlCharAttribDialog( Window* pParent, const SfxItemSet& _rCoreSet, const SvxFontListItem& _rFontList ) + :SfxTabDialog( pParent, SVX_RES( RID_SVXDLG_TEXTCONTROL_CHARATTR ), &_rCoreSet ) + ,m_aFontList( _rFontList ) + { + FreeResource(); + + AddTabPage( RID_SVXPAGE_CHAR_NAME); + AddTabPage( RID_SVXPAGE_CHAR_EFFECTS); + AddTabPage( RID_SVXPAGE_CHAR_POSITION); + } + + //-------------------------------------------------------------------- + TextControlCharAttribDialog::~TextControlCharAttribDialog() + { + } + + //-------------------------------------------------------------------- + void TextControlCharAttribDialog::PageCreated( USHORT _nId, SfxTabPage& _rPage ) + { + SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool())); + + switch( _nId ) + { + case RID_SVXPAGE_CHAR_NAME: + aSet.Put (m_aFontList); + _rPage.PageCreated(aSet); + break; + + case RID_SVXPAGE_CHAR_EFFECTS: + aSet.Put (SfxUInt16Item(SID_DISABLE_CTL,DISABLE_CASEMAP)); + _rPage.PageCreated(aSet); + break; + + case RID_SVXPAGE_CHAR_POSITION: + aSet.Put( SfxUInt32Item(SID_FLAG_TYPE, SVX_PREVIEW_CHARACTER) ); + _rPage.PageCreated(aSet); + break; + } + } + + //==================================================================== + //= TextControlParaAttribDialog + //==================================================================== + //-------------------------------------------------------------------- + TextControlParaAttribDialog::TextControlParaAttribDialog( Window* _pParent, const SfxItemSet& _rCoreSet ) + :SfxTabDialog( _pParent, SVX_RES( RID_SVXDLG_TEXTCONTROL_PARAATTR ), &_rCoreSet ) + { + FreeResource(); + + AddTabPage( RID_SVXPAGE_STD_PARAGRAPH ); + AddTabPage( RID_SVXPAGE_ALIGN_PARAGRAPH ); + + SvtCJKOptions aCJKOptions; + if( aCJKOptions.IsAsianTypographyEnabled() ) + AddTabPage( RID_SVXPAGE_PARA_ASIAN ); + else + RemoveTabPage( RID_SVXPAGE_PARA_ASIAN ); + + AddTabPage( RID_SVXPAGE_TABULATOR ); + } + + //-------------------------------------------------------------------- + TextControlParaAttribDialog::~TextControlParaAttribDialog() + { + } + +//........................................................................ +} // namespace svx +//........................................................................ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmtextcontrolfeature.cxx b/svx/source/form/fmtextcontrolfeature.cxx new file mode 100644 index 000000000000..c773881cb3da --- /dev/null +++ b/svx/source/form/fmtextcontrolfeature.cxx @@ -0,0 +1,133 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include "fmtextcontrolfeature.hxx" + +/** === begin UNO includes === **/ +/** === end UNO includes === **/ + +//........................................................................ +namespace svx +{ +//........................................................................ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::util; + + //==================================================================== + //= FmTextControlFeature + //==================================================================== + //-------------------------------------------------------------------- + FmTextControlFeature::FmTextControlFeature( const Reference< XDispatch >& _rxDispatcher, const URL& _rFeatureURL, SfxSlotId _nSlotId, ISlotInvalidator* _pInvalidator ) + :m_xDispatcher ( _rxDispatcher ) + ,m_aFeatureURL ( _rFeatureURL ) + ,m_nSlotId ( _nSlotId ) + ,m_pInvalidator ( _pInvalidator ) + ,m_bFeatureEnabled( false ) + { + OSL_ENSURE( _rxDispatcher.is(), "FmTextControlFeature::FmTextControlFeature: invalid dispatcher!" ); + OSL_ENSURE( m_nSlotId, "FmTextControlFeature::FmTextControlFeature: invalid slot id!" ); + OSL_ENSURE( m_pInvalidator, "FmTextControlFeature::FmTextControlFeature: invalid invalidator!" ); + + osl_incrementInterlockedCount( &m_refCount ); + try + { + m_xDispatcher->addStatusListener( this, m_aFeatureURL ); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FmTextControlFeature::FmTextControlFeature: caught an exception!" ); + } + osl_decrementInterlockedCount( &m_refCount ); + } + + //-------------------------------------------------------------------- + FmTextControlFeature::~FmTextControlFeature( ) + { + } + + //-------------------------------------------------------------------- + void FmTextControlFeature::dispatch() const SAL_THROW(()) + { + dispatch( Sequence< PropertyValue >( ) ); + } + + //-------------------------------------------------------------------- + void FmTextControlFeature::dispatch( const Sequence< PropertyValue >& _rArgs ) const SAL_THROW(()) + { + try + { + if ( m_xDispatcher.is() ) + m_xDispatcher->dispatch( m_aFeatureURL, _rArgs ); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FmTextControlFeature::dispatch: caught an exception!" ); + } + } + + //-------------------------------------------------------------------- + void SAL_CALL FmTextControlFeature::statusChanged( const FeatureStateEvent& _rState ) throw (RuntimeException) + { + m_aFeatureState = _rState.State; + m_bFeatureEnabled = _rState.IsEnabled; + + if ( m_pInvalidator ) + m_pInvalidator->Invalidate( m_nSlotId ); + } + + //-------------------------------------------------------------------- + void SAL_CALL FmTextControlFeature::disposing( const EventObject& /*Source*/ ) throw (RuntimeException) + { + // nothing to do + } + + //-------------------------------------------------------------------- + void FmTextControlFeature::dispose() SAL_THROW(()) + { + try + { + m_xDispatcher->removeStatusListener( this, m_aFeatureURL ); + m_xDispatcher.clear(); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FmTextControlFeature::dispose: caught an exception!" ); + } + } + +//........................................................................ +} // namespace svx +//........................................................................ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmtextcontrolshell.cxx b/svx/source/form/fmtextcontrolshell.cxx new file mode 100644 index 000000000000..a1a3f1592f68 --- /dev/null +++ b/svx/source/form/fmtextcontrolshell.cxx @@ -0,0 +1,1401 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include "fmprop.hrc" +#include "fmresids.hrc" +#include "fmtextcontroldialogs.hxx" +#include "fmtextcontrolfeature.hxx" +#include "fmtextcontrolshell.hxx" +#include "editeng/crsditem.hxx" +#include "svx/dialmgr.hxx" +#include "editeng/editeng.hxx" +#include "editeng/eeitem.hxx" +#include "svx/fmglob.hxx" +#include "editeng/scriptspaceitem.hxx" +#include "svx/svxids.hrc" +#include "editeng/udlnitem.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/awt/FontDescriptor.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/form/XForm.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/awt/XFocusListener.hpp> +#include <com/sun/star/awt/XMouseListener.hpp> +/** === end UNO includes === **/ + +#include <comphelper/componentcontext.hxx> +#include <comphelper/processfactory.hxx> +#include <cppuhelper/implbase1.hxx> +#include <sfx2/app.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/msgpool.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/request.hxx> +#include <sfx2/sfxuno.hxx> +#include <sfx2/viewfrm.hxx> +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#include <svl/itempool.hxx> +#include <svl/languageoptions.hxx> +#include <svtools/stringtransfer.hxx> +#include <svl/whiter.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/msgbox.hxx> +#include <vcl/outdev.hxx> +#include <osl/mutex.hxx> + +#include <memory> + +//........................................................................ +namespace svx +{ +//........................................................................ + + using namespace ::com::sun::star; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::form; + using namespace ::com::sun::star::form::runtime; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::container; + + //==================================================================== + typedef USHORT WhichId; + + //==================================================================== + static SfxSlotId pTextControlSlots[] = + { + SID_CLIPBOARD_FORMAT_ITEMS, + SID_CUT, + SID_COPY, + SID_PASTE, + SID_SELECTALL, +// SID_ATTR_TABSTOP, /* 2 */ + SID_ATTR_CHAR_FONT, + SID_ATTR_CHAR_POSTURE, + SID_ATTR_CHAR_WEIGHT, + SID_ATTR_CHAR_SHADOWED, + SID_ATTR_CHAR_WORDLINEMODE, + SID_ATTR_CHAR_CONTOUR, + SID_ATTR_CHAR_STRIKEOUT, + SID_ATTR_CHAR_UNDERLINE, + SID_ATTR_CHAR_FONTHEIGHT, + SID_ATTR_CHAR_COLOR, + SID_ATTR_CHAR_KERNING, + SID_ATTR_CHAR_LANGUAGE, /* 20 */ + SID_ATTR_CHAR_ESCAPEMENT, + SID_ATTR_PARA_ADJUST, /* 28 */ + SID_ATTR_PARA_ADJUST_LEFT, + SID_ATTR_PARA_ADJUST_RIGHT, + SID_ATTR_PARA_ADJUST_CENTER, + SID_ATTR_PARA_ADJUST_BLOCK, + SID_ATTR_PARA_LINESPACE, /* 33 */ + SID_ATTR_PARA_LINESPACE_10, + SID_ATTR_PARA_LINESPACE_15, + SID_ATTR_PARA_LINESPACE_20, + SID_ATTR_LRSPACE, /* 48 */ + SID_ATTR_ULSPACE, /* 49 */ + SID_ATTR_CHAR_AUTOKERN, + SID_SET_SUPER_SCRIPT, + SID_SET_SUB_SCRIPT, + SID_CHAR_DLG, + SID_PARA_DLG, +// SID_TEXTDIRECTION_LEFT_TO_RIGHT, /* 907 */ +// SID_TEXTDIRECTION_TOP_TO_BOTTOM, + SID_ATTR_CHAR_SCALEWIDTH, /* 911 */ + SID_ATTR_CHAR_RELIEF, + SID_ATTR_PARA_LEFT_TO_RIGHT, /* 950 */ + SID_ATTR_PARA_RIGHT_TO_LEFT, + SID_ATTR_CHAR_OVERLINE, + 0 + }; + + // slots which we are not responsible for on the SfxShell level, but + // need to handle during the "paragraph attributes" and/or "character + // attributes" dialogs + static SfxSlotId pDialogSlots[] = + { + SID_ATTR_TABSTOP, + SID_ATTR_PARA_HANGPUNCTUATION, + SID_ATTR_PARA_FORBIDDEN_RULES, + SID_ATTR_PARA_SCRIPTSPACE, + SID_ATTR_CHAR_LATIN_LANGUAGE, + SID_ATTR_CHAR_CJK_LANGUAGE, + SID_ATTR_CHAR_CTL_LANGUAGE, + SID_ATTR_CHAR_LATIN_FONT, + SID_ATTR_CHAR_CJK_FONT, + SID_ATTR_CHAR_CTL_FONT, + SID_ATTR_CHAR_LATIN_FONTHEIGHT, + SID_ATTR_CHAR_CJK_FONTHEIGHT, + SID_ATTR_CHAR_CTL_FONTHEIGHT, + SID_ATTR_CHAR_LATIN_WEIGHT, + SID_ATTR_CHAR_CJK_WEIGHT, + SID_ATTR_CHAR_CTL_WEIGHT, + SID_ATTR_CHAR_LATIN_POSTURE, + SID_ATTR_CHAR_CJK_POSTURE, + SID_ATTR_CHAR_CTL_POSTURE, + SID_ATTR_CHAR_EMPHASISMARK, + 0 + }; + + //==================================================================== + //= FmFocusListenerAdapter + //==================================================================== + typedef ::cppu::WeakImplHelper1 < XFocusListener + > FmFocusListenerAdapter_Base; + class FmFocusListenerAdapter : public FmFocusListenerAdapter_Base + { + private: + IFocusObserver* m_pObserver; + Reference< XWindow > m_xWindow; + + public: + FmFocusListenerAdapter( const Reference< XControl >& _rxControl, IFocusObserver* _pObserver ); + + // clean up the instance + void dispose(); + + protected: + ~FmFocusListenerAdapter(); + + protected: + virtual void SAL_CALL focusGained( const FocusEvent& e ) throw (RuntimeException); + virtual void SAL_CALL focusLost( const FocusEvent& e ) throw (RuntimeException); + virtual void SAL_CALL disposing( const EventObject& Source ) throw (RuntimeException); + }; + + //-------------------------------------------------------------------- + DBG_NAME( FmFocusListenerAdapter ) + //-------------------------------------------------------------------- + FmFocusListenerAdapter::FmFocusListenerAdapter( const Reference< XControl >& _rxControl, IFocusObserver* _pObserver ) + :m_pObserver( _pObserver ) + ,m_xWindow( _rxControl, UNO_QUERY ) + { + DBG_CTOR( FmFocusListenerAdapter, NULL ); + + DBG_ASSERT( m_xWindow.is(), "FmFocusListenerAdapter::FmFocusListenerAdapter: invalid control!" ); + osl_incrementInterlockedCount( &m_refCount ); + { + try + { + if ( m_xWindow.is() ) + m_xWindow->addFocusListener( this ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + osl_decrementInterlockedCount( &m_refCount ); + } + + //-------------------------------------------------------------------- + FmFocusListenerAdapter::~FmFocusListenerAdapter() + { + acquire(); + dispose(); + + DBG_DTOR( FmFocusListenerAdapter, NULL ); + } + + //-------------------------------------------------------------------- + void FmFocusListenerAdapter::dispose() + { + if ( m_xWindow.is() ) + { + m_xWindow->removeFocusListener( this ); + m_xWindow.clear(); + } + } + + //-------------------------------------------------------------------- + void SAL_CALL FmFocusListenerAdapter::focusGained( const FocusEvent& e ) throw (RuntimeException) + { + if ( m_pObserver ) + m_pObserver->focusGained( e ); + } + + //-------------------------------------------------------------------- + void SAL_CALL FmFocusListenerAdapter::focusLost( const FocusEvent& e ) throw (RuntimeException) + { + if ( m_pObserver ) + m_pObserver->focusLost( e ); + } + + //-------------------------------------------------------------------- + void SAL_CALL FmFocusListenerAdapter::disposing( const EventObject& Source ) throw (RuntimeException) + { + (void)Source; + DBG_ASSERT( Source.Source == m_xWindow, "FmFocusListenerAdapter::disposing: where did this come from?" ); + m_xWindow.clear(); + } + + //==================================================================== + //= FmMouseListenerAdapter + //==================================================================== + typedef ::cppu::WeakImplHelper1 < XMouseListener + > FmMouseListenerAdapter_Base; + class FmMouseListenerAdapter : public FmMouseListenerAdapter_Base + { + private: + IContextRequestObserver* m_pObserver; + Reference< XWindow > m_xWindow; + + public: + FmMouseListenerAdapter( const Reference< XControl >& _rxControl, IContextRequestObserver* _pObserver ); + + // clean up the instance + void dispose(); + + protected: + ~FmMouseListenerAdapter(); + + protected: + virtual void SAL_CALL mousePressed( const awt::MouseEvent& e ) throw (RuntimeException); + virtual void SAL_CALL mouseReleased( const awt::MouseEvent& e ) throw (RuntimeException); + virtual void SAL_CALL mouseEntered( const awt::MouseEvent& e ) throw (RuntimeException); + virtual void SAL_CALL mouseExited( const awt::MouseEvent& e ) throw (RuntimeException); + virtual void SAL_CALL disposing( const EventObject& Source ) throw (RuntimeException); + }; + + //==================================================================== + //= FmMouseListenerAdapter + //==================================================================== + //-------------------------------------------------------------------- + DBG_NAME( FmMouseListenerAdapter ) + //-------------------------------------------------------------------- + FmMouseListenerAdapter::FmMouseListenerAdapter( const Reference< XControl >& _rxControl, IContextRequestObserver* _pObserver ) + :m_pObserver( _pObserver ) + ,m_xWindow( _rxControl, UNO_QUERY ) + { + DBG_CTOR( FmMouseListenerAdapter, NULL ); + + DBG_ASSERT( m_xWindow.is(), "FmMouseListenerAdapter::FmMouseListenerAdapter: invalid control!" ); + osl_incrementInterlockedCount( &m_refCount ); + { + try + { + if ( m_xWindow.is() ) + m_xWindow->addMouseListener( this ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + osl_decrementInterlockedCount( &m_refCount ); + } + + //-------------------------------------------------------------------- + FmMouseListenerAdapter::~FmMouseListenerAdapter() + { + acquire(); + dispose(); + + DBG_DTOR( FmMouseListenerAdapter, NULL ); + } + + //-------------------------------------------------------------------- + void FmMouseListenerAdapter::dispose() + { + if ( m_xWindow.is() ) + { + m_xWindow->removeMouseListener( this ); + m_xWindow.clear(); + } + } + + //-------------------------------------------------------------------- + void SAL_CALL FmMouseListenerAdapter::mousePressed( const awt::MouseEvent& _rEvent ) throw (::com::sun::star::uno::RuntimeException) + { + SolarMutexGuard aGuard; + // is this a request for a context menu? + if ( _rEvent.PopupTrigger ) + { + if ( m_pObserver ) + m_pObserver->contextMenuRequested( _rEvent ); + } + } + + //-------------------------------------------------------------------- + void SAL_CALL FmMouseListenerAdapter::mouseReleased( const awt::MouseEvent& /*e*/ ) throw (::com::sun::star::uno::RuntimeException) + { + // not interested in + } + + //-------------------------------------------------------------------- + void SAL_CALL FmMouseListenerAdapter::mouseEntered( const awt::MouseEvent& /*e*/ ) throw (::com::sun::star::uno::RuntimeException) + { + // not interested in + } + + //-------------------------------------------------------------------- + void SAL_CALL FmMouseListenerAdapter::mouseExited( const awt::MouseEvent& /*e*/ ) throw (::com::sun::star::uno::RuntimeException) + { + // not interested in + } + + //-------------------------------------------------------------------- + void SAL_CALL FmMouseListenerAdapter::disposing( const EventObject& Source ) throw (RuntimeException) + { + (void)Source; + DBG_ASSERT( Source.Source == m_xWindow, "FmMouseListenerAdapter::disposing: where did this come from?" ); + m_xWindow.clear(); + } + + //==================================================================== + //= FmTextControlShell + //==================================================================== + //------------------------------------------------------------------------ + namespace + { + //.................................................................... + void lcl_translateUnoStateToItem( SfxSlotId _nSlot, const Any& _rUnoState, SfxItemSet& _rSet ) + { + WhichId nWhich = _rSet.GetPool()->GetWhich( _nSlot ); + if ( !_rUnoState.hasValue() ) + { + if ( ( _nSlot != SID_CUT ) + && ( _nSlot != SID_COPY ) + && ( _nSlot != SID_PASTE ) + ) + { + _rSet.InvalidateItem( nWhich ); + } + } + else + { + switch ( _rUnoState.getValueType().getTypeClass() ) + { + case TypeClass_BOOLEAN: + { + sal_Bool bState = sal_False; + _rUnoState >>= bState; + if ( _nSlot == SID_ATTR_PARA_SCRIPTSPACE ) + _rSet.Put( SvxScriptSpaceItem( bState, nWhich ) ); + else + _rSet.Put( SfxBoolItem( nWhich, bState ) ); + } + break; + + default: + { + Sequence< PropertyValue > aComplexState; + if ( _rUnoState >>= aComplexState ) + { + if ( !aComplexState.getLength() ) + _rSet.InvalidateItem( nWhich ); + else + { + SfxAllItemSet aAllItems( _rSet ); + TransformParameters( _nSlot, aComplexState, aAllItems ); + const SfxPoolItem* pTransformed = aAllItems.GetItem( nWhich ); + OSL_ENSURE( pTransformed, "lcl_translateUnoStateToItem: non-empty parameter sequence leading to empty item?" ); + if ( pTransformed ) + _rSet.Put( *pTransformed ); + else + _rSet.InvalidateItem( nWhich ); + } + } + else + { + DBG_ERROR( "lcl_translateUnoStateToItem: invalid state!" ); + } + } + } + } + } + + //.................................................................... + ::rtl::OUString lcl_getUnoSlotName( SfxApplication&, SfxSlotId _nSlotId ) + { + ::rtl::OUString sSlotUnoName; + + SfxSlotPool& rSlotPool = SfxSlotPool::GetSlotPool( NULL ); + const SfxSlot* pSlot = rSlotPool.GetSlot( _nSlotId ); + + const sal_Char* pAsciiUnoName = NULL; + if ( pSlot ) + { + pAsciiUnoName = pSlot->GetUnoName(); + } + else + { + // some hard-coded slots, which do not have a UNO name at SFX level, but which + // we nevertheless need to transport via UNO mechanisms, so we need a name + switch ( _nSlotId ) + { + case SID_ATTR_PARA_HANGPUNCTUATION: pAsciiUnoName = "AllowHangingPunctuation"; break; + case SID_ATTR_PARA_FORBIDDEN_RULES: pAsciiUnoName = "ApplyForbiddenCharacterRules"; break; + case SID_ATTR_PARA_SCRIPTSPACE: pAsciiUnoName = "UseScriptSpacing"; break; + } + } + + if ( pAsciiUnoName ) + { + sSlotUnoName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".uno:" ) ); + sSlotUnoName += ::rtl::OUString::createFromAscii( pAsciiUnoName ); + } +#if OSL_DEBUG_LEVEL > 0 + else + { + ::rtl::OString sMessage( "lcl_getUnoSlotName: invalid slot id, or invalid slot, or no UNO name!\n" ); + sMessage += "(slot id: "; + sMessage += ::rtl::OString::valueOf( (sal_Int32)_nSlotId ); + sMessage += ")"; + DBG_ERROR( sMessage ); + } +#endif + return sSlotUnoName; + } + + //.................................................................... + bool lcl_determineReadOnly( const Reference< XControl >& _rxControl ) + { + bool bIsReadOnlyModel = true; + try + { + Reference< XPropertySet > xModelProps; + if ( _rxControl.is() ) + xModelProps = xModelProps.query( _rxControl->getModel() ); + Reference< XPropertySetInfo > xModelPropInfo; + if ( xModelProps.is() ) + xModelPropInfo = xModelProps->getPropertySetInfo(); + + if ( !xModelPropInfo.is() || !xModelPropInfo->hasPropertyByName( FM_PROP_READONLY ) ) + bIsReadOnlyModel = true; + else + { + sal_Bool bReadOnly = sal_True; + xModelProps->getPropertyValue( FM_PROP_READONLY ) >>= bReadOnly; + bIsReadOnlyModel = bReadOnly; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return bIsReadOnlyModel; + } + + //.................................................................... + static Window* lcl_getWindow( const Reference< XControl >& _rxControl ) + { + Window* pWindow = NULL; + try + { + Reference< XWindowPeer > xControlPeer; + if ( _rxControl.is() ) + xControlPeer = _rxControl->getPeer(); + if ( xControlPeer.is() ) + pWindow = VCLUnoHelper::GetWindow( xControlPeer ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + return pWindow; + } + + //.................................................................... + bool lcl_isRichText( const Reference< XControl >& _rxControl ) + { + if ( !_rxControl.is() ) + return false; + + bool bIsRichText = false; + try + { + Reference< XPropertySet > xModelProps( _rxControl->getModel(), UNO_QUERY ); + Reference< XPropertySetInfo > xPSI; + if ( xModelProps.is() ) + xPSI = xModelProps->getPropertySetInfo(); + ::rtl::OUString sRichTextPropertyName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "RichText" ) ); + if ( xPSI.is() && xPSI->hasPropertyByName( sRichTextPropertyName ) ) + { + OSL_VERIFY( xModelProps->getPropertyValue( sRichTextPropertyName ) >>= bIsRichText ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return bIsRichText; + } + } + + //------------------------------------------------------------------------ + FmTextControlShell::FmTextControlShell( SfxViewFrame* _pFrame ) + :m_bActiveControl( false ) + ,m_bActiveControlIsReadOnly( true ) + ,m_bActiveControlIsRichText( false ) + ,m_pViewFrame( _pFrame ) + ,m_rBindings( _pFrame->GetBindings() ) + ,m_bNeedClipboardInvalidation( true ) + { + m_aClipboardInvalidation.SetTimeoutHdl( LINK( this, FmTextControlShell, OnInvalidateClipboard ) ); + m_aClipboardInvalidation.SetTimeout( 200 ); + } + + //------------------------------------------------------------------------ + FmTextControlShell::~FmTextControlShell() + { + dispose(); + } + + //------------------------------------------------------------------------ + IMPL_LINK( FmTextControlShell, OnInvalidateClipboard, void*, /*_pNotInterestedIn*/ ) + { + if ( m_bNeedClipboardInvalidation ) + { + DBG_TRACE( "FmTextControlShell::ClipBoard: invalidating clipboard slots" ); + m_rBindings.Invalidate( SID_CUT ); + m_rBindings.Invalidate( SID_COPY ); + m_rBindings.Invalidate( SID_PASTE ); + m_bNeedClipboardInvalidation = false; + } + return 0L; + } + + //------------------------------------------------------------------------ + void FmTextControlShell::transferFeatureStatesToItemSet( ControlFeatures& _rDispatchers, SfxAllItemSet& _rSet, bool _bTranslateLatin ) + { + SfxItemPool& rPool = *_rSet.GetPool(); + + for ( ControlFeatures::const_iterator aFeature = _rDispatchers.begin(); + aFeature != _rDispatchers.end(); + ++aFeature + ) + { + SfxSlotId nSlotId( aFeature->first ); + #if OSL_DEBUG_LEVEL > 0 + ::rtl::OUString sUnoSlotName; + if ( SFX_APP() ) + sUnoSlotName = lcl_getUnoSlotName( *SFX_APP(), nSlotId ); + else + sUnoSlotName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "<unknown>" ) ); + ::rtl::OString sUnoSlotNameAscii( "\"" ); + sUnoSlotNameAscii += ::rtl::OString( sUnoSlotName.getStr(), sUnoSlotName.getLength(), RTL_TEXTENCODING_ASCII_US ); + sUnoSlotNameAscii += "\""; + #endif + + if ( _bTranslateLatin ) + { + // A rich text control offers a dispatcher for the "Font" slot/feature. + // Sadly, the semantics of the dispatches is that the feature "Font" depends + // on the current cursor position: If it's on latin text, it's the "latin font" + // which is set up at the control. If it's on CJK text, it's the "CJK font", and + // aequivalent for "CTL font". + // The same holds for some other font related features/slots. + // Thus, we have separate dispatches for "Latin Font", "Latin Font Size", etc, + // which are only "virtual", in a sense that there exist no item with this id. + // So when we encounter such a dispatcher for, say, "Latin Font", we need to + // put an item into the set which has the "Font" id. + + switch ( nSlotId ) + { + case SID_ATTR_CHAR_LATIN_FONT: nSlotId = SID_ATTR_CHAR_FONT; break; + case SID_ATTR_CHAR_LATIN_FONTHEIGHT:nSlotId = SID_ATTR_CHAR_FONTHEIGHT; break; + case SID_ATTR_CHAR_LATIN_LANGUAGE: nSlotId = SID_ATTR_CHAR_LANGUAGE; break; + case SID_ATTR_CHAR_LATIN_POSTURE: nSlotId = SID_ATTR_CHAR_POSTURE; break; + case SID_ATTR_CHAR_LATIN_WEIGHT: nSlotId = SID_ATTR_CHAR_WEIGHT; break; + } + } + + WhichId nWhich = rPool.GetWhich( nSlotId ); + bool bIsInPool = rPool.IsInRange( nWhich ); + if ( bIsInPool ) + { + #if OSL_DEBUG_LEVEL > 0 + bool bFeatureIsEnabled = aFeature->second->isFeatureEnabled(); + ::rtl::OString sMessage( "FmTextControlShell::transferFeatureStatesToItemSet: found a feature state for " ); + sMessage += sUnoSlotNameAscii; + if ( !bFeatureIsEnabled ) + sMessage += " (disabled)"; + DBG_TRACE( sMessage ); + #endif + + lcl_translateUnoStateToItem( nSlotId, aFeature->second->getFeatureState(), _rSet ); + } + #if OSL_DEBUG_LEVEL > 0 + else + { + ::rtl::OString sMessage( "FmTextControlShell::transferFeatureStatesToItemSet: found a feature state for " ); + sMessage += sUnoSlotNameAscii; + sMessage += ", but could not translate it into an item!"; + DBG_TRACE( sMessage ); + } + #endif + } + } + + //------------------------------------------------------------------------ + void FmTextControlShell::executeAttributeDialog( AttributeSet _eSet, SfxRequest& _rReq ) + { + const SvxFontListItem* pFontList = PTR_CAST( SvxFontListItem, m_pViewFrame->GetObjectShell()->GetItem( SID_ATTR_CHAR_FONTLIST ) ); + DBG_ASSERT( pFontList, "FmTextControlShell::executeAttributeDialog: no font list item!" ); + if ( !pFontList ) + return; + + SfxItemPool* pPool = EditEngine::CreatePool(); + pPool->FreezeIdRanges(); + ::std::auto_ptr< SfxItemSet > pPureItems( new SfxItemSet( *pPool ) ); + + // put the current states of the items into the set + ::std::auto_ptr< SfxAllItemSet > pCurrentItems( new SfxAllItemSet( *pPureItems ) ); + transferFeatureStatesToItemSet( m_aControlFeatures, *pCurrentItems ); + + // additional items, which we are not responsible for at the SfxShell level, + // but which need to be forwarded to the dialog, anyway + ControlFeatures aAdditionalFestures; + fillFeatureDispatchers( m_xActiveControl, pDialogSlots, aAdditionalFestures ); + transferFeatureStatesToItemSet( aAdditionalFestures, *pCurrentItems, true ); + + ::std::auto_ptr< SfxTabDialog > pDialog ( _eSet == eCharAttribs + ? static_cast< SfxTabDialog* >( new TextControlCharAttribDialog( NULL, *pCurrentItems, *pFontList ) ) + : static_cast< SfxTabDialog* >( new TextControlParaAttribDialog( NULL, *pCurrentItems ) ) ); + if ( RET_OK == pDialog->Execute() ) + { + const SfxItemSet& rModifiedItems = *pDialog->GetOutputItemSet(); + for ( WhichId nWhich = pPool->GetFirstWhich(); nWhich <= pPool->GetLastWhich(); ++nWhich ) + { + if ( rModifiedItems.GetItemState( nWhich ) == SFX_ITEM_SET ) + { + SfxSlotId nSlotForItemSet = pPool->GetSlotId( nWhich ); + const SfxPoolItem* pModifiedItem = rModifiedItems.GetItem( nWhich ); + + + SfxSlotId nSlotForDispatcher = nSlotForItemSet; + switch ( nSlotForDispatcher ) + { + case SID_ATTR_CHAR_FONT: nSlotForDispatcher = SID_ATTR_CHAR_LATIN_FONT; break; + case SID_ATTR_CHAR_FONTHEIGHT:nSlotForDispatcher = SID_ATTR_CHAR_LATIN_FONTHEIGHT; break; + case SID_ATTR_CHAR_LANGUAGE: nSlotForDispatcher = SID_ATTR_CHAR_LATIN_LANGUAGE; break; + case SID_ATTR_CHAR_POSTURE: nSlotForDispatcher = SID_ATTR_CHAR_LATIN_POSTURE; break; + case SID_ATTR_CHAR_WEIGHT: nSlotForDispatcher = SID_ATTR_CHAR_LATIN_WEIGHT; break; + } + + // do we already have a dispatcher for this slot/feature? + ControlFeatures::const_iterator aFeaturePos = m_aControlFeatures.find( nSlotForDispatcher ); + bool bFound = aFeaturePos != m_aControlFeatures.end( ); + + if ( !bFound ) + { + aFeaturePos = aAdditionalFestures.find( nSlotForDispatcher ); + bFound = aFeaturePos != aAdditionalFestures.end( ); + } + + if ( bFound ) + { + Sequence< PropertyValue > aArgs; + // temporarily put the modified item into a "clean" set, + // and let TransformItems calc the respective UNO parameters + pPureItems->Put( *pModifiedItem ); + TransformItems( nSlotForItemSet, *pPureItems, aArgs ); + pPureItems->ClearItem( nWhich ); + + if ( ( nSlotForItemSet == SID_ATTR_PARA_HANGPUNCTUATION ) + || ( nSlotForItemSet == SID_ATTR_PARA_FORBIDDEN_RULES ) + || ( nSlotForItemSet == SID_ATTR_PARA_SCRIPTSPACE ) + ) + { + // these are no UNO slots, they need special handling since TransformItems cannot + // handle them + DBG_ASSERT( aArgs.getLength() == 0, "FmTextControlShell::executeAttributeDialog: these are no UNO slots - are they?" ); + + const SfxBoolItem* pBoolItem = PTR_CAST( SfxBoolItem, pModifiedItem ); + DBG_ASSERT( pBoolItem, "FmTextControlShell::executeAttributeDialog: no bool item?!" ); + if ( pBoolItem ) + { + aArgs.realloc( 1 ); + aArgs[ 0 ].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Enable" ) ); + aArgs[ 0 ].Value <<= (sal_Bool)pBoolItem->GetValue(); + } + } + + // dispatch this + aFeaturePos->second->dispatch( aArgs ); + } + #if OSL_DEBUG_LEVEL > 0 + else + { + ::rtl::OString sError( "FmTextControShell::executeAttributeDialog: Could not handle the following item:" ); + sError += "\n SlotID: "; sError += ::rtl::OString::valueOf( (sal_Int32)nSlotForItemSet ); + sError += "\n WhichID: "; sError += ::rtl::OString::valueOf( (sal_Int32)nWhich ); + sError += "\n UNO name: "; + + ::rtl::OUString sUnoSlotName = lcl_getUnoSlotName( *SFX_APP(), nSlotForItemSet ); + if ( sUnoSlotName.getLength() ) + sError += ::rtl::OString( sUnoSlotName.getStr(), sUnoSlotName.getLength(), RTL_TEXTENCODING_ASCII_US ); + else + sError += "unknown (no SfxSlot)"; + DBG_ERROR( sError.getStr() ); + } + #endif + } + } + _rReq.Done( rModifiedItems ); + } + + pDialog.reset(); + pCurrentItems.reset(); + pPureItems.reset(); + SfxItemPool::Free(pPool); + } + + //------------------------------------------------------------------------ + bool FmTextControlShell::executeSelectAll( ) + { + try + { + if ( m_xActiveTextComponent.is() ) + { + sal_Int32 nTextLen = m_xActiveTextComponent->getText().getLength(); + m_xActiveTextComponent->setSelection( awt::Selection( 0, nTextLen ) ); + return true; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return false; // not handled + } + + //------------------------------------------------------------------------ + bool FmTextControlShell::executeClipboardSlot( SfxSlotId _nSlot ) + { + try + { + if ( m_xActiveTextComponent.is() ) + { + switch ( _nSlot ) + { + case SID_COPY: + case SID_CUT: + { + ::rtl::OUString sSelectedText( m_xActiveTextComponent->getSelectedText() ); + ::svt::OStringTransfer::CopyString( sSelectedText, lcl_getWindow( m_xActiveControl ) ); + if ( SID_CUT == _nSlot ) + { + awt::Selection aSelection( m_xActiveTextComponent->getSelection() ); + m_xActiveTextComponent->insertText( aSelection, ::rtl::OUString() ); + } + } + break; + case SID_PASTE: + { + ::rtl::OUString sClipboardContent; + OSL_VERIFY( ::svt::OStringTransfer::PasteString( sClipboardContent, lcl_getWindow( m_xActiveControl ) ) ); + awt::Selection aSelection( m_xActiveTextComponent->getSelection() ); + m_xActiveTextComponent->insertText( aSelection, sClipboardContent ); + } + break; + default: + OSL_ENSURE( sal_False, "FmTextControlShell::executeClipboardSlot: invalid slot!" ); + } + return true; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return false; // not handled + } + + //------------------------------------------------------------------------ + void FmTextControlShell::ExecuteTextAttribute( SfxRequest& _rReq ) + { + SfxSlotId nSlot = _rReq.GetSlot(); + + ControlFeatures::const_iterator aFeaturePos = m_aControlFeatures.find( nSlot ); + if ( aFeaturePos == m_aControlFeatures.end() ) + { + // special slots + switch ( nSlot ) + { + case SID_CHAR_DLG: + executeAttributeDialog( eCharAttribs, _rReq ); + break; + + case SID_PARA_DLG: + executeAttributeDialog( eParaAttribs, _rReq ); + break; + + case SID_SELECTALL: + executeSelectAll(); + break; + + case SID_CUT: + case SID_COPY: + case SID_PASTE: + executeClipboardSlot( nSlot ); + break; + + default: + DBG_ASSERT( aFeaturePos != m_aControlFeatures.end(), "FmTextControShell::ExecuteTextAttribute: I have no such dispatcher, and cannot handle it at all!" ); + return; + } + } + else + { + // slots which are dispatched to the control + + switch ( nSlot ) + { + case SID_ATTR_CHAR_STRIKEOUT: + case SID_ATTR_CHAR_UNDERLINE: + case SID_ATTR_CHAR_OVERLINE: + { + SfxItemSet aToggled( *_rReq.GetArgs() ); + + lcl_translateUnoStateToItem( nSlot, aFeaturePos->second->getFeatureState(), aToggled ); + WhichId nWhich = aToggled.GetPool()->GetWhich( nSlot ); + const SfxPoolItem* pItem = aToggled.GetItem( nWhich ); + if ( ( SID_ATTR_CHAR_UNDERLINE == nSlot ) || ( SID_ATTR_CHAR_OVERLINE == nSlot ) ) + { + const SvxOverlineItem* pTextLine = PTR_CAST( SvxOverlineItem, pItem ); + DBG_ASSERT( pTextLine, "FmTextControlShell::ExecuteTextAttribute: ooops - no underline/overline item!" ); + if ( pTextLine ) + { + FontUnderline eTL = pTextLine->GetLineStyle(); + if ( SID_ATTR_CHAR_UNDERLINE == nSlot ) { + aToggled.Put( SvxUnderlineItem( eTL == UNDERLINE_SINGLE ? UNDERLINE_NONE : UNDERLINE_SINGLE, nWhich ) ); + } else { + aToggled.Put( SvxOverlineItem( eTL == UNDERLINE_SINGLE ? UNDERLINE_NONE : UNDERLINE_SINGLE, nWhich ) ); + } + } + } + else + { + const SvxCrossedOutItem* pCrossedOut = PTR_CAST( SvxCrossedOutItem, pItem ); + DBG_ASSERT( pCrossedOut, "FmTextControlShell::ExecuteTextAttribute: ooops - no CrossedOut item!" ); + if ( pCrossedOut ) + { + FontStrikeout eFS = pCrossedOut->GetStrikeout(); + aToggled.Put( SvxCrossedOutItem( eFS == STRIKEOUT_SINGLE ? STRIKEOUT_NONE : STRIKEOUT_SINGLE, nWhich ) ); + } + } + + Sequence< PropertyValue > aArguments; + TransformItems( nSlot, aToggled, aArguments ); + aFeaturePos->second->dispatch( aArguments ); + } + break; + + case SID_ATTR_CHAR_FONTHEIGHT: + case SID_ATTR_CHAR_FONT: + case SID_ATTR_CHAR_POSTURE: + case SID_ATTR_CHAR_WEIGHT: + case SID_ATTR_CHAR_SHADOWED: + case SID_ATTR_CHAR_CONTOUR: + case SID_SET_SUPER_SCRIPT: + case SID_SET_SUB_SCRIPT: + { + const SfxItemSet* pArgs = _rReq.GetArgs(); + Sequence< PropertyValue > aArgs; + if ( pArgs ) + TransformItems( nSlot, *pArgs, aArgs ); + aFeaturePos->second->dispatch( aArgs ); + } + break; + + default: + if ( aFeaturePos->second->isFeatureEnabled() ) + aFeaturePos->second->dispatch(); + break; + } + } + _rReq.Done(); + } + + //------------------------------------------------------------------------ + void FmTextControlShell::GetTextAttributeState( SfxItemSet& _rSet ) + { + SfxWhichIter aIter( _rSet ); + sal_uInt16 nSlot = aIter.FirstWhich(); + while ( nSlot ) + { + if ( ( nSlot == SID_ATTR_PARA_LEFT_TO_RIGHT ) + || ( nSlot == SID_ATTR_PARA_RIGHT_TO_LEFT ) + ) + { + if ( !SvtLanguageOptions().IsCTLFontEnabled() ) + { + _rSet.DisableItem( nSlot ); + nSlot = aIter.NextWhich(); + continue; + } + } + + ControlFeatures::const_iterator aFeaturePos = m_aControlFeatures.find( nSlot ); + if ( aFeaturePos != m_aControlFeatures.end() ) + { + if ( aFeaturePos->second->isFeatureEnabled() ) + lcl_translateUnoStateToItem( nSlot, aFeaturePos->second->getFeatureState(), _rSet ); + else + _rSet.DisableItem( nSlot ); + } + else + { + bool bDisable = false; + + bool bNeedWriteableControl = false; + bool bNeedTextComponent = false; + bool bNeedSelection = false; + + switch ( nSlot ) + { + case SID_CHAR_DLG: + case SID_PARA_DLG: + bDisable |= m_aControlFeatures.empty(); + bNeedWriteableControl = true; + break; + + case SID_CUT: + bNeedSelection = true; + bNeedTextComponent = true; + bNeedWriteableControl = true; + DBG_TRACE( "FmTextControlShell::ClipBoard: need to invalidate again" ); + m_bNeedClipboardInvalidation = true; + break; + + case SID_PASTE: + { + Window* pActiveControlVCLWindow = lcl_getWindow( m_xActiveControl ); + if ( pActiveControlVCLWindow ) + { + TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pActiveControlVCLWindow) ); + bDisable |= !aDataHelper.HasFormat( SOT_FORMAT_STRING ); + } + else + bDisable |= true; + + bNeedTextComponent = true; + bNeedWriteableControl = true; + } + break; + + case SID_COPY: + bNeedTextComponent = true; + bNeedSelection = true; + break; + + case SID_SELECTALL: + bNeedTextComponent = true; + break; + + default: + // slot is unknown at all + bDisable |= true; + break; + } + OSL_POSTCOND( !bNeedSelection || bNeedTextComponent, "FmTextControlShell::GetTextAttributeState: bNeedSelection should imply bNeedTextComponent!" ); + + if ( !bDisable && bNeedWriteableControl ) + bDisable |= !IsActiveControl( ) || m_bActiveControlIsReadOnly; + + if ( !bDisable && bNeedTextComponent ) + bDisable |= !m_xActiveTextComponent.is(); + + if ( !bDisable && bNeedSelection ) + { + awt::Selection aSelection = m_xActiveTextComponent->getSelection(); + bDisable |= aSelection.Min == aSelection.Max; + } + + if ( bDisable ) + _rSet.DisableItem( nSlot ); + } + + nSlot = aIter.NextWhich(); + } + } + + //------------------------------------------------------------------------ + bool FmTextControlShell::IsActiveControl( bool _bCountRichTextOnly ) const + { + if ( _bCountRichTextOnly && !m_bActiveControlIsRichText ) + return false; + + return m_bActiveControl; + } + + //------------------------------------------------------------------------ + void FmTextControlShell::dispose() + { + if ( IsActiveControl() ) + controlDeactivated(); + if ( isControllerListening() ) + stopControllerListening(); + } + + //------------------------------------------------------------------------ + void FmTextControlShell::designModeChanged( bool /*_bNewDesignMode*/ ) + { + m_rBindings.Invalidate( pTextControlSlots ); + } + + //------------------------------------------------------------------------ + void FmTextControlShell::formActivated( const Reference< XFormController >& _rxController ) + { +#if OSL_DEBUG_LEVEL > 0 + ::rtl::OString sTrace( "FmTextControlShell::formActivated: 0x" ); + sTrace += ::rtl::OString::valueOf( (sal_IntPtr)_rxController.get(), 16 ); + DBG_TRACE( sTrace ); +#endif + + DBG_ASSERT( _rxController.is(), "FmTextControlShell::formActivated: invalid controller!" ); + if ( !_rxController.is() ) + return; + + // sometimes, a form controller notifies activations, even if it's already activated + if ( m_xActiveController == _rxController ) + return; + + try + { + startControllerListening( _rxController ); + controlActivated( _rxController->getCurrentControl() ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + //------------------------------------------------------------------------ + void FmTextControlShell::formDeactivated( const Reference< XFormController >& _rxController ) + { +#if OSL_DEBUG_LEVEL > 0 + ::rtl::OString sTrace( "FmTextControlShell::formDeactivated: 0x" ); + sTrace += ::rtl::OString::valueOf( (sal_IntPtr)_rxController.get(), 16 ); + DBG_TRACE( sTrace ); +#endif + (void)_rxController; + + if ( IsActiveControl() ) + controlDeactivated(); + if ( isControllerListening() ) + stopControllerListening(); + } + + //------------------------------------------------------------------------ + void FmTextControlShell::startControllerListening( const Reference< XFormController >& _rxController ) + { + OSL_PRECOND( _rxController.is(), "FmTextControlShell::startControllerListening: invalid controller!" ); + if ( !_rxController.is() ) + return; + + OSL_PRECOND( !isControllerListening(), "FmTextControlShell::startControllerListening: already listening!" ); + if ( isControllerListening() ) + stopControllerListening( ); + DBG_ASSERT( !isControllerListening(), "FmTextControlShell::startControllerListening: inconsistence!" ); + + try + { + Sequence< Reference< XControl > > aControls( _rxController->getControls() ); + m_aControlObservers.resize( 0 ); + m_aControlObservers.reserve( aControls.getLength() ); + + const Reference< XControl >* pControls = aControls.getConstArray(); + const Reference< XControl >* pControlsEnd = pControls + aControls.getLength(); + for ( ; pControls != pControlsEnd; ++pControls ) + { + m_aControlObservers.push_back( FocusListenerAdapter( new FmFocusListenerAdapter( *pControls, this ) ) ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + m_xActiveController = _rxController; + } + + //------------------------------------------------------------------------ + void FmTextControlShell::stopControllerListening( ) + { + OSL_PRECOND( isControllerListening(), "FmTextControlShell::stopControllerListening: inconsistence!" ); + + // dispose all listeners associated with the controls of the active controller + for ( FocusListenerAdapters::iterator aLoop = m_aControlObservers.begin(); + aLoop != m_aControlObservers.end(); + ++aLoop + ) + { + (*aLoop)->dispose(); + } + + FocusListenerAdapters aEmpty; + m_aControlObservers.swap( aEmpty ); + + m_xActiveController.clear(); + } + + //------------------------------------------------------------------------ + void FmTextControlShell::implClearActiveControlRef() + { + // no more features for this control + for ( ControlFeatures::iterator aLoop = m_aControlFeatures.begin(); + aLoop != m_aControlFeatures.end(); + ++aLoop + ) + { + aLoop->second->dispose(); + } + + ControlFeatures aEmpty; + m_aControlFeatures.swap( aEmpty ); + + if ( m_aContextMenuObserver.get() ) + { + m_aContextMenuObserver->dispose(); + m_aContextMenuObserver = MouseListenerAdapter(); + } + + if ( m_xActiveTextComponent.is() ) + { + DBG_TRACE( "FmTextControlShell::ClipBoard: stopping timer for clipboard invalidation" ); + m_aClipboardInvalidation.Stop(); + } + // no more active control + m_xActiveControl.clear(); + m_xActiveTextComponent.clear(); + m_bActiveControlIsReadOnly = true; + m_bActiveControlIsRichText = false; + m_bActiveControl = false; + } + + //------------------------------------------------------------------------ + void FmTextControlShell::controlDeactivated( ) + { + DBG_ASSERT( IsActiveControl(), "FmTextControlShell::controlDeactivated: no active control!" ); + + m_bActiveControl = false; + + m_rBindings.Invalidate( pTextControlSlots ); + } + + //------------------------------------------------------------------------ + void FmTextControlShell::controlActivated( const Reference< XControl >& _rxControl ) + { + // ensure that all knittings with the previously active control are lost + if ( m_xActiveControl.is() ) + implClearActiveControlRef(); + DBG_ASSERT( m_aControlFeatures.empty(), "FmTextControlShell::controlActivated: should have no dispatchers when I'm here!" ); + +#if OSL_DEBUG_LEVEL > 0 + { + Sequence< Reference< XControl > > aActiveControls; + if ( m_xActiveController.is() ) + aActiveControls = m_xActiveController->getControls(); + + bool bFoundThisControl = false; + + const Reference< XControl >* pControls = aActiveControls.getConstArray(); + const Reference< XControl >* pControlsEnd = pControls + aActiveControls.getLength(); + for ( ; ( pControls != pControlsEnd ) && !bFoundThisControl; ++pControls ) + { + if ( *pControls == _rxControl ) + bFoundThisControl = true; + } + DBG_ASSERT( bFoundThisControl, "FmTextControlShell::controlActivated: only controls which belong to the active controller can be activated!" ); + } +#endif + // ask the control for dispatchers for our text-related slots + fillFeatureDispatchers( _rxControl, pTextControlSlots, m_aControlFeatures ); + + // remember this control + m_xActiveControl = _rxControl; + m_xActiveTextComponent = m_xActiveTextComponent.query( _rxControl ); + m_bActiveControlIsReadOnly = lcl_determineReadOnly( m_xActiveControl ); + m_bActiveControlIsRichText = lcl_isRichText( m_xActiveControl ); + + // if we found a rich text control, we need context menu support + if ( m_bActiveControlIsRichText ) + { + DBG_ASSERT( NULL == m_aContextMenuObserver.get(), "FmTextControlShell::controlActivated: already have an observer!" ); + m_aContextMenuObserver = MouseListenerAdapter( new FmMouseListenerAdapter( _rxControl, this ) ); + } + + if ( m_xActiveTextComponent.is() ) + { + DBG_TRACE( "FmTextControlShell::ClipBoard: starting timer for clipboard invalidation" ); + m_aClipboardInvalidation.Start(); + } + + m_bActiveControl = true; + + m_rBindings.Invalidate( pTextControlSlots ); + + if ( m_pViewFrame ) + m_pViewFrame->UIFeatureChanged(); + + // don't call the activation handler if we don't have any slots we can serve + // The activation handler is used to put the shell on the top of the dispatcher stack, + // so it's preferred when slots are distributed. + // Note that this is a slight hack, to prevent that we grab slots from the SfxDispatcher + // which should be served by other shells (e.g. Cut/Copy/Paste). + // A real solution would be a forwarding-mechanism for slots: We should be on the top + // if we're active, but if we cannot handle the slot, then we need to tell the dispatcher + // to skip our shell, and pass the slot to the next one. However, this mechanism is not + // not in place in SFX. + // Another possibility would be to have dedicated shells for the slots which we might + // or might not be able to serve. However, this could probably increase the number of + // shells too much (In theory, nearly every slot could have an own shell then). + // + // #i51621# / 2005-08-19 / frank.schoenheit@sun.com + bool bHaveAnyServeableSlots = m_xActiveTextComponent.is() || !m_aControlFeatures.empty(); + if ( m_aControlActivationHandler.IsSet() && bHaveAnyServeableSlots ) + m_aControlActivationHandler.Call( NULL ); + + m_bNeedClipboardInvalidation = true; + } + + //------------------------------------------------------------------------ + void FmTextControlShell::fillFeatureDispatchers( const Reference< XControl > _rxControl, SfxSlotId* _pZeroTerminatedSlots, + ControlFeatures& _rDispatchers ) + { + Reference< XDispatchProvider > xProvider( _rxControl, UNO_QUERY ); + SfxApplication* pApplication = SFX_APP(); + DBG_ASSERT( pApplication, "FmTextControlShell::fillFeatureDispatchers: no SfxApplication!" ); + if ( xProvider.is() && pApplication ) + { + SfxSlotId* pSlots = _pZeroTerminatedSlots; + while ( *pSlots ) + { + FmTextControlFeature* pDispatcher = implGetFeatureDispatcher( xProvider, pApplication, *pSlots ); + if ( pDispatcher ) + _rDispatchers.insert( ControlFeatures::value_type( *pSlots, ControlFeature( pDispatcher ) ) ); + + ++pSlots; + } + } + } + + //------------------------------------------------------------------------ + void FmTextControlShell::impl_parseURL_nothrow( URL& _rURL ) + { + try + { + if ( !m_xURLTransformer.is() ) + { + ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() ); + aContext.createComponent( "com.sun.star.util.URLTransformer", m_xURLTransformer ); + } + if ( m_xURLTransformer.is() ) + m_xURLTransformer->parseStrict( _rURL ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + //------------------------------------------------------------------------ + FmTextControlFeature* FmTextControlShell::implGetFeatureDispatcher( const Reference< XDispatchProvider >& _rxProvider, SfxApplication* _pApplication, SfxSlotId _nSlot ) + { + OSL_PRECOND( _rxProvider.is() && _pApplication, "FmTextControlShell::implGetFeatureDispatcher: invalid arg(s)!" ); + URL aFeatureURL; + aFeatureURL.Complete = lcl_getUnoSlotName( *_pApplication, _nSlot ); + impl_parseURL_nothrow( aFeatureURL ); + Reference< XDispatch > xDispatcher = _rxProvider->queryDispatch( aFeatureURL, ::rtl::OUString(), 0xFF ); + if ( xDispatcher.is() ) + return new FmTextControlFeature( xDispatcher, aFeatureURL, _nSlot, this ); + return NULL; + } + + //------------------------------------------------------------------------ + void FmTextControlShell::Invalidate( SfxSlotId _nSlot ) + { + m_rBindings.Invalidate( _nSlot ); + // despite this method being called "Invalidate", we also update here - this gives more immediate + // feedback in the UI + m_rBindings.Update( _nSlot ); + } + + //------------------------------------------------------------------------ + void FmTextControlShell::focusGained( const ::com::sun::star::awt::FocusEvent& _rEvent ) + { + Reference< XControl > xControl( _rEvent.Source, UNO_QUERY ); + +#if OSL_DEBUG_LEVEL > 0 + ::rtl::OString sTrace( "FmTextControlShell::focusGained: 0x" ); + sTrace += ::rtl::OString::valueOf( (sal_IntPtr)xControl.get(), 16 ); + DBG_TRACE( sTrace ); +#endif + + DBG_ASSERT( xControl.is(), "FmTextControlShell::focusGained: suspicious focus event!" ); + if ( xControl.is() ) + controlActivated( xControl ); + } + + //------------------------------------------------------------------------ + void FmTextControlShell::focusLost( const ::com::sun::star::awt::FocusEvent& _rEvent ) + { + Reference< XControl > xControl( _rEvent.Source, UNO_QUERY ); + +#if OSL_DEBUG_LEVEL > 0 + ::rtl::OString sTrace( "FmTextControlShell::focusLost: 0x" ); + sTrace += ::rtl::OString::valueOf( (sal_IntPtr)xControl.get(), 16 ); + DBG_TRACE( sTrace ); +#endif + + m_bActiveControl = false; + } + + //------------------------------------------------------------------------ + void FmTextControlShell::ForgetActiveControl() + { + implClearActiveControlRef(); + } + + //------------------------------------------------------------------------ + void FmTextControlShell::contextMenuRequested( const awt::MouseEvent& /*_rEvent*/ ) + { + m_rBindings.GetDispatcher()->ExecutePopup( SVX_RES( RID_FM_TEXTATTRIBUTE_MENU ) ); + } + +//........................................................................ +} // namespace svx +//........................................................................ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmtools.cxx b/svx/source/form/fmtools.cxx new file mode 100644 index 000000000000..432213384298 --- /dev/null +++ b/svx/source/form/fmtools.cxx @@ -0,0 +1,498 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include "fmprop.hrc" +#include "fmservs.hxx" +#include "svx/fmtools.hxx" +#include "svx/dbtoolsclient.hxx" +#include "svx/fmglob.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/awt/LineEndFormat.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/XIntrospection.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/form/XForm.hpp> +#include <com/sun/star/form/XFormComponent.hpp> +#include <com/sun/star/form/XGridColumnFactory.hpp> +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/io/XActiveDataSource.hpp> +#include <com/sun/star/io/XObjectInputStream.hpp> +#include <com/sun/star/io/XObjectOutputStream.hpp> +#include <com/sun/star/io/XPersistObject.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdb/ErrorCondition.hpp> +#include <com/sun/star/sdb/SQLContext.hpp> +#include <com/sun/star/sdb/XCompletedConnection.hpp> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include <com/sun/star/sdb/XResultSetAccess.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/XDataSource.hpp> +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#include <com/sun/star/uno/XNamingService.hpp> +#include <com/sun/star/util/Language.hpp> +#include <com/sun/star/util/NumberFormat.hpp> +#include <com/sun/star/util/XCloneable.hpp> +#include <com/sun/star/util/XNumberFormatTypes.hpp> +#include <com/sun/star/util/XNumberFormats.hpp> +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> +#include <com/sun/star/util/XNumberFormatter.hpp> +/** === end UNO includes === **/ + +#include <basic/sbxvar.hxx> +#include <svl/eitem.hxx> +#include <svl/stritem.hxx> +#include <comphelper/container.hxx> +#include <comphelper/extract.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/property.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/types.hxx> +#include <comphelper/uno3.hxx> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbtools.hxx> +#include <cppuhelper/servicefactory.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <rtl/logfile.hxx> +#include <rtl/math.hxx> +#include <sfx2/bindings.hxx> +#include <svl/eitem.hxx> +#include <svl/stritem.hxx> +#include <toolkit/unohlp.hxx> +#include <tools/debug.hxx> +#include <tools/string.hxx> +#include <vcl/stdtext.hxx> +#include <vcl/svapp.hxx> + +#include <algorithm> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::ui::dialogs; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::form; +using namespace ::svxform; +using namespace ::connectivity::simple; + +// ------------------------------------------------------------------------------ +namespace +{ + static bool lcl_shouldDisplayError( const Any& _rError ) + { + SQLException aError; + if ( !( _rError >>= aError ) ) + return true; + + if ( aError.Message.indexOfAsciiL( RTL_CONSTASCII_STRINGPARAM( "[OOoBase]" ) ) != 0 ) + // it is an exception *not* thrown by an OOo Base core component + return true; + + // the only exception we do not display ATM is a RowSetVetoException, which + // has been raised because an XRowSetApprovalListener vetoed a change + if ( aError.ErrorCode + ErrorCondition::ROW_SET_OPERATION_VETOED == 0 ) + return false; + + // everything else is to be displayed + return true; + } +} + +// ------------------------------------------------------------------------------ +void displayException(const Any& _rExcept, Window* _pParent) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "fmtools::displayException" ); + // check whether we need to display it + if ( !lcl_shouldDisplayError( _rExcept ) ) + return; + + try + { + // the parent window + Window* pParentWindow = _pParent ? _pParent : GetpApp()->GetDefDialogParent(); + Reference< XWindow > xParentWindow = VCLUnoHelper::GetInterface(pParentWindow); + + Sequence< Any > aArgs(2); + aArgs[0] <<= PropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("SQLException")), 0, _rExcept, PropertyState_DIRECT_VALUE); + aArgs[1] <<= PropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ParentWindow")), 0, makeAny(xParentWindow), PropertyState_DIRECT_VALUE); + + static ::rtl::OUString s_sDialogServiceName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sdb.ErrorMessageDialog") ); + Reference< XExecutableDialog > xErrorDialog( + ::comphelper::getProcessServiceFactory()->createInstanceWithArguments(s_sDialogServiceName, aArgs), UNO_QUERY); + if (xErrorDialog.is()) + xErrorDialog->execute(); + else + ShowServiceNotAvailableError(pParentWindow, s_sDialogServiceName, sal_True); + } + catch(Exception&) + { + OSL_ENSURE(sal_False, "displayException: could not display the error message!"); + } +} + +// ------------------------------------------------------------------------------ +void displayException(const ::com::sun::star::sdbc::SQLException& _rExcept, Window* _pParent) +{ + displayException(makeAny(_rExcept), _pParent); +} + +// ------------------------------------------------------------------------------ +void displayException(const ::com::sun::star::sdbc::SQLWarning& _rExcept, Window* _pParent) +{ + displayException(makeAny(_rExcept), _pParent); +} + +// ------------------------------------------------------------------------------ +void displayException(const ::com::sun::star::sdb::SQLContext& _rExcept, Window* _pParent) +{ + displayException(makeAny(_rExcept), _pParent); +} + +// ------------------------------------------------------------------------------ +void displayException(const ::com::sun::star::sdb::SQLErrorEvent& _rEvent, Window* _pParent) +{ + displayException(_rEvent.Reason, _pParent); +} + +//------------------------------------------------------------------------------ +sal_Int32 getElementPos(const Reference< ::com::sun::star::container::XIndexAccess>& xCont, const Reference< XInterface >& xElement) +{ + sal_Int32 nIndex = -1; + if (!xCont.is()) + return nIndex; + + + Reference< XInterface > xNormalized( xElement, UNO_QUERY ); + DBG_ASSERT( xNormalized.is(), "getElementPos: invalid element!" ); + if ( xNormalized.is() ) + { + // Feststellen an welcher Position sich das Kind befindet + nIndex = xCont->getCount(); + while (nIndex--) + { + try + { + Reference< XInterface > xCurrent(xCont->getByIndex( nIndex ),UNO_QUERY); + DBG_ASSERT( xCurrent.get() == Reference< XInterface >( xCurrent, UNO_QUERY ).get(), + "getElementPos: container element not normalized!" ); + if ( xNormalized.get() == xCurrent.get() ) + break; + } + catch(Exception&) + { + DBG_ERROR( "getElementPos: caught an exception!" ); + } + + } + } + return nIndex; +} + +//------------------------------------------------------------------ +::rtl::OUString getLabelName(const Reference< ::com::sun::star::beans::XPropertySet>& xControlModel) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "fmtools::getLabelName" ); + if (!xControlModel.is()) + return ::rtl::OUString(); + + if (::comphelper::hasProperty(FM_PROP_CONTROLLABEL, xControlModel)) + { + Reference< ::com::sun::star::beans::XPropertySet> xLabelSet; + xControlModel->getPropertyValue(FM_PROP_CONTROLLABEL) >>= xLabelSet; + if (xLabelSet.is() && ::comphelper::hasProperty(FM_PROP_LABEL, xLabelSet)) + { + Any aLabel( xLabelSet->getPropertyValue(FM_PROP_LABEL) ); + if ((aLabel.getValueTypeClass() == TypeClass_STRING) && ::comphelper::getString(aLabel).getLength()) + return ::comphelper::getString(aLabel); + } + } + + return ::comphelper::getString(xControlModel->getPropertyValue(FM_PROP_CONTROLSOURCE)); +} + +//======================================================================== +// = CursorWrapper +//------------------------------------------------------------------------ +CursorWrapper::CursorWrapper(const Reference< ::com::sun::star::sdbc::XRowSet>& _rxCursor, sal_Bool bUseCloned) +{ + ImplConstruct(Reference< ::com::sun::star::sdbc::XResultSet>(_rxCursor, UNO_QUERY), bUseCloned); +} + +//------------------------------------------------------------------------ +CursorWrapper::CursorWrapper(const Reference< ::com::sun::star::sdbc::XResultSet>& _rxCursor, sal_Bool bUseCloned) +{ + ImplConstruct(_rxCursor, bUseCloned); +} + +//------------------------------------------------------------------------ +void CursorWrapper::ImplConstruct(const Reference< ::com::sun::star::sdbc::XResultSet>& _rxCursor, sal_Bool bUseCloned) +{ + if (bUseCloned) + { + Reference< ::com::sun::star::sdb::XResultSetAccess> xAccess(_rxCursor, UNO_QUERY); + try + { + m_xMoveOperations = xAccess.is() ? xAccess->createResultSet() : Reference< ::com::sun::star::sdbc::XResultSet>(); + } + catch(Exception&) + { + } + } + else + m_xMoveOperations = _rxCursor; + + m_xBookmarkOperations = m_xBookmarkOperations.query( m_xMoveOperations ); + m_xColumnsSupplier = m_xColumnsSupplier.query( m_xMoveOperations ); + m_xPropertyAccess = m_xPropertyAccess.query( m_xMoveOperations ); + + if ( !m_xMoveOperations.is() || !m_xBookmarkOperations.is() || !m_xColumnsSupplier.is() || !m_xPropertyAccess.is() ) + { // all or nothing !! + m_xMoveOperations = NULL; + m_xBookmarkOperations = NULL; + m_xColumnsSupplier = NULL; + } + else + m_xGeneric = m_xMoveOperations.get(); +} + +//------------------------------------------------------------------------ +const CursorWrapper& CursorWrapper::operator=(const Reference< ::com::sun::star::sdbc::XRowSet>& _rxCursor) +{ + m_xMoveOperations = Reference< ::com::sun::star::sdbc::XResultSet>(_rxCursor, UNO_QUERY); + m_xBookmarkOperations = Reference< ::com::sun::star::sdbcx::XRowLocate>(_rxCursor, UNO_QUERY); + m_xColumnsSupplier = Reference< ::com::sun::star::sdbcx::XColumnsSupplier>(_rxCursor, UNO_QUERY); + if (!m_xMoveOperations.is() || !m_xBookmarkOperations.is() || !m_xColumnsSupplier.is()) + { // all or nothing !! + m_xMoveOperations = NULL; + m_xBookmarkOperations = NULL; + m_xColumnsSupplier = NULL; + } + return *this; +} + +//------------------------------------------------------------------------------ +FmXDisposeListener::~FmXDisposeListener() +{ + setAdapter(NULL); +} + +//------------------------------------------------------------------------------ +void FmXDisposeListener::setAdapter(FmXDisposeMultiplexer* pAdapter) +{ + if (m_pAdapter) + { + ::osl::MutexGuard aGuard(m_rMutex); + m_pAdapter->release(); + m_pAdapter = NULL; + } + + if (pAdapter) + { + ::osl::MutexGuard aGuard(m_rMutex); + m_pAdapter = pAdapter; + m_pAdapter->acquire(); + } +} + +//============================================================================== +DBG_NAME(FmXDisposeMultiplexer); +//------------------------------------------------------------------------------ +FmXDisposeMultiplexer::FmXDisposeMultiplexer(FmXDisposeListener* _pListener, const Reference< ::com::sun::star::lang::XComponent>& _rxObject, sal_Int16 _nId) + :m_xObject(_rxObject) + ,m_pListener(_pListener) + ,m_nId(_nId) +{ + DBG_CTOR(FmXDisposeMultiplexer, NULL); + m_pListener->setAdapter(this); + + if (m_xObject.is()) + m_xObject->addEventListener(this); +} + +//------------------------------------------------------------------------------ +FmXDisposeMultiplexer::~FmXDisposeMultiplexer() +{ + DBG_DTOR(FmXDisposeMultiplexer, NULL); +} + +// ::com::sun::star::lang::XEventListener +//------------------------------------------------------------------ +void FmXDisposeMultiplexer::disposing(const ::com::sun::star::lang::EventObject& _Source) throw( RuntimeException ) +{ + Reference< ::com::sun::star::lang::XEventListener> xPreventDelete(this); + + if (m_pListener) + { + m_pListener->disposing(_Source, m_nId); + m_pListener->setAdapter(NULL); + m_pListener = NULL; + } + m_xObject = NULL; +} + +//------------------------------------------------------------------ +void FmXDisposeMultiplexer::dispose() +{ + if (m_xObject.is()) + { + Reference< ::com::sun::star::lang::XEventListener> xPreventDelete(this); + + m_xObject->removeEventListener(this); + m_xObject = NULL; + + m_pListener->setAdapter(NULL); + m_pListener = NULL; + } +} + +//============================================================================== +//------------------------------------------------------------------------------ +sal_Int16 getControlTypeByObject(const Reference< ::com::sun::star::lang::XServiceInfo>& _rxObject) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "fmtools::getControlTypeByObject" ); + // ask for the persistent service name + Reference< ::com::sun::star::io::XPersistObject> xPersistence(_rxObject, UNO_QUERY); + DBG_ASSERT(xPersistence.is(), "::getControlTypeByObject : argument shold be an ::com::sun::star::io::XPersistObject !"); + if (!xPersistence.is()) + return OBJ_FM_CONTROL; + + ::rtl::OUString sPersistentServiceName = xPersistence->getServiceName(); + if (sPersistentServiceName.equals(FM_COMPONENT_EDIT)) // 5.0-Name + { + // may be a simple edit field or a formatted field, dependent of the supported services + if (_rxObject->supportsService(FM_SUN_COMPONENT_FORMATTEDFIELD)) + return OBJ_FM_FORMATTEDFIELD; + return OBJ_FM_EDIT; + } + if (sPersistentServiceName.equals(FM_COMPONENT_TEXTFIELD)) + return OBJ_FM_EDIT; + if (sPersistentServiceName.equals(FM_COMPONENT_COMMANDBUTTON)) + return OBJ_FM_BUTTON; + if (sPersistentServiceName.equals(FM_COMPONENT_FIXEDTEXT)) + return OBJ_FM_FIXEDTEXT; + if (sPersistentServiceName.equals(FM_COMPONENT_LISTBOX)) + return OBJ_FM_LISTBOX; + if (sPersistentServiceName.equals(FM_COMPONENT_CHECKBOX)) + return OBJ_FM_CHECKBOX; + if (sPersistentServiceName.equals(FM_COMPONENT_RADIOBUTTON)) + return OBJ_FM_RADIOBUTTON; + if (sPersistentServiceName.equals(FM_COMPONENT_GROUPBOX)) + return OBJ_FM_GROUPBOX; + if (sPersistentServiceName.equals(FM_COMPONENT_COMBOBOX)) + return OBJ_FM_COMBOBOX; + if (sPersistentServiceName.equals(FM_COMPONENT_GRID)) // 5.0-Name + return OBJ_FM_GRID; + if (sPersistentServiceName.equals(FM_COMPONENT_GRIDCONTROL)) + return OBJ_FM_GRID; + if (sPersistentServiceName.equals(FM_COMPONENT_IMAGEBUTTON)) + return OBJ_FM_IMAGEBUTTON; + if (sPersistentServiceName.equals(FM_COMPONENT_FILECONTROL)) + return OBJ_FM_FILECONTROL; + if (sPersistentServiceName.equals(FM_COMPONENT_DATEFIELD)) + return OBJ_FM_DATEFIELD; + if (sPersistentServiceName.equals(FM_COMPONENT_TIMEFIELD)) + return OBJ_FM_TIMEFIELD; + if (sPersistentServiceName.equals(FM_COMPONENT_NUMERICFIELD)) + return OBJ_FM_NUMERICFIELD; + if (sPersistentServiceName.equals(FM_COMPONENT_CURRENCYFIELD)) + return OBJ_FM_CURRENCYFIELD; + if (sPersistentServiceName.equals(FM_COMPONENT_PATTERNFIELD)) + return OBJ_FM_PATTERNFIELD; + if (sPersistentServiceName.equals(FM_COMPONENT_HIDDEN)) // 5.0-Name + return OBJ_FM_HIDDEN; + if (sPersistentServiceName.equals(FM_COMPONENT_HIDDENCONTROL)) + return OBJ_FM_HIDDEN; + if (sPersistentServiceName.equals(FM_COMPONENT_IMAGECONTROL)) + return OBJ_FM_IMAGECONTROL; + if (sPersistentServiceName.equals(FM_COMPONENT_FORMATTEDFIELD)) + { + DBG_ERROR("::getControlTypeByObject : suspicious persistent service name (formatted field) !"); + // objects with that service name should exist as they aren't compatible with older versions + return OBJ_FM_FORMATTEDFIELD; + } + if ( sPersistentServiceName.equals( FM_SUN_COMPONENT_SCROLLBAR ) ) + return OBJ_FM_SCROLLBAR; + if ( sPersistentServiceName.equals( FM_SUN_COMPONENT_SPINBUTTON) ) + return OBJ_FM_SPINBUTTON; + if (sPersistentServiceName.equals(FM_SUN_COMPONENT_NAVIGATIONBAR)) + return OBJ_FM_NAVIGATIONBAR; + + DBG_ERROR("::getControlTypeByObject : unknown object type !"); + return OBJ_FM_CONTROL; +} + +//------------------------------------------------------------------------------ +void setConnection(const Reference< ::com::sun::star::sdbc::XRowSet>& _rxRowSet, const Reference< ::com::sun::star::sdbc::XConnection>& _rxConn) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "fmtools::setConnection" ); + Reference< ::com::sun::star::beans::XPropertySet> xRowSetProps(_rxRowSet, UNO_QUERY); + if (xRowSetProps.is()) + { + try + { + Any aConn(makeAny(_rxConn)); + xRowSetProps->setPropertyValue(FM_PROP_ACTIVE_CONNECTION, aConn); + } + catch(Exception&) + { + DBG_ERROR("::setConnection : could not set the connection !"); + } + + } +} +//------------------------------------------------------------------------------ +sal_Bool isRowSetAlive(const Reference< XInterface >& _rxRowSet) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "fmtools::isRowSetAlive" ); + sal_Bool bIsAlive = sal_False; + Reference< ::com::sun::star::sdbcx::XColumnsSupplier> xSupplyCols(_rxRowSet, UNO_QUERY); + Reference< ::com::sun::star::container::XIndexAccess> xCols; + if (xSupplyCols.is()) + xCols = Reference< ::com::sun::star::container::XIndexAccess>(xSupplyCols->getColumns(), UNO_QUERY); + if (xCols.is() && (xCols->getCount() > 0)) + bIsAlive = sal_True; + + return bIsAlive; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmundo.cxx b/svx/source/form/fmundo.cxx new file mode 100644 index 000000000000..7dfbea35000b --- /dev/null +++ b/svx/source/form/fmundo.cxx @@ -0,0 +1,1350 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include <sal/macros.h> +#include "fmundo.hxx" +#include "fmpgeimp.hxx" +#include "svx/dbtoolsclient.hxx" +#include "svditer.hxx" +#include "fmobj.hxx" +#include "fmprop.hrc" +#include "fmresids.hrc" +#include "svx/fmglob.hxx" +#include "svx/dialmgr.hxx" +#include "svx/fmmodel.hxx" +#include "svx/fmpage.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/util/XModifyBroadcaster.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/container/XContainer.hpp> +#include <com/sun/star/container/XContainerListener.hpp> +#include <com/sun/star/script/XEventAttacherManager.hpp> +#include <com/sun/star/form/binding/XBindableValue.hpp> +#include <com/sun/star/form/binding/XListEntrySink.hpp> +#include <com/sun/star/reflection/XInterfaceMethodTypeDescription.hpp> +/** === end UNO includes === **/ + +#include "svx/fmtools.hxx" +#include <rtl/logfile.hxx> +#include <svl/macitem.hxx> +#include <tools/shl.hxx> +#include <tools/diagnose_ex.h> +#include <sfx2/objsh.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/app.hxx> +#include <sfx2/sfx.hrc> +#include <sfx2/event.hxx> +#include <osl/mutex.hxx> +#include <osl/mutex.hxx> +#include <comphelper/property.hxx> +#include <comphelper/uno3.hxx> +#include <comphelper/stl_types.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::script; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::reflection; +using namespace ::com::sun::star::form::binding; +using namespace ::svxform; + + +#include <com/sun/star/script/XScriptListener.hdl> +#include <comphelper/processfactory.hxx> +#include <cppuhelper/implbase1.hxx> + +typedef cppu::WeakImplHelper1< XScriptListener > ScriptEventListener_BASE; +class ScriptEventListenerWrapper : public ScriptEventListener_BASE +{ +public: + ScriptEventListenerWrapper( FmFormModel& _rModel) throw ( RuntimeException ) : pModel(&_rModel) + { + + } + // XEventListener + virtual void SAL_CALL disposing(const EventObject& ) throw( RuntimeException ){} + + // XScriptListener + virtual void SAL_CALL firing(const ScriptEvent& evt) throw(RuntimeException) + { + setModel(); + if ( m_vbaListener.is() ) + { + m_vbaListener->firing( evt ); + } + } + + virtual Any SAL_CALL approveFiring(const ScriptEvent& evt) throw( com::sun::star::reflection::InvocationTargetException, RuntimeException) + { + setModel(); + if ( m_vbaListener.is() ) + { + return m_vbaListener->approveFiring( evt ); + } + return Any(); + } + +private: + void setModel() + { + if ( !m_vbaListener.is() ) + { + Reference < XPropertySet > xProps( + ::comphelper::getProcessServiceFactory(), UNO_QUERY ); + if ( xProps.is() ) + { + Reference< XComponentContext > xCtx( xProps->getPropertyValue( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))), UNO_QUERY ); + if ( xCtx.is() ) + { + Reference< XMultiComponentFactory > xMFac( + xCtx->getServiceManager(), UNO_QUERY ); + SfxObjectShellRef xObjSh = pModel->GetObjectShell(); + Reference< XMultiServiceFactory > xDocFac; + if ( xObjSh.Is() ) + xDocFac.set( xObjSh->GetModel(), UNO_QUERY ); + + if ( xMFac.is() ) + { + m_vbaListener.set( xMFac->createInstanceWithContext( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "ooo.vba.EventListener" ) ), xCtx ), + UNO_QUERY_THROW ); + } + } + } + } + Reference< XPropertySet > xProps( m_vbaListener, UNO_QUERY ); + if ( xProps.is() ) + { + try + { + SfxObjectShellRef xObjSh = pModel->GetObjectShell(); + if ( xObjSh.Is() && m_vbaListener.is() ) + { + Any aVal; + aVal <<= xObjSh->GetModel(); + xProps->setPropertyValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Model" ) ), + aVal ); + } + } + catch( Exception& ) + { + //swallow any errors + } + } + } + FmFormModel* pModel; + Reference< XScriptListener > m_vbaListener; + + +}; + +//------------------------------------------------------------------------------ +// some helper structs for caching property infos +//------------------------------------------------------------------------------ +struct PropertyInfo +{ + BOOL bIsTransientOrReadOnly : 1; // the property is transient or read-only, thus we need no undo action for it + BOOL bIsValueProperty : 1; // the property is the special value property, thus it may be handled + // as if it's transient or persistent +}; + +struct PropertySetInfo +{ + DECLARE_STL_USTRINGACCESS_MAP(PropertyInfo, AllProperties); + + AllProperties aProps; // all properties of this set which we know so far + BOOL bHasEmptyControlSource; // sal_True -> the set has a DataField property, and the current value is an empty string + // sal_False -> the set has _no_ such property or it's value isn't empty +}; + +BOOL operator < (const Reference< XPropertySet >& lhs, + const Reference< XPropertySet >& rhs) +{ + return lhs.get() < rhs.get(); +} + +DECLARE_STL_STDKEY_MAP(Reference< XPropertySet >, PropertySetInfo, PropertySetInfoCache); + +//------------------------------------------------------------------------------ + +String static_STR_UNDO_PROPERTY; +//------------------------------------------------------------------------------ +DBG_NAME(FmXUndoEnvironment) +//------------------------------------------------------------------------------ +FmXUndoEnvironment::FmXUndoEnvironment(FmFormModel& _rModel) + :rModel( _rModel ) + ,m_pPropertySetCache( NULL ) + ,m_pScriptingEnv( ::svxform::createDefaultFormScriptingEnvironment( _rModel ) ) + ,m_Locks( 0 ) + ,bReadOnly( sal_False ) + ,m_bDisposed( false ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::FmXUndoEnvironment" ); + DBG_CTOR(FmXUndoEnvironment,NULL); + try + { + m_vbaListener = new ScriptEventListenerWrapper( _rModel ); + } + catch( Exception& ) + { + } +} + +//------------------------------------------------------------------------------ +FmXUndoEnvironment::~FmXUndoEnvironment() +{ + DBG_DTOR(FmXUndoEnvironment,NULL); + if (m_pPropertySetCache) + delete static_cast<PropertySetInfoCache*>(m_pPropertySetCache); +} + +//------------------------------------------------------------------------------ +void FmXUndoEnvironment::dispose() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::dispose" ); + OSL_ENSURE( !m_bDisposed, "FmXUndoEnvironment::dispose: disposed twice?" ); + if ( !m_bDisposed ) + return; + + Lock(); + + sal_uInt16 nCount = rModel.GetPageCount(); + sal_uInt16 i; + for (i = 0; i < nCount; i++) + { + FmFormPage* pPage = PTR_CAST( FmFormPage, rModel.GetPage(i) ); + if ( pPage ) + { + Reference< XInterface > xForms = pPage->GetForms( false ).get(); + if ( xForms.is() ) + RemoveElement( xForms ); + } + } + + nCount = rModel.GetMasterPageCount(); + for (i = 0; i < nCount; i++) + { + FmFormPage* pPage = PTR_CAST( FmFormPage, rModel.GetMasterPage(i) ); + if ( pPage ) + { + Reference< XInterface > xForms = pPage->GetForms( false ).get(); + if ( xForms.is() ) + RemoveElement( xForms ); + } + } + + UnLock(); + + OSL_PRECOND( rModel.GetObjectShell(), "FmXUndoEnvironment::dispose: no object shell anymore!" ); + if ( rModel.GetObjectShell() ) + EndListening( *rModel.GetObjectShell() ); + + if ( IsListening( rModel ) ) + EndListening( rModel ); + + m_pScriptingEnv->dispose(); + + m_bDisposed = true; +} + +//------------------------------------------------------------------------------ +void FmXUndoEnvironment::ModeChanged() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::ModeChanged" ); + OSL_PRECOND( rModel.GetObjectShell(), "FmXUndoEnvironment::ModeChanged: no object shell anymore!" ); + if ( !rModel.GetObjectShell() ) + return; + + if (bReadOnly != (rModel.GetObjectShell()->IsReadOnly() || rModel.GetObjectShell()->IsReadOnlyUI())) + { + bReadOnly = !bReadOnly; + + sal_uInt16 nCount = rModel.GetPageCount(); + sal_uInt16 i; + for (i = 0; i < nCount; i++) + { + FmFormPage* pPage = PTR_CAST( FmFormPage, rModel.GetPage(i) ); + if ( pPage ) + { + Reference< XInterface > xForms = pPage->GetForms( false ).get(); + if ( xForms.is() ) + TogglePropertyListening( xForms ); + } + } + + nCount = rModel.GetMasterPageCount(); + for (i = 0; i < nCount; i++) + { + FmFormPage* pPage = PTR_CAST( FmFormPage, rModel.GetMasterPage(i) ); + if ( pPage ) + { + Reference< XInterface > xForms = pPage->GetForms( false ).get(); + if ( xForms.is() ) + TogglePropertyListening( xForms ); + } + } + + if (!bReadOnly) + StartListening(rModel); + else + EndListening(rModel); + } +} + +//------------------------------------------------------------------------------ +void FmXUndoEnvironment::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::Notify" ); + if (rHint.ISA(SdrHint)) + { + SdrHint* pSdrHint = (SdrHint*)&rHint; + switch( pSdrHint->GetKind() ) + { + case HINT_OBJINSERTED: + { + SdrObject* pSdrObj = (SdrObject*)pSdrHint->GetObject(); + Inserted( pSdrObj ); + } break; + case HINT_OBJREMOVED: + { + SdrObject* pSdrObj = (SdrObject*)pSdrHint->GetObject(); + Removed( pSdrObj ); + } + break; + default: + break; + } + } + else if (rHint.ISA(SfxSimpleHint)) + { + switch ( ((SfxSimpleHint&)rHint).GetId() ) + { + case SFX_HINT_DYING: + dispose(); + rModel.SetObjectShell( NULL ); + break; + case SFX_HINT_MODECHANGED: + ModeChanged(); + break; + } + } + else if (rHint.ISA(SfxEventHint)) + { + switch (((SfxEventHint&)rHint).GetEventId()) + { + case SFX_EVENT_CREATEDOC: + case SFX_EVENT_OPENDOC: + ModeChanged(); + break; + } + } + +} + +//------------------------------------------------------------------ +void FmXUndoEnvironment::Inserted(SdrObject* pObj) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::Inserted" ); + if (pObj->GetObjInventor() == FmFormInventor) + { + FmFormObj* pFormObj = PTR_CAST(FmFormObj, pObj); + Inserted( pFormObj ); + } + else if (pObj->IsGroupObject()) + { + SdrObjListIter aIter(*pObj->GetSubList()); + while ( aIter.IsMore() ) + Inserted( aIter.Next() ); + } +} + +//------------------------------------------------------------------------------ +namespace +{ + sal_Bool lcl_searchElement(const Reference< XIndexAccess>& xCont, const Reference< XInterface >& xElement) + { + if (!xCont.is() || !xElement.is()) + return sal_False; + + sal_Int32 nCount = xCont->getCount(); + Reference< XInterface > xComp; + for (sal_Int32 i = 0; i < nCount; i++) + { + try + { + xCont->getByIndex(i) >>= xComp; + if (xComp.is()) + { + if ( xElement == xComp ) + return sal_True; + else + { + Reference< XIndexAccess> xCont2(xComp, UNO_QUERY); + if (xCont2.is() && lcl_searchElement(xCont2, xElement)) + return sal_True; + } + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + return sal_False; + } +} + +//------------------------------------------------------------------------------ +void FmXUndoEnvironment::Inserted(FmFormObj* pObj) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::Inserted" ); + DBG_ASSERT( pObj, "FmXUndoEnvironment::Inserted: invalid object!" ); + if ( !pObj ) + return; + + // ist das Control noch einer Form zugeordnet + Reference< XInterface > xModel(pObj->GetUnoControlModel(), UNO_QUERY); + Reference< XFormComponent > xContent(xModel, UNO_QUERY); + if (xContent.is() && pObj->GetPage()) + { + // if the component doesn't belong to a form, yet, find one to insert into + if (!xContent->getParent().is()) + { + try + { + Reference< XIndexContainer > xObjectParent = pObj->GetOriginalParent(); + + FmFormPage& rPage = dynamic_cast< FmFormPage& >( *pObj->GetPage() ); + Reference< XIndexAccess > xForms( rPage.GetForms(), UNO_QUERY_THROW ); + + Reference< XIndexContainer > xNewParent; + Reference< XForm > xForm; + sal_Int32 nPos = -1; + if ( lcl_searchElement( xForms, xObjectParent ) ) + { + // the form which was the parent of the object when it was removed is still + // part of the form component hierachy of the current page + xNewParent = xObjectParent; + xForm.set( xNewParent, UNO_QUERY_THROW ); + nPos = ::std::min( pObj->GetOriginalIndex(), xNewParent->getCount() ); + } + else + { + xForm.set( rPage.GetImpl().findPlaceInFormComponentHierarchy( xContent ), UNO_SET_THROW ); + xNewParent.set( xForm, UNO_QUERY_THROW ); + nPos = xNewParent->getCount(); + } + + rPage.GetImpl().setUniqueName( xContent, xForm ); + xNewParent->insertByIndex( nPos, makeAny( xContent ) ); + + Reference< XEventAttacherManager > xManager( xNewParent, UNO_QUERY_THROW ); + xManager->registerScriptEvents( nPos, pObj->GetOriginalEvents() ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + // FormObject zuruecksetzen + pObj->ClearObjEnv(); + } +} + +//------------------------------------------------------------------ +void FmXUndoEnvironment::Removed(SdrObject* pObj) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::Removed" ); + if ( pObj->IsVirtualObj() ) + // for virtual objects, we've already been notified of the removal of the master + // object, which is sufficient here + return; + + if (pObj->GetObjInventor() == FmFormInventor) + { + FmFormObj* pFormObj = PTR_CAST(FmFormObj, pObj); + Removed(pFormObj); + } + else if (pObj->IsGroupObject()) + { + SdrObjListIter aIter(*pObj->GetSubList()); + while ( aIter.IsMore() ) + Removed( aIter.Next() ); + } +} + +//------------------------------------------------------------------------------ +void FmXUndoEnvironment::Removed(FmFormObj* pObj) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::Removed" ); + DBG_ASSERT( pObj, "FmXUndoEnvironment::Removed: invalid object!" ); + if ( !pObj ) + return; + + // ist das Control noch einer Form zugeordnet + Reference< XFormComponent > xContent(pObj->GetUnoControlModel(), UNO_QUERY); + if (xContent.is()) + { + // das Object wird aus einer Liste herausgenommen + // existiert ein Vater wird das Object beim beim Vater entfernt und + // am FormObject gemerkt! + + // wird das Object wieder eingefuegt und ein Parent existiert, so wird dieser + // Parent wiederum gesetzt + Reference< XIndexContainer > xForm(xContent->getParent(), UNO_QUERY); + if (xForm.is()) + { + Reference< XIndexAccess > xIndexAccess((XIndexContainer*)xForm.get()); + // Feststellen an welcher Position sich das Kind befunden hat + const sal_Int32 nPos = getElementPos(xIndexAccess, xContent); + if (nPos >= 0) + { + Sequence< ScriptEventDescriptor > aEvts; + Reference< XEventAttacherManager > xManager(xForm, UNO_QUERY); + if (xManager.is()) + aEvts = xManager->getScriptEvents(nPos); + + try + { + pObj->SetObjEnv(xForm, nPos, aEvts); + xForm->removeByIndex(nPos); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + + } + } + } +} + +// XEventListener +//------------------------------------------------------------------------------ +void SAL_CALL FmXUndoEnvironment::disposing(const EventObject& e) throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::disposing" ); + // check if it's an object we have cached informations about + if (m_pPropertySetCache) + { + Reference< XPropertySet > xSourceSet(e.Source, UNO_QUERY); + if (xSourceSet.is()) + { + PropertySetInfoCache* pCache = static_cast<PropertySetInfoCache*>(m_pPropertySetCache); + PropertySetInfoCacheIterator aSetPos = pCache->find(xSourceSet); + if (aSetPos != pCache->end()) + pCache->erase(aSetPos); + } + } +} + +// XPropertyChangeListener +//------------------------------------------------------------------------------ +void SAL_CALL FmXUndoEnvironment::propertyChange(const PropertyChangeEvent& evt) throw(::com::sun::star::uno::RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::propertyChange" ); + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + + if (!IsLocked()) + { + Reference< XPropertySet > xSet(evt.Source, UNO_QUERY); + if (!xSet.is()) + return; + + // if it's a "default value" property of a control model, set the according "value" property + static ::rtl::OUString pDefaultValueProperties[] = { + FM_PROP_DEFAULT_TEXT, FM_PROP_DEFAULTCHECKED, FM_PROP_DEFAULT_DATE, FM_PROP_DEFAULT_TIME, + FM_PROP_DEFAULT_VALUE, FM_PROP_DEFAULT_SELECT_SEQ, FM_PROP_EFFECTIVE_DEFAULT + }; + const ::rtl::OUString aValueProperties[] = { + FM_PROP_TEXT, FM_PROP_STATE, FM_PROP_DATE, FM_PROP_TIME, + FM_PROP_VALUE, FM_PROP_SELECT_SEQ, FM_PROP_EFFECTIVE_VALUE + }; + sal_Int32 nDefaultValueProps = SAL_N_ELEMENTS(pDefaultValueProperties); + OSL_ENSURE(SAL_N_ELEMENTS(aValueProperties) == nDefaultValueProps, + "FmXUndoEnvironment::propertyChange: inconsistence!"); + for (sal_Int32 i=0; i<nDefaultValueProps; ++i) + { + if (0 == evt.PropertyName.compareTo(pDefaultValueProperties[i])) + { + try + { + xSet->setPropertyValue(aValueProperties[i], evt.NewValue); + } + catch(const Exception&) + { + OSL_ENSURE(sal_False, "FmXUndoEnvironment::propertyChange: could not adjust the value property!"); + } + } + } + + // no Undo for transient and readonly props. But unfortunately "transient" is not only that the + // "transient" flag is set for the property in question, instead is is somewhat more complex + // Transience criterions are: + // - the "transient" flag is set for the property + // - OR the control has a non-empty COntrolSource property, i.e. is intended to be bound + // to a database column. Note that it doesn't matter here whether the control actually + // *is* bound to a column + // - OR the control is bound to an external value via XBindableValue/XValueBinding + // which does not have a "ExternalData" property being <TRUE/> + + if (!m_pPropertySetCache) + m_pPropertySetCache = new PropertySetInfoCache; + PropertySetInfoCache* pCache = static_cast<PropertySetInfoCache*>(m_pPropertySetCache); + + // let's see if we know something about the set + PropertySetInfoCacheIterator aSetPos = pCache->find(xSet); + if (aSetPos == pCache->end()) + { + PropertySetInfo aNewEntry; + if (!::comphelper::hasProperty(FM_PROP_CONTROLSOURCE, xSet)) + { + aNewEntry.bHasEmptyControlSource = sal_False; + } + else + { + try + { + Any aCurrentControlSource = xSet->getPropertyValue(FM_PROP_CONTROLSOURCE); + aNewEntry.bHasEmptyControlSource = !aCurrentControlSource.hasValue() || (::comphelper::getString(aCurrentControlSource).getLength() == 0); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + aSetPos = pCache->insert(PropertySetInfoCache::value_type(xSet,aNewEntry)).first; + DBG_ASSERT(aSetPos != pCache->end(), "FmXUndoEnvironment::propertyChange : just inserted it ... why it's not there ?"); + } + else + { // is it the DataField property ? + if (evt.PropertyName.equals(FM_PROP_CONTROLSOURCE)) + { + aSetPos->second.bHasEmptyControlSource = !evt.NewValue.hasValue() || (::comphelper::getString(evt.NewValue).getLength() == 0); + } + } + + // now we have access to the cached info about the set + // let's see what we know about the property + PropertySetInfo::AllProperties& rPropInfos = aSetPos->second.aProps; + PropertySetInfo::AllPropertiesIterator aPropertyPos = rPropInfos.find(evt.PropertyName); + if (aPropertyPos == rPropInfos.end()) + { // nothing 'til now ... have to change this .... + PropertyInfo aNewEntry; + + // the attributes + INT32 nAttributes = xSet->getPropertySetInfo()->getPropertyByName(evt.PropertyName).Attributes; + aNewEntry.bIsTransientOrReadOnly = ((nAttributes & PropertyAttribute::READONLY) != 0) || ((nAttributes & PropertyAttribute::TRANSIENT) != 0); + + // check if it is the special "DataFieldProperty" + aNewEntry.bIsValueProperty = sal_False; + try + { + if (::comphelper::hasProperty(FM_PROP_CONTROLSOURCEPROPERTY, xSet)) + { + Any aControlSourceProperty = xSet->getPropertyValue(FM_PROP_CONTROLSOURCEPROPERTY); + ::rtl::OUString sControlSourceProperty; + aControlSourceProperty >>= sControlSourceProperty; + + aNewEntry.bIsValueProperty = (sControlSourceProperty.equals(evt.PropertyName)); + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + + // insert the new entry + aPropertyPos = rPropInfos.insert(PropertySetInfo::AllProperties::value_type(evt.PropertyName,aNewEntry)).first; + DBG_ASSERT(aPropertyPos != rPropInfos.end(), "FmXUndoEnvironment::propertyChange : just inserted it ... why it's not there ?"); + } + + // now we have access to the cached info about the property affected + // and are able to decide wether or not we need an undo action + + bool bAddUndoAction = rModel.IsUndoEnabled(); + // no UNDO for transient/readonly properties + if ( bAddUndoAction && aPropertyPos->second.bIsTransientOrReadOnly ) + bAddUndoAction = false; + + if ( bAddUndoAction && aPropertyPos->second.bIsValueProperty ) + { + // no UNDO when the "value" property changes, but the ControlSource is non-empty + // (in this case the control is intended to be bound to a database column) + if ( !aSetPos->second.bHasEmptyControlSource ) + bAddUndoAction = false; + + // no UNDO if the control is currently bound to an external value + if ( bAddUndoAction ) + { + Reference< XBindableValue > xBindable( evt.Source, UNO_QUERY ); + Reference< XValueBinding > xBinding; + if ( xBindable.is() ) + xBinding = xBindable->getValueBinding(); + + Reference< XPropertySet > xBindingProps; + Reference< XPropertySetInfo > xBindingPropsPSI; + if ( xBindable.is() ) + xBindingProps.set( xBinding, UNO_QUERY ); + if ( xBindingProps.is() ) + xBindingPropsPSI = xBindingProps->getPropertySetInfo(); + // TODO: we should cache all those things, else this might be too expensive. + // However, this requires we're notified of changes in the value binding + + static const ::rtl::OUString s_sExternalData( RTL_CONSTASCII_USTRINGPARAM( "ExternalData" ) ); + if ( xBindingPropsPSI.is() && xBindingPropsPSI->hasPropertyByName( s_sExternalData ) ) + { + sal_Bool bExternalData = sal_True; + OSL_VERIFY( xBindingProps->getPropertyValue( s_sExternalData ) >>= bExternalData ); + bAddUndoAction = !bExternalData; + } + else + bAddUndoAction = !xBinding.is(); + } + } + + if ( bAddUndoAction && ( evt.PropertyName == FM_PROP_STRINGITEMLIST ) ) + { + Reference< XListEntrySink > xSink( evt.Source, UNO_QUERY ); + if ( xSink.is() && xSink->getListEntrySource().is() ) + // #i41029# / 2005-01-31 / frank.schoenheit@sun.com + bAddUndoAction = false; + } + + if ( bAddUndoAction ) + { + aGuard.clear(); + // TODO: this is a potential race condition: two threads here could in theory + // add their undo actions out-of-order + + SolarMutexGuard aSolarGuard; + rModel.AddUndo(new FmUndoPropertyAction(rModel, evt)); + } + } + else + { + // if it's the DataField property we may have to adjust our cache + if (m_pPropertySetCache && evt.PropertyName.equals(FM_PROP_CONTROLSOURCE)) + { + Reference< XPropertySet > xSet(evt.Source, UNO_QUERY); + PropertySetInfoCache* pCache = static_cast<PropertySetInfoCache*>(m_pPropertySetCache); + PropertySetInfo& rSetInfo = (*pCache)[xSet]; + rSetInfo.bHasEmptyControlSource = !evt.NewValue.hasValue() || (::comphelper::getString(evt.NewValue).getLength() == 0); + } + } +} + +// XContainerListener +//------------------------------------------------------------------------------ +void SAL_CALL FmXUndoEnvironment::elementInserted(const ContainerEvent& evt) throw(::com::sun::star::uno::RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::elementInserted" ); + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + // neues Object zum lauschen + Reference< XInterface > xIface; + evt.Element >>= xIface; + OSL_ENSURE(xIface.is(), "FmXUndoEnvironment::elementInserted: invalid container notification!"); + AddElement(xIface); + + implSetModified(); +} + +//------------------------------------------------------------------------------ +void FmXUndoEnvironment::implSetModified() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::implSetModified" ); + if ( !IsLocked() && rModel.GetObjectShell() ) + { + rModel.GetObjectShell()->SetModified( sal_True ); + } +} + +//------------------------------------------------------------------------------ +void SAL_CALL FmXUndoEnvironment::elementReplaced(const ContainerEvent& evt) throw(::com::sun::star::uno::RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::elementReplaced" ); + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + Reference< XInterface > xIface; + evt.ReplacedElement >>= xIface; + OSL_ENSURE(xIface.is(), "FmXUndoEnvironment::elementReplaced: invalid container notification!"); + RemoveElement(xIface); + + evt.Element >>= xIface; + AddElement(xIface); + + implSetModified(); +} + +//------------------------------------------------------------------------------ +void SAL_CALL FmXUndoEnvironment::elementRemoved(const ContainerEvent& evt) throw(::com::sun::star::uno::RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::elementRemoved" ); + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + Reference< XInterface > xIface( evt.Element, UNO_QUERY ); + OSL_ENSURE(xIface.is(), "FmXUndoEnvironment::elementRemoved: invalid container notification!"); + RemoveElement(xIface); + + implSetModified(); +} + +//------------------------------------------------------------------------------ +void SAL_CALL FmXUndoEnvironment::modified( const EventObject& /*aEvent*/ ) throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::modified" ); + implSetModified(); +} + +//------------------------------------------------------------------------------ +void FmXUndoEnvironment::AddForms(const Reference< XNameContainer > & rForms) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::AddForms" ); + Lock(); + Reference< XInterface > xInt(rForms, UNO_QUERY); + AddElement(xInt); + UnLock(); +} + +//------------------------------------------------------------------------------ +void FmXUndoEnvironment::RemoveForms(const Reference< XNameContainer > & rForms) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::RemoveForms" ); + Lock(); + Reference< XInterface > xInt(rForms, UNO_QUERY); + RemoveElement(xInt); + UnLock(); +} + +//------------------------------------------------------------------------------ +void FmXUndoEnvironment::TogglePropertyListening(const Reference< XInterface > & Element) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::TogglePropertyListening" ); + // am Container horchen + Reference< XIndexContainer > xContainer(Element, UNO_QUERY); + if (xContainer.is()) + { + sal_uInt32 nCount = xContainer->getCount(); + Reference< XInterface > xIface; + for (sal_uInt32 i = 0; i < nCount; i++) + { + xContainer->getByIndex(i) >>= xIface; + TogglePropertyListening(xIface); + } + } + + Reference< XPropertySet > xSet(Element, UNO_QUERY); + if (xSet.is()) + { + if (!bReadOnly) + xSet->addPropertyChangeListener( ::rtl::OUString(), this ); + else + xSet->removePropertyChangeListener( ::rtl::OUString(), this ); + } +} + + +//------------------------------------------------------------------------------ +void FmXUndoEnvironment::switchListening( const Reference< XIndexContainer >& _rxContainer, bool _bStartListening ) SAL_THROW(()) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::switchListening" ); + OSL_PRECOND( _rxContainer.is(), "FmXUndoEnvironment::switchListening: invalid container!" ); + if ( !_rxContainer.is() ) + return; + + try + { + // if it's an EventAttacherManager, then we need to listen for + // script events + Reference< XEventAttacherManager > xManager( _rxContainer, UNO_QUERY ); + if ( xManager.is() ) + { + if ( _bStartListening ) + { + m_pScriptingEnv->registerEventAttacherManager( xManager ); + if ( m_vbaListener.is() ) + xManager->addScriptListener( m_vbaListener ); + } + else + { + m_pScriptingEnv->revokeEventAttacherManager( xManager ); + if ( m_vbaListener.is() ) + xManager->removeScriptListener( m_vbaListener ); + } + } + + // also handle all children of this element + sal_uInt32 nCount = _rxContainer->getCount(); + Reference< XInterface > xInterface; + for ( sal_uInt32 i = 0; i < nCount; ++i ) + { + _rxContainer->getByIndex( i ) >>= xInterface; + if ( _bStartListening ) + AddElement( xInterface ); + else + RemoveElement( xInterface ); + } + + // be notified of any changes in the container elements + Reference< XContainer > xSimpleContainer( _rxContainer, UNO_QUERY ); + OSL_ENSURE( xSimpleContainer.is(), "FmXUndoEnvironment::switchListening: how are we expected to be notified of changes in the container?" ); + if ( xSimpleContainer.is() ) + { + if ( _bStartListening ) + xSimpleContainer->addContainerListener( this ); + else + xSimpleContainer->removeContainerListener( this ); + } + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FmXUndoEnvironment::switchListening: caught an exception!" ); + } +} + +//------------------------------------------------------------------------------ +void FmXUndoEnvironment::switchListening( const Reference< XInterface >& _rxObject, bool _bStartListening ) SAL_THROW(()) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::switchListening" ); + OSL_PRECOND( _rxObject.is(), "FmXUndoEnvironment::switchListening: how should I listen at a NULL object?" ); + + try + { + if ( !bReadOnly ) + { + Reference< XPropertySet > xProps( _rxObject, UNO_QUERY ); + if ( xProps.is() ) + { + if ( _bStartListening ) + xProps->addPropertyChangeListener( ::rtl::OUString(), this ); + else + xProps->removePropertyChangeListener( ::rtl::OUString(), this ); + } + } + + Reference< XModifyBroadcaster > xBroadcaster( _rxObject, UNO_QUERY ); + if ( xBroadcaster.is() ) + { + if ( _bStartListening ) + xBroadcaster->addModifyListener( this ); + else + xBroadcaster->removeModifyListener( this ); + } + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FmXUndoEnvironment::switchListening: caught an exception!" ); + } +} + +//------------------------------------------------------------------------------ +void FmXUndoEnvironment::AddElement(const Reference< XInterface >& _rxElement ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::AddElement" ); + OSL_ENSURE( !m_bDisposed, "FmXUndoEnvironment::AddElement: not when I'm already disposed!" ); + + // am Container horchen + Reference< XIndexContainer > xContainer( _rxElement, UNO_QUERY ); + if ( xContainer.is() ) + switchListening( xContainer, true ); + + switchListening( _rxElement, true ); +} + +//------------------------------------------------------------------------------ +void FmXUndoEnvironment::RemoveElement(const Reference< XInterface >& _rxElement) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXUndoEnvironment::RemoveElement" ); + if ( m_bDisposed ) + return; + + switchListening( _rxElement, false ); + + if (!bReadOnly) + { + // reset the ActiveConnection if the form is to be removed. This will (should) free the resources + // associated with this connection + // 86299 - 05/02/2001 - frank.schoenheit@germany.sun.com + Reference< XForm > xForm( _rxElement, UNO_QUERY ); + Reference< XPropertySet > xFormProperties( xForm, UNO_QUERY ); + if ( xFormProperties.is() ) + if ( !::svxform::OStaticDataAccessTools().isEmbeddedInDatabase( _rxElement ) ) + // (if there is a connection in the context of the component, setting + // a new connection would be vetoed, anyway) + // #i34196# - 2004-09-21 - fs@openoffice.org + xFormProperties->setPropertyValue( FM_PROP_ACTIVE_CONNECTION, Any() ); + } + + Reference< XIndexContainer > xContainer( _rxElement, UNO_QUERY ); + if ( xContainer.is() ) + switchListening( xContainer, false ); +} + + +//------------------------------------------------------------------------------ +FmUndoPropertyAction::FmUndoPropertyAction(FmFormModel& rNewMod, const PropertyChangeEvent& evt) + :SdrUndoAction(rNewMod) + ,xObj(evt.Source, UNO_QUERY) + ,aPropertyName(evt.PropertyName) + ,aNewValue(evt.NewValue) + ,aOldValue(evt.OldValue) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoPropertyAction::FmUndoPropertyAction" ); + if (rNewMod.GetObjectShell()) + rNewMod.GetObjectShell()->SetModified(sal_True); + if(static_STR_UNDO_PROPERTY.Len() == 0) + static_STR_UNDO_PROPERTY = SVX_RES(RID_STR_UNDO_PROPERTY); +} + + +//------------------------------------------------------------------------------ +void FmUndoPropertyAction::Undo() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoPropertyAction::Undo" ); + FmXUndoEnvironment& rEnv = ((FmFormModel&)rMod).GetUndoEnv(); + + if (xObj.is() && !rEnv.IsLocked()) + { + rEnv.Lock(); + try + { + xObj->setPropertyValue( aPropertyName, aOldValue ); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FmUndoPropertyAction::Undo: caught an exception!" ); + } + rEnv.UnLock(); + } +} + +//------------------------------------------------------------------------------ +void FmUndoPropertyAction::Redo() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoPropertyAction::Redo" ); + FmXUndoEnvironment& rEnv = ((FmFormModel&)rMod).GetUndoEnv(); + + if (xObj.is() && !rEnv.IsLocked()) + { + rEnv.Lock(); + try + { + xObj->setPropertyValue( aPropertyName, aNewValue ); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FmUndoPropertyAction::Redo: caught an exception!" ); + } + rEnv.UnLock(); + } +} + +//------------------------------------------------------------------------------ +String FmUndoPropertyAction::GetComment() const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoPropertyAction::GetComment" ); + String aStr(static_STR_UNDO_PROPERTY); + + aStr.SearchAndReplace( '#', aPropertyName ); + return aStr; +} + + +DBG_NAME(FmUndoContainerAction); +//------------------------------------------------------------------------------ +FmUndoContainerAction::FmUndoContainerAction(FmFormModel& _rMod, + Action _eAction, + const Reference< XIndexContainer > & xCont, + const Reference< XInterface > & xElem, + sal_Int32 nIdx) + :SdrUndoAction( _rMod ) + ,m_xContainer( xCont ) + ,m_nIndex( nIdx ) + ,m_eAction( _eAction ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoContainerAction::FmUndoContainerAction" ); + OSL_ENSURE( nIdx >= 0, "FmUndoContainerAction::FmUndoContainerAction: invalid index!" ); + // some old code suggested this could be a valid argument. However, this code was + // buggy, and it *seemed* that nobody used it - so it was removed. + + DBG_CTOR(FmUndoContainerAction,NULL); + if ( xCont.is() && xElem.is() ) + { + // normalize + m_xElement = m_xElement.query( xElem ); + if ( m_eAction == Removed ) + { + if (m_nIndex >= 0) + { + Reference< XEventAttacherManager > xManager( xCont, UNO_QUERY ); + if ( xManager.is() ) + m_aEvents = xManager->getScriptEvents(m_nIndex); + } + else + m_xElement = NULL; + + // we now own the element + m_xOwnElement = m_xElement; + } + } +} + +//------------------------------------------------------------------------------ +FmUndoContainerAction::~FmUndoContainerAction() +{ + // if we own the object .... + DisposeElement( m_xOwnElement ); + DBG_DTOR(FmUndoContainerAction,NULL); +} + +//------------------------------------------------------------------------------ + +void FmUndoContainerAction::DisposeElement( const Reference< XInterface > & xElem ) +{ + Reference< XComponent > xComp( xElem, UNO_QUERY ); + if ( xComp.is() ) + { + // and the object does not have a parent + Reference< XChild > xChild( xElem, UNO_QUERY ); + if ( xChild.is() && !xChild->getParent().is() ) + // -> dispose it + xComp->dispose(); + } +} + +//------------------------------------------------------------------------------ +void FmUndoContainerAction::implReInsert( ) SAL_THROW( ( Exception ) ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoContainerAction::implReInsert" ); + if ( m_xContainer->getCount() >= m_nIndex ) + { + // insert the element + Any aVal; + if ( m_xContainer->getElementType() == ::getCppuType( static_cast< const Reference< XFormComponent >* >( NULL ) ) ) + { + aVal <<= Reference< XFormComponent >( m_xElement, UNO_QUERY ); + } + else + { + aVal <<= Reference< XForm >( m_xElement, UNO_QUERY ); + } + m_xContainer->insertByIndex( m_nIndex, aVal ); + + OSL_ENSURE( getElementPos( m_xContainer.get(), m_xElement ) == m_nIndex, "FmUndoContainerAction::implReInsert: insertion did not work!" ); + + // register the events + Reference< XEventAttacherManager > xManager( m_xContainer, UNO_QUERY ); + if ( xManager.is() ) + xManager->registerScriptEvents( m_nIndex, m_aEvents ); + + // we don't own the object anymore + m_xOwnElement = NULL; + } +} + +//------------------------------------------------------------------------------ +void FmUndoContainerAction::implReRemove( ) SAL_THROW( ( Exception ) ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoContainerAction::implReRemove" ); + Reference< XInterface > xElement; + if ( ( m_nIndex >= 0 ) && ( m_nIndex < m_xContainer->getCount() ) ) + m_xContainer->getByIndex( m_nIndex ) >>= xElement; + + if ( xElement != m_xElement ) + { + // the indexes in the container changed. Okay, so go the long way and + // manually determine the index + m_nIndex = getElementPos( m_xContainer.get(), m_xElement ); + if ( m_nIndex != -1 ) + xElement = m_xElement; + } + + OSL_ENSURE( xElement == m_xElement, "FmUndoContainerAction::implReRemove: cannot find the element which I'm responsible for!" ); + if ( xElement == m_xElement ) + { + Reference< XEventAttacherManager > xManager( m_xContainer, UNO_QUERY ); + if ( xManager.is() ) + m_aEvents = xManager->getScriptEvents( m_nIndex ); + m_xContainer->removeByIndex( m_nIndex ); + // from now on, we own this object + m_xOwnElement = m_xElement; + } +} + +//------------------------------------------------------------------------------ +void FmUndoContainerAction::Undo() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoContainerAction::Undo" ); + FmXUndoEnvironment& rEnv = static_cast< FmFormModel& >( rMod ).GetUndoEnv(); + + if ( m_xContainer.is() && !rEnv.IsLocked() && m_xElement.is() ) + { + rEnv.Lock(); + try + { + switch ( m_eAction ) + { + case Inserted: + implReRemove(); + break; + + case Removed: + implReInsert(); + break; + } + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FmUndoContainerAction::Undo: caught an exception!" ); + } + rEnv.UnLock(); + } +} + +//------------------------------------------------------------------------------ +void FmUndoContainerAction::Redo() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoContainerAction::Redo" ); + FmXUndoEnvironment& rEnv = static_cast< FmFormModel& >( rMod ).GetUndoEnv(); + if ( m_xContainer.is() && !rEnv.IsLocked() && m_xElement.is() ) + { + rEnv.Lock(); + try + { + switch ( m_eAction ) + { + case Inserted: + implReInsert(); + break; + + case Removed: + implReRemove(); + break; + } + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FmUndoContainerAction::Redo: caught an exception!" ); + } + rEnv.UnLock(); + } +} + +//------------------------------------------------------------------------------ +FmUndoModelReplaceAction::FmUndoModelReplaceAction(FmFormModel& _rMod, SdrUnoObj* _pObject, const Reference< XControlModel > & _xReplaced) + :SdrUndoAction(_rMod) + ,m_xReplaced(_xReplaced) + ,m_pObject(_pObject) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoModelReplaceAction::FmUndoModelReplaceAction" ); +} + +//------------------------------------------------------------------------------ +FmUndoModelReplaceAction::~FmUndoModelReplaceAction() +{ + // dispose our element if nobody else is responsible for + DisposeElement(m_xReplaced); +} + +//------------------------------------------------------------------------------ + +void FmUndoModelReplaceAction::DisposeElement( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XControlModel>& xReplaced ) +{ + Reference< XComponent > xComp(xReplaced, UNO_QUERY); + if (xComp.is()) + { + Reference< XChild > xChild(xReplaced, UNO_QUERY); + if (!xChild.is() || !xChild->getParent().is()) + xComp->dispose(); + } +} + +//------------------------------------------------------------------------------ +void FmUndoModelReplaceAction::Undo() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoModelReplaceAction::Undo" ); + try + { + Reference< XControlModel > xCurrentModel( m_pObject->GetUnoControlModel() ); + + // replace the model within the parent + Reference< XChild > xCurrentAsChild( xCurrentModel, UNO_QUERY ); + Reference< XNameContainer > xCurrentsParent; + if ( xCurrentAsChild.is() ) + xCurrentsParent = xCurrentsParent.query( xCurrentAsChild->getParent() ); + DBG_ASSERT( xCurrentsParent.is(), "FmUndoModelReplaceAction::Undo: invalid current model!" ); + + if ( xCurrentsParent.is() ) + { + // the form container works with FormComponents + Reference< XFormComponent > xComponent( m_xReplaced, UNO_QUERY ); + DBG_ASSERT( xComponent.is(), "FmUndoModelReplaceAction::Undo: the new model is no form component !" ); + + Reference< XPropertySet > xCurrentAsSet( xCurrentModel, UNO_QUERY ); + DBG_ASSERT( ::comphelper::hasProperty(FM_PROP_NAME, xCurrentAsSet ), "FmUndoModelReplaceAction::Undo : one of the models is invalid !"); + + ::rtl::OUString sName; + xCurrentAsSet->getPropertyValue( FM_PROP_NAME ) >>= sName; + xCurrentsParent->replaceByName( sName, makeAny( xComponent ) ); + + m_pObject->SetUnoControlModel(m_xReplaced); + m_pObject->SetChanged(); + + m_xReplaced = xCurrentModel; + } + } + catch(Exception&) + { + DBG_ERROR("FmUndoModelReplaceAction::Undo : could not replace the model !"); + } +} + +//------------------------------------------------------------------------------ +String FmUndoModelReplaceAction::GetComment() const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmUndoModelReplaceAction::GetComment" ); + return SVX_RES(RID_STR_UNDO_MODEL_REPLACE); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmview.cxx b/svx/source/form/fmview.cxx new file mode 100644 index 000000000000..b0a8ce637fc8 --- /dev/null +++ b/svx/source/form/fmview.cxx @@ -0,0 +1,628 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include <sfx2/docfile.hxx> +#ifdef REFERENCE +#undef REFERENCE +#endif +#include <svtools/ehdl.hxx> +#include <unotools/moduleoptions.hxx> +#include <com/sun/star/sdb/SQLContext.hpp> +#include <com/sun/star/uno/XNamingService.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/form/XLoadable.hpp> +#include <com/sun/star/form/XReset.hpp> +#include "fmvwimp.hxx" +#include <sfx2/objsh.hxx> +#include <sfx2/viewsh.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/dispatch.hxx> +#include <basic/sbuno.hxx> +#include <sfx2/macrconf.hxx> +#include <basic/sbx.hxx> +#include "fmitems.hxx" +#include "fmobj.hxx" +#include "svditer.hxx" +#include <svx/svdpagv.hxx> +#include <svx/svdogrp.hxx> +#include <svx/fmview.hxx> +#include <svx/fmmodel.hxx> +#include <svx/fmpage.hxx> +#include <svx/fmshell.hxx> +#include "fmpgeimp.hxx" +#include "svx/fmtools.hxx" +#include "fmshimp.hxx" +#include "fmservs.hxx" +#include "fmprop.hrc" +#include "fmundo.hxx" +#include <svx/dataaccessdescriptor.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/PropertyState.hpp> +#include <com/sun/star/form/FormComponentType.hpp> +#include <vcl/svapp.hxx> +#include <tools/urlobj.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/stdtext.hxx> +#include <svx/fmglob.hxx> +#include <svx/sdrpagewindow.hxx> +#include "sdrpaintwindow.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::util; +using namespace ::svxform; +using namespace ::svx; + +//======================================================================== +//------------------------------------------------------------------------ +TYPEINIT1(FmFormView, E3dView); + +//------------------------------------------------------------------------ +FmFormView::FmFormView( FmFormModel* pModel, OutputDevice* pOut ) + :E3dView(pModel,pOut) +{ + Init(); +} + +//------------------------------------------------------------------------ +void FmFormView::Init() +{ + pFormShell = NULL; + pImpl = new FmXFormView(::comphelper::getProcessServiceFactory(),this); + pImpl->acquire(); + + ////////////////////////////////////////////////////////////////////// + // Model setzen + SdrModel* pModel = GetModel(); + + DBG_ASSERT( pModel->ISA(FmFormModel), "Falsches Model" ); + if( !pModel->ISA(FmFormModel) ) return; + FmFormModel* pFormModel = (FmFormModel*)pModel; + + ////////////////////////////////////////////////////////////////////// + // DesignMode vom Model holen + sal_Bool bInitDesignMode = pFormModel->GetOpenInDesignMode(); + if ( pFormModel->OpenInDesignModeIsDefaulted( ) ) + { // this means that nobody ever explicitly set this on the model, and the model has never + // been loaded from a stream. + // This means this is a newly created document. This means, we want to have it in design + // mode by default (though a newly created model returns true for GetOpenInDesignMode). + // We _want_ to have this because it makes a lot of hacks following the original fix + // for #94595# unnecessary + // #96399# - 2002-10-11 - fs@openoffice.org + DBG_ASSERT( !bInitDesignMode, "FmFormView::Init: doesn't the model default to FALSE anymore?" ); + // if this asserts, either the on-contruction default in the model has changed (then this here + // may not be necessary anymore), or we're not dealing with a new document .... + bInitDesignMode = sal_True; + } + + SfxObjectShell* pObjShell = pFormModel->GetObjectShell(); + if ( pObjShell && pObjShell->GetMedium() ) + { + const SfxPoolItem *pItem=0; + if ( pObjShell->GetMedium()->GetItemSet()->GetItemState( SID_COMPONENTDATA, sal_False, &pItem ) == SFX_ITEM_SET ) + { + Sequence< PropertyValue > aSeq; + ( ((SfxUnoAnyItem*)pItem)->GetValue() ) >>= aSeq; + ::comphelper::NamedValueCollection aComponentData( aSeq ); + bInitDesignMode = aComponentData.getOrDefault( "ApplyFormDesignMode", bInitDesignMode ); + } + } + + if( pObjShell && pObjShell->IsReadOnly() ) + bInitDesignMode = sal_False; + + // dieses wird in der Shell vorgenommen + // bDesignMode = !bInitDesignMode; // erzwingt, dass SetDesignMode ausgefuehrt wird + SetDesignMode( bInitDesignMode ); +} + +//------------------------------------------------------------------------ +FmFormView::~FmFormView() +{ + if( pFormShell ) + pFormShell->SetView( NULL ); + + pImpl->notifyViewDying(); + pImpl->release(); + pImpl = NULL; +} + +//------------------------------------------------------------------------ +FmFormPage* FmFormView::GetCurPage() +{ + SdrPageView* pPageView = GetSdrPageView(); + FmFormPage* pCurPage = pPageView ? PTR_CAST( FmFormPage, pPageView->GetPage() ) : NULL; + return pCurPage; +} + +//------------------------------------------------------------------------ +void FmFormView::MarkListHasChanged() +{ + E3dView::MarkListHasChanged(); + + if ( pFormShell && IsDesignMode() ) + { + FmFormObj* pObj = getMarkedGrid(); + if ( pImpl->m_pMarkedGrid && pImpl->m_pMarkedGrid != pObj ) + { + pImpl->m_pMarkedGrid = NULL; + if ( pImpl->m_xWindow.is() ) + { + pImpl->m_xWindow->removeFocusListener(pImpl); + pImpl->m_xWindow = NULL; + } + SetMoveOutside(FALSE); + //OLMRefreshAllIAOManagers(); + } + + pFormShell->GetImpl()->SetSelectionDelayed(); + } +} + +namespace +{ + const SdrPageWindow* findPageWindow( const SdrPaintView* _pView, OutputDevice* _pWindow ) + { + SdrPageView* pPageView = _pView->GetSdrPageView(); + if(pPageView) + { + for ( sal_uInt32 window = 0; window < pPageView->PageWindowCount(); ++window ) + { + const SdrPageWindow* pPageWindow = pPageView->GetPageWindow( window ); + if ( !pPageWindow || &pPageWindow->GetPaintWindow().GetOutputDevice() != _pWindow ) + continue; + + return pPageWindow; + } + } + return NULL; + } +} + +//------------------------------------------------------------------------ +void FmFormView::AddWindowToPaintView(OutputDevice* pNewWin) +{ + E3dView::AddWindowToPaintView(pNewWin); + + if ( !pNewWin ) + return; + + // look up the PageViewWindow for the newly inserted window, and care for it + // #i39269# / 2004-12-20 / frank.schoenheit@sun.com + const SdrPageWindow* pPageWindow = findPageWindow( this, pNewWin ); + if ( pPageWindow ) + pImpl->addWindow( *pPageWindow ); +} + +//------------------------------------------------------------------------ +void FmFormView::DeleteWindowFromPaintView(OutputDevice* pNewWin) +{ + const SdrPageWindow* pPageWindow = findPageWindow( this, pNewWin ); + if ( pPageWindow ) + pImpl->removeWindow( pPageWindow->GetControlContainer() ); + + E3dView::DeleteWindowFromPaintView(pNewWin); +} + +//------------------------------------------------------------------------ +void FmFormView::ChangeDesignMode(sal_Bool bDesign) +{ + if (bDesign == IsDesignMode()) + return; + + FmFormModel* pModel = PTR_CAST(FmFormModel, GetModel()); + if (pModel) + { // fuer die Zeit des Uebergangs das Undo-Environment ausschalten, das sichert, dass man dort auch nicht-transiente + // Properties mal eben aendern kann (sollte allerdings mit Vorsicht genossen und beim Rueckschalten des Modes + // auch immer wieder rueckgaegig gemacht werden. Ein Beispiel ist das Setzen der maximalen Text-Laenge durch das + // FmXEditModel an seinem Control.) + pModel->GetUndoEnv().Lock(); + } + + // --- 1. deactivate all controls if we are switching to design mode + if ( bDesign ) + DeactivateControls( GetSdrPageView() ); + + // --- 2. simulate a deactivation (the shell will handle some things there ...?) + if ( pFormShell && pFormShell->GetImpl() ) + pFormShell->GetImpl()->viewDeactivated( *this, sal_True ); + else + pImpl->Deactivate( sal_True ); + + // --- 3. activate all controls, if we're switching to alive mode + if ( !bDesign ) + ActivateControls( GetSdrPageView() ); + + // --- 4. load resp. unload the forms + FmFormPage* pCurPage = GetCurPage(); + if ( pCurPage ) + { + if ( pFormShell && pFormShell->GetImpl() ) + pFormShell->GetImpl()->loadForms( pCurPage, ( bDesign ? FORMS_UNLOAD : FORMS_LOAD ) ); + } + + // --- 5. base class functionality + SetDesignMode( bDesign ); + + // --- 6. simulate a activation (the shell will handle some things there ...?) + OSL_PRECOND( pFormShell && pFormShell->GetImpl(), "FmFormView::ChangeDesignMode: is this really allowed? No shell?" ); + if ( pFormShell && pFormShell->GetImpl() ) + pFormShell->GetImpl()->viewActivated( *this ); + else + pImpl->Activate(); + + if ( pCurPage ) + { + if ( bDesign ) + { + if ( GetActualOutDev() && GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW ) + { + const Window* pWindow = static_cast< const Window* >( GetActualOutDev() ); + const_cast< Window* >( pWindow )->GrabFocus(); + } + + // redraw UNO objects + if ( GetSdrPageView() ) + { + SdrObjListIter aIter(*pCurPage); + while( aIter.IsMore() ) + { + SdrObject* pObj = aIter.Next(); + if (pObj && pObj->IsUnoObj()) + { + // For redraw just use ActionChanged() + // pObj->BroadcastObjectChange(); + pObj->ActionChanged(); + } + } + } + } + else + { + // set the auto focus to the first control (if indicated by the model to do so) + sal_Bool bForceControlFocus = pModel ? pModel->GetAutoControlFocus() : sal_False; + if (bForceControlFocus) + pImpl->AutoFocus(); + } + } + + // und mein Undo-Environment wieder an + if (pModel) + pModel->GetUndoEnv().UnLock(); +} + +//------------------------------------------------------------------------ +void FmFormView::GrabFirstControlFocus( sal_Bool _bForceSync ) +{ + if ( !IsDesignMode() ) + pImpl->AutoFocus( _bForceSync ); +} + +//------------------------------------------------------------------------ +SdrPageView* FmFormView::ShowSdrPage(SdrPage* pPage) +{ + SdrPageView* pPV = E3dView::ShowSdrPage(pPage); + + if (pPage) + { + if (!IsDesignMode()) + { + // creating the controllers + ActivateControls(pPV); + + // Alles deselektieren + UnmarkAll(); + } + else if ( pFormShell && pFormShell->IsDesignMode() ) + { + FmXFormShell* pFormShellImpl = pFormShell->GetImpl(); + pFormShellImpl->UpdateForms( sal_True ); + + // damit der Formular-Navigator auf den Seitenwechsel reagieren kann + pFormShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(SID_FM_FMEXPLORER_CONTROL , sal_True, sal_False); + + pFormShellImpl->SetSelection(GetMarkedObjectList()); + } + } + + // notify our shell that we have been activated + if ( pFormShell && pFormShell->GetImpl() ) + pFormShell->GetImpl()->viewActivated( *this ); + else + pImpl->Activate(); + + return pPV; +} + +//------------------------------------------------------------------------ +void FmFormView::HideSdrPage() +{ + // --- 1. deactivate controls + if ( !IsDesignMode() ) + DeactivateControls(GetSdrPageView()); + + // --- 2. tell the shell the view is (going to be) deactivated + if ( pFormShell && pFormShell->GetImpl() ) + pFormShell->GetImpl()->viewDeactivated( *this, sal_True ); + else + pImpl->Deactivate( sal_True ); + + // --- 3. base class behavior + E3dView::HideSdrPage(); +} + +//------------------------------------------------------------------------ +SdrModel* FmFormView::GetMarkedObjModel() const +{ + return E3dView::GetMarkedObjModel(); +} + +//------------------------------------------------------------------------ +sal_Bool FmFormView::Paste(const SdrModel& rMod, const Point& rPos, SdrObjList* pLst, sal_uInt32 nOptions) +{ + return E3dView::Paste(rMod, rPos, pLst, nOptions); +} + +//------------------------------------------------------------------------ +void FmFormView::ActivateControls(SdrPageView* pPageView) +{ + if (!pPageView) + return; + + for (sal_uInt32 i = 0L; i < pPageView->PageWindowCount(); ++i) + { + const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i); + pImpl->addWindow(rPageWindow); + } +} + +//------------------------------------------------------------------------ +void FmFormView::DeactivateControls(SdrPageView* pPageView) +{ + if( !pPageView ) + return; + + for (sal_uInt32 i = 0L; i < pPageView->PageWindowCount(); ++i) + { + const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i); + pImpl->removeWindow(rPageWindow.GetControlContainer() ); + } +} + +//------------------------------------------------------------------------ +SdrObject* FmFormView::CreateFieldControl( const ODataAccessDescriptor& _rColumnDescriptor ) +{ + return pImpl->implCreateFieldControl( _rColumnDescriptor ); +} + +//------------------------------------------------------------------------ +SdrObject* FmFormView::CreateXFormsControl( const OXFormsDescriptor &_rDesc ) +{ + return pImpl->implCreateXFormsControl(_rDesc); +} + +//------------------------------------------------------------------------ +SdrObject* FmFormView::CreateFieldControl(const UniString& rFieldDesc) const +{ + ::rtl::OUString sDataSource = rFieldDesc.GetToken(0,sal_Unicode(11)); + ::rtl::OUString sObjectName = rFieldDesc.GetToken(1,sal_Unicode(11)); + sal_uInt16 nObjectType = (sal_uInt16)rFieldDesc.GetToken(2,sal_Unicode(11)).ToInt32(); + ::rtl::OUString sFieldName = rFieldDesc.GetToken(3,sal_Unicode(11)); + + if (!sFieldName.getLength() || !sObjectName.getLength() || !sDataSource.getLength()) + return NULL; + + ODataAccessDescriptor aColumnDescriptor; + aColumnDescriptor.setDataSource(sDataSource); + aColumnDescriptor[ daCommand ] <<= sObjectName; + aColumnDescriptor[ daCommandType ] <<= nObjectType; + aColumnDescriptor[ daColumnName ] <<= sFieldName; + + return pImpl->implCreateFieldControl( aColumnDescriptor ); +} + +//------------------------------------------------------------------------ +void FmFormView::InsertControlContainer(const Reference< ::com::sun::star::awt::XControlContainer > & xCC) +{ + if( !IsDesignMode() ) + { + SdrPageView* pPageView = GetSdrPageView(); + if( pPageView ) + { + for( sal_uInt32 i = 0L; i < pPageView->PageWindowCount(); i++ ) + { + const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i); + + if( rPageWindow.GetControlContainer( false ) == xCC ) + { + pImpl->addWindow(rPageWindow); + break; + } + } + } + } +} + +//------------------------------------------------------------------------ +void FmFormView::RemoveControlContainer(const Reference< ::com::sun::star::awt::XControlContainer > & xCC) +{ + if( !IsDesignMode() ) + { + pImpl->removeWindow( xCC ); + } +} + +// ----------------------------------------------------------------------------- +SdrPaintWindow* FmFormView::BeginCompleteRedraw(OutputDevice* pOut) +{ + SdrPaintWindow* pPaintWindow = E3dView::BeginCompleteRedraw( pOut ); + pImpl->suspendTabOrderUpdate(); + return pPaintWindow; +} + +// ----------------------------------------------------------------------------- +void FmFormView::EndCompleteRedraw( SdrPaintWindow& rPaintWindow, bool bPaintFormLayer ) +{ + E3dView::EndCompleteRedraw( rPaintWindow, bPaintFormLayer ); + pImpl->resumeTabOrderUpdate(); +} + +// ----------------------------------------------------------------------------- +BOOL FmFormView::KeyInput(const KeyEvent& rKEvt, Window* pWin) +{ + BOOL bDone = FALSE; + const KeyCode& rKeyCode = rKEvt.GetKeyCode(); + if ( IsDesignMode() + && rKeyCode.GetCode() == KEY_RETURN + ) + { + // RETURN alone enters grid controls, for keyboard accessibility + if ( pWin + && !rKeyCode.IsShift() + && !rKeyCode.IsMod1() + && !rKeyCode.IsMod2() + ) + { + FmFormObj* pObj = getMarkedGrid(); + if ( pObj ) + { + Reference< awt::XWindow > xWindow( pObj->GetUnoControl( *this, *pWin ), UNO_QUERY ); + if ( xWindow.is() ) + { + pImpl->m_pMarkedGrid = pObj; + pImpl->m_xWindow = xWindow; + // add as listener to get notified when ESC will be pressed inside the grid + pImpl->m_xWindow->addFocusListener(pImpl); + SetMoveOutside(TRUE); + //OLMRefreshAllIAOManagers(); + xWindow->setFocus(); + bDone = TRUE; + } + } + } + // Alt-RETURN alone shows the properties of the selection + if ( pFormShell + && pFormShell->GetImpl() + && !rKeyCode.IsShift() + && !rKeyCode.IsMod1() + && rKeyCode.IsMod2() + ) + { + pFormShell->GetImpl()->handleShowPropertiesRequest(); + } + + } + + if ( !bDone ) + bDone = E3dView::KeyInput(rKEvt,pWin); + return bDone; +} +// ----------------------------------------------------------------------------- +sal_Bool FmFormView::checkUnMarkAll(const Reference< XInterface >& _xSource) +{ + Reference< ::com::sun::star::awt::XControl> xControl(pImpl->m_xWindow,UNO_QUERY); + sal_Bool bRet = !xControl.is() || !_xSource.is() || _xSource != xControl->getModel(); + if ( bRet ) + UnmarkAll(); + + return bRet; +} + +// ----------------------------------------------------------------------------- +BOOL FmFormView::MouseButtonDown( const MouseEvent& _rMEvt, Window* _pWin ) +{ + BOOL bReturn = E3dView::MouseButtonDown( _rMEvt, _pWin ); + + if ( pFormShell && pFormShell->GetImpl() ) + { + SdrViewEvent aViewEvent; + PickAnything( _rMEvt, SDRMOUSEBUTTONDOWN, aViewEvent ); + pFormShell->GetImpl()->handleMouseButtonDown( aViewEvent ); + } + + return bReturn; +} + +// ----------------------------------------------------------------------------- +FmFormObj* FmFormView::getMarkedGrid() const +{ + FmFormObj* pFormObject = NULL; + const SdrMarkList& rMarkList = GetMarkedObjectList(); + if ( 1 == rMarkList.GetMarkCount() ) + { + SdrMark* pMark = rMarkList.GetMark(0); + if ( pMark ) + { + pFormObject = FmFormObj::GetFormObject( pMark->GetMarkedSdrObj() ); + if ( pFormObject ) + { + Reference< XServiceInfo > xServInfo( pFormObject->GetUnoControlModel(), UNO_QUERY ); + if ( !xServInfo.is() || !xServInfo->supportsService( FM_SUN_COMPONENT_GRIDCONTROL ) ) + pFormObject = NULL; + } + } + } + return pFormObject; +} + +// ----------------------------------------------------------------------------- +void FmFormView::createControlLabelPair( OutputDevice* _pOutDev, sal_Int32 _nXOffsetMM, sal_Int32 _nYOffsetMM, + const Reference< XPropertySet >& _rxField, const Reference< XNumberFormats >& _rxNumberFormats, + sal_uInt16 _nControlObjectID, const ::rtl::OUString& _rFieldPostfix, UINT32 _nInventor, UINT16 _nLabelObjectID, + SdrPage* _pLabelPage, SdrPage* _pControlPage, SdrModel* _pModel, SdrUnoObj*& _rpLabel, SdrUnoObj*& _rpControl ) +{ + FmXFormView::createControlLabelPair( + ::comphelper::getProcessServiceFactory(), + *_pOutDev, _nXOffsetMM, _nYOffsetMM, + _rxField, _rxNumberFormats, + _nControlObjectID, _rFieldPostfix, _nInventor, _nLabelObjectID, + _pLabelPage, _pControlPage, _pModel, + _rpLabel, _rpControl + ); +} +// ----------------------------------------------------------------------------- +Reference< runtime::XFormController > FmFormView::GetFormController( const Reference< XForm >& _rxForm, const OutputDevice& _rDevice ) const +{ + return pImpl->getFormController( _rxForm, _rDevice ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/fmvwimp.cxx b/svx/source/form/fmvwimp.cxx new file mode 100644 index 000000000000..2af37dccd535 --- /dev/null +++ b/svx/source/form/fmvwimp.cxx @@ -0,0 +1,1961 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include "fmdocumentclassification.hxx" +#include "fmobj.hxx" +#include "fmpgeimp.hxx" +#include "fmprop.hrc" +#include "fmresids.hrc" +#include "fmservs.hxx" +#include "fmshimp.hxx" +#include "svx/fmtools.hxx" +#include "fmundo.hxx" +#include "fmvwimp.hxx" +#include "formcontrolfactory.hxx" +#include "sdrpaintwindow.hxx" +#include "svditer.hxx" +#include "svx/dataaccessdescriptor.hxx" +#include "svx/dialmgr.hxx" +#include "svx/fmglob.hxx" +#include "svx/fmmodel.hxx" +#include "svx/fmpage.hxx" +#include "svx/fmshell.hxx" +#include "svx/fmview.hxx" +#include "svx/sdrpagewindow.hxx" +#include "svx/svdogrp.hxx" +#include "svx/svdpagv.hxx" +#include "xmlexchg.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#include <com/sun/star/style/VerticalAlignment.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/sdbc/XRowSet.hpp> +#include <com/sun/star/form/XLoadable.hpp> +#include <com/sun/star/awt/VisualEffect.hpp> +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> +#include <com/sun/star/util/XNumberFormats.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/form/FormComponentType.hpp> +#include <com/sun/star/form/FormButtonType.hpp> +#include <com/sun/star/form/XReset.hpp> +#include <com/sun/star/form/binding/XBindableValue.hpp> +#include <com/sun/star/form/binding/XValueBinding.hpp> +#include <com/sun/star/form/submission/XSubmissionSupplier.hpp> +#include <com/sun/star/awt/XTabControllerModel.hpp> +#include <com/sun/star/awt/XControlContainer.hpp> +#include <com/sun/star/awt/XTabController.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/awt/XControl.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbc/XPreparedStatement.hpp> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include <com/sun/star/container/XContainer.hpp> +/** === end UNO includes === **/ + +#include <comphelper/enumhelper.hxx> +#include <comphelper/extract.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <comphelper/numbers.hxx> +#include <comphelper/property.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <unotools/moduleoptions.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/msgbox.hxx> +#include <vcl/stdtext.hxx> +#include <osl/mutex.hxx> +#include <rtl/logfile.hxx> + +#include <algorithm> + +using namespace ::comphelper; +using namespace ::svx; +using namespace ::svxform; + + using namespace ::com::sun::star; + /** === begin UNO using === **/ + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Type; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::makeAny; + using ::com::sun::star::style::VerticalAlignment_MIDDLE; + using ::com::sun::star::form::FormButtonType_SUBMIT; + using ::com::sun::star::form::binding::XValueBinding; + using ::com::sun::star::form::binding::XBindableValue; + using ::com::sun::star::lang::XComponent; + using ::com::sun::star::container::XIndexAccess; + using ::com::sun::star::form::XForm; + using ::com::sun::star::form::runtime::XFormController; + using ::com::sun::star::script::XEventAttacherManager; + using ::com::sun::star::awt::XTabControllerModel; + using ::com::sun::star::container::XChild; + using ::com::sun::star::container::XEnumeration; + using ::com::sun::star::task::XInteractionHandler; + using ::com::sun::star::lang::XInitialization; + using ::com::sun::star::awt::XTabController; + using ::com::sun::star::lang::XUnoTunnel; + using ::com::sun::star::awt::XControlContainer; + using ::com::sun::star::awt::XControl; + using ::com::sun::star::form::XFormComponent; + using ::com::sun::star::form::XForm; + using ::com::sun::star::lang::IndexOutOfBoundsException; + using ::com::sun::star::lang::WrappedTargetException; + using ::com::sun::star::container::XContainer; + using ::com::sun::star::container::ContainerEvent; + using ::com::sun::star::lang::EventObject; + using ::com::sun::star::beans::NamedValue; + using ::com::sun::star::sdb::SQLErrorEvent; + using ::com::sun::star::sdbc::XRowSet; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::container::XElementAccess; + using ::com::sun::star::awt::XWindow; + using ::com::sun::star::awt::FocusEvent; + using ::com::sun::star::ui::dialogs::XExecutableDialog; + using ::com::sun::star::sdbc::XDataSource; + using ::com::sun::star::container::XIndexContainer; + using ::com::sun::star::sdbc::XConnection; + using ::com::sun::star::container::XNameAccess; + using ::com::sun::star::sdb::SQLContext; + using ::com::sun::star::sdbc::SQLWarning; + using ::com::sun::star::sdbc::SQLException; + using ::com::sun::star::util::XNumberFormatsSupplier; + using ::com::sun::star::util::XNumberFormats; + using ::com::sun::star::beans::XPropertySetInfo; + /** === end UNO using === **/ + namespace FormComponentType = ::com::sun::star::form::FormComponentType; + namespace CommandType = ::com::sun::star::sdb::CommandType; + namespace DataType = ::com::sun::star::sdbc::DataType; + +//------------------------------------------------------------------------------ +class FmXFormView::ObjectRemoveListener : public SfxListener +{ + FmXFormView* m_pParent; +public: + ObjectRemoveListener( FmXFormView* pParent ); + virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ); +}; + +//======================================================================== +DBG_NAME(FmXPageViewWinRec) +//------------------------------------------------------------------------ +FmXPageViewWinRec::FmXPageViewWinRec( const ::comphelper::ComponentContext& _rContext, const SdrPageWindow& _rWindow, FmXFormView* _pViewImpl ) +: m_xControlContainer( _rWindow.GetControlContainer() ), + m_aContext( _rContext ), + m_pViewImpl( _pViewImpl ), + m_pWindow( dynamic_cast< Window* >( &_rWindow.GetPaintWindow().GetOutputDevice() ) ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXPageViewWinRec::FmXPageViewWinRec" ); + DBG_CTOR(FmXPageViewWinRec,NULL); + + // create an XFormController for every form + FmFormPage* pFormPage = dynamic_cast< FmFormPage* >( _rWindow.GetPageView().GetPage() ); + DBG_ASSERT( pFormPage, "FmXPageViewWinRec::FmXPageViewWinRec: no FmFormPage found!" ); + if ( pFormPage ) + { + try + { + Reference< XIndexAccess > xForms( pFormPage->GetForms(), UNO_QUERY_THROW ); + sal_uInt32 nLength = xForms->getCount(); + for (sal_uInt32 i = 0; i < nLength; i++) + { + Reference< XForm > xForm( xForms->getByIndex(i), UNO_QUERY ); + if ( xForm.is() ) + setController( xForm, NULL ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } +} +// ----------------------------------------------------------------------------- +FmXPageViewWinRec::~FmXPageViewWinRec() +{ + DBG_DTOR(FmXPageViewWinRec,NULL); +} + +//------------------------------------------------------------------ +void FmXPageViewWinRec::dispose() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXPageViewWinRec::dispose" ); + for ( ::std::vector< Reference< XFormController > >::const_iterator i = m_aControllerList.begin(); + i != m_aControllerList.end(); + ++i + ) + { + try + { + Reference< XFormController > xController( *i, UNO_QUERY_THROW ); + + // detaching the events + Reference< XChild > xControllerModel( xController->getModel(), UNO_QUERY ); + if ( xControllerModel.is() ) + { + Reference< XEventAttacherManager > xEventManager( xControllerModel->getParent(), UNO_QUERY_THROW ); + Reference< XInterface > xControllerNormalized( xController, UNO_QUERY_THROW ); + xEventManager->detach( i - m_aControllerList.begin(), xControllerNormalized ); + } + + // dispose the formcontroller + Reference< XComponent > xComp( xController, UNO_QUERY_THROW ); + xComp->dispose(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + m_aControllerList.clear(); +} + + +//------------------------------------------------------------------------------ +sal_Bool SAL_CALL FmXPageViewWinRec::hasElements(void) throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXPageViewWinRec::hasElements" ); + return getCount() != 0; +} + +//------------------------------------------------------------------------------ +Type SAL_CALL FmXPageViewWinRec::getElementType(void) throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXPageViewWinRec::getElementType" ); + return ::getCppuType((const Reference< XFormController>*)0); +} + +// XEnumerationAccess +//------------------------------------------------------------------------------ +Reference< XEnumeration > SAL_CALL FmXPageViewWinRec::createEnumeration(void) throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXPageViewWinRec::createEnumeration" ); + return new ::comphelper::OEnumerationByIndex(this); +} + +// XIndexAccess +//------------------------------------------------------------------------------ +sal_Int32 SAL_CALL FmXPageViewWinRec::getCount(void) throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXPageViewWinRec::getCount" ); + return m_aControllerList.size(); +} + +//------------------------------------------------------------------------------ +Any SAL_CALL FmXPageViewWinRec::getByIndex(sal_Int32 nIndex) throw( IndexOutOfBoundsException, WrappedTargetException, RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXPageViewWinRec::getByIndex" ); + if (nIndex < 0 || + nIndex >= getCount()) + throw IndexOutOfBoundsException(); + + Any aElement; + aElement <<= m_aControllerList[nIndex]; + return aElement; +} + +//------------------------------------------------------------------------ +void SAL_CALL FmXPageViewWinRec::makeVisible( const Reference< XControl >& _Control ) throw (RuntimeException) +{ + SolarMutexGuard aSolarGuard; + + Reference< XWindow > xWindow( _Control, UNO_QUERY ); + if ( xWindow.is() && m_pViewImpl->getView() && m_pWindow ) + { + awt::Rectangle aRect = xWindow->getPosSize(); + ::Rectangle aNewRect( aRect.X, aRect.Y, aRect.X + aRect.Width, aRect.Y + aRect.Height ); + aNewRect = m_pWindow->PixelToLogic( aNewRect ); + m_pViewImpl->getView()->MakeVisible( aNewRect, *m_pWindow ); + } +} + +//------------------------------------------------------------------------ +Reference< XFormController > getControllerSearchChilds( const Reference< XIndexAccess > & xIndex, const Reference< XTabControllerModel > & xModel) +{ + if (xIndex.is() && xIndex->getCount()) + { + Reference< XFormController > xController; + + for (sal_Int32 n = xIndex->getCount(); n-- && !xController.is(); ) + { + xIndex->getByIndex(n) >>= xController; + if ((XTabControllerModel*)xModel.get() == (XTabControllerModel*)xController->getModel().get()) + return xController; + else + { + xController = getControllerSearchChilds(Reference< XIndexAccess > (xController, UNO_QUERY), xModel); + if ( xController.is() ) + return xController; + } + } + } + return Reference< XFormController > (); +} + +// Search the according controller +//------------------------------------------------------------------------ +Reference< XFormController > FmXPageViewWinRec::getController( const Reference< XForm > & xForm ) const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXPageViewWinRec::getController" ); + Reference< XTabControllerModel > xModel(xForm, UNO_QUERY); + for (::std::vector< Reference< XFormController > >::const_iterator i = m_aControllerList.begin(); + i != m_aControllerList.end(); i++) + { + if ((XTabControllerModel*)(*i)->getModel().get() == (XTabControllerModel*)xModel.get()) + return *i; + + // the current-round controller isn't the right one. perhaps one of it's children ? + Reference< XFormController > xChildSearch = getControllerSearchChilds(Reference< XIndexAccess > (*i, UNO_QUERY), xModel); + if (xChildSearch.is()) + return xChildSearch; + } + return Reference< XFormController > (); +} + +//------------------------------------------------------------------------ +void FmXPageViewWinRec::setController(const Reference< XForm > & xForm, const Reference< XFormController >& _rxParentController ) +{ + DBG_ASSERT( xForm.is(), "FmXPageViewWinRec::setController: there should be a form!" ); + Reference< XIndexAccess > xFormCps(xForm, UNO_QUERY); + if (!xFormCps.is()) + return; + + Reference< XTabControllerModel > xTabOrder(xForm, UNO_QUERY); + + // create a form controller + Reference< XFormController > xController( m_aContext.createComponent( FM_FORM_CONTROLLER ), UNO_QUERY ); + if ( !xController.is() ) + { + ShowServiceNotAvailableError( m_pWindow, FM_FORM_CONTROLLER, sal_True ); + return; + } + + Reference< XInteractionHandler > xHandler; + if ( _rxParentController.is() ) + xHandler = _rxParentController->getInteractionHandler(); + else + { + // TODO: should we create a default handler? Not really necessary, since the + // FormController itself has a default fallback + } + if ( xHandler.is() ) + xController->setInteractionHandler( xHandler ); + + xController->setContext( this ); + + xController->setModel( xTabOrder ); + xController->setContainer( m_xControlContainer ); + xController->activateTabOrder(); + xController->addActivateListener( m_pViewImpl ); + + if ( _rxParentController.is() ) + _rxParentController->addChildController( xController ); + else + { + m_aControllerList.push_back(xController); + + xController->setParent( *this ); + + // attaching the events + Reference< XEventAttacherManager > xEventManager( xForm->getParent(), UNO_QUERY ); + Reference< XInterface > xIfc(xController, UNO_QUERY); + xEventManager->attach(m_aControllerList.size() - 1, xIfc, makeAny(xController) ); + } + + // jetzt die Subforms durchgehen + sal_uInt32 nLength = xFormCps->getCount(); + Reference< XForm > xSubForm; + for (sal_uInt32 i = 0; i < nLength; i++) + { + if ( xFormCps->getByIndex(i) >>= xSubForm ) + setController( xSubForm, xController ); + } +} + +//------------------------------------------------------------------------ +void FmXPageViewWinRec::updateTabOrder( const Reference< XForm >& _rxForm ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXPageViewWinRec::updateTabOrder" ); + OSL_PRECOND( _rxForm.is(), "FmXPageViewWinRec::updateTabOrder: illegal argument!" ); + if ( !_rxForm.is() ) + return; + + try + { + Reference< XTabController > xTabCtrl( getController( _rxForm ).get() ); + if ( xTabCtrl.is() ) + { // if there already is a TabController for this form, then delegate the "updateTabOrder" request + xTabCtrl->activateTabOrder(); + } + else + { // otherwise, create a TabController + + // if it's a sub form, then we must ensure there exist TabControllers + // for all its ancestors, too + Reference< XForm > xParentForm( _rxForm->getParent(), UNO_QUERY ); + // there is a parent form -> look for the respective controller + Reference< XFormController > xParentController; + if ( xParentForm.is() ) + xParentController.set( getController( xParentForm ), UNO_QUERY ); + + setController( _rxForm, xParentController ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +//------------------------------------------------------------------------ +FmXFormView::FmXFormView(const ::comphelper::ComponentContext& _rContext, FmFormView* _pView ) + :m_aContext( _rContext ) + ,m_pMarkedGrid(NULL) + ,m_pView(_pView) + ,m_nActivationEvent(0) + ,m_nErrorMessageEvent( 0 ) + ,m_nAutoFocusEvent( 0 ) + ,m_nControlWizardEvent( 0 ) + ,m_pWatchStoredList( NULL ) + ,m_bFirstActivation( true ) + ,m_isTabOrderUpdateSuspended( false ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::FmXFormView" ); +} + +//------------------------------------------------------------------------ +void FmXFormView::cancelEvents() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::cancelEvents" ); + if ( m_nActivationEvent ) + { + Application::RemoveUserEvent( m_nActivationEvent ); + m_nActivationEvent = 0; + } + + if ( m_nErrorMessageEvent ) + { + Application::RemoveUserEvent( m_nErrorMessageEvent ); + m_nErrorMessageEvent = 0; + } + + if ( m_nAutoFocusEvent ) + { + Application::RemoveUserEvent( m_nAutoFocusEvent ); + m_nAutoFocusEvent = 0; + } + + if ( m_nControlWizardEvent ) + { + Application::RemoveUserEvent( m_nControlWizardEvent ); + m_nControlWizardEvent = 0; + } +} + +//------------------------------------------------------------------------ +void FmXFormView::notifyViewDying( ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::notifyViewDying" ); + DBG_ASSERT( m_pView, "FmXFormView::notifyViewDying: my view already died!" ); + m_pView = NULL; + cancelEvents(); +} + +//------------------------------------------------------------------------ +FmXFormView::~FmXFormView() +{ + DBG_ASSERT(m_aWinList.size() == 0, "FmXFormView::~FmXFormView: Window list not empty!"); + + cancelEvents(); + + delete m_pWatchStoredList; + m_pWatchStoredList = NULL; +} + +// EventListener +//------------------------------------------------------------------------------ +void SAL_CALL FmXFormView::disposing(const EventObject& Source) throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::disposing" ); + if ( m_xWindow.is() && Source.Source == m_xWindow ) + removeGridWindowListening(); +} + +// XFormControllerListener +//------------------------------------------------------------------------------ +void SAL_CALL FmXFormView::formActivated(const EventObject& rEvent) throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::formActivated" ); + if ( m_pView && m_pView->GetFormShell() && m_pView->GetFormShell()->GetImpl() ) + m_pView->GetFormShell()->GetImpl()->formActivated( rEvent ); +} + +//------------------------------------------------------------------------------ +void SAL_CALL FmXFormView::formDeactivated(const EventObject& rEvent) throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::formDeactivated" ); + if ( m_pView && m_pView->GetFormShell() && m_pView->GetFormShell()->GetImpl() ) + m_pView->GetFormShell()->GetImpl()->formDeactivated( rEvent ); +} + +// XContainerListener +//------------------------------------------------------------------------------ +void SAL_CALL FmXFormView::elementInserted(const ContainerEvent& evt) throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::elementInserted" ); + try + { + Reference< XControlContainer > xControlContainer( evt.Source, UNO_QUERY_THROW ); + Reference< XControl > xControl( evt.Element, UNO_QUERY_THROW ); + Reference< XFormComponent > xControlModel( xControl->getModel(), UNO_QUERY_THROW ); + Reference< XForm > xForm( xControlModel->getParent(), UNO_QUERY_THROW ); + + if ( m_isTabOrderUpdateSuspended ) + { + // remember the container and the control, so we can update the tab order on resumeTabOrderUpdate + m_aNeedTabOrderUpdate[ xControlContainer ].insert( xForm ); + } + else + { + FmWinRecList::iterator pos = findWindow( xControlContainer ); + if ( pos != m_aWinList.end() ) + { + (*pos)->updateTabOrder( xForm ); + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +//------------------------------------------------------------------------------ +void SAL_CALL FmXFormView::elementReplaced(const ContainerEvent& evt) throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::elementReplaced" ); + elementInserted(evt); +} + +//------------------------------------------------------------------------------ +void SAL_CALL FmXFormView::elementRemoved(const ContainerEvent& /*evt*/) throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::elementRemoved" ); +} + +//------------------------------------------------------------------------------ +FmWinRecList::const_iterator FmXFormView::findWindow( const Reference< XControlContainer >& _rxCC ) const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::findWindow" ); + for (FmWinRecList::const_iterator i = m_aWinList.begin(); + i != m_aWinList.end(); ++i) + { + if ( _rxCC == (*i)->getControlContainer() ) + return i; + } + return m_aWinList.end(); +} + +//------------------------------------------------------------------------------ +FmWinRecList::iterator FmXFormView::findWindow( const Reference< XControlContainer >& _rxCC ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::findWindow" ); + for (FmWinRecList::iterator i = m_aWinList.begin(); + i != m_aWinList.end(); ++i) + { + if ( _rxCC == (*i)->getControlContainer() ) + return i; + } + return m_aWinList.end(); +} + +//------------------------------------------------------------------------------ +void FmXFormView::addWindow(const SdrPageWindow& rWindow) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::addWindow" ); + FmFormPage* pFormPage = PTR_CAST( FmFormPage, rWindow.GetPageView().GetPage() ); + if ( !pFormPage ) + return; + + Reference< XControlContainer > xCC = rWindow.GetControlContainer(); + if ( xCC.is() && findWindow( xCC ) == m_aWinList.end()) + { + FmXPageViewWinRec *pFmRec = new FmXPageViewWinRec( m_aContext, rWindow, this ); + pFmRec->acquire(); + + m_aWinList.push_back(pFmRec); + + // Am ControlContainer horchen um Aenderungen mitzbekommen + Reference< XContainer > xContainer( xCC, UNO_QUERY ); + if (xContainer.is()) + xContainer->addContainerListener(this); + } +} + +//------------------------------------------------------------------------------ +void FmXFormView::removeWindow( const Reference< XControlContainer >& _rxCC ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::removeWindow" ); + // Wird gerufen, wenn + // - in den Design-Modus geschaltet wird + // - ein Window geloescht wird, waehrend man im Design-Modus ist + // - der Control-Container fuer ein Window entfernt wird, waehrend + // der aktive Modus eingeschaltet ist. + FmWinRecList::iterator i = findWindow( _rxCC ); + if (i != m_aWinList.end()) + { + // Am ControlContainer horchen um Aenderungen mitzbekommen + Reference< XContainer > xContainer( _rxCC, UNO_QUERY ); + if (xContainer.is()) + xContainer->removeContainerListener(this); + + (*i)->dispose(); + (*i)->release(); + m_aWinList.erase(i); + } +} + +//------------------------------------------------------------------------------ +void FmXFormView::displayAsyncErrorMessage( const SQLErrorEvent& _rEvent ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::displayAsyncErrorMessage" ); + DBG_ASSERT( 0 == m_nErrorMessageEvent, "FmXFormView::displayAsyncErrorMessage: not too fast, please!" ); + // This should not happen - usually, the PostUserEvent is faster than any possible user + // interaction which could trigger a new error. If it happens, we need a queue for the events. + m_aAsyncError = _rEvent; + m_nErrorMessageEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnDelayedErrorMessage ) ); +} + +//------------------------------------------------------------------------------ +IMPL_LINK(FmXFormView, OnDelayedErrorMessage, void*, /*EMPTYTAG*/) +{ + m_nErrorMessageEvent = 0; + displayException( m_aAsyncError ); + return 0L; +} + +//------------------------------------------------------------------------------ +void FmXFormView::onFirstViewActivation( const FmFormModel* _pDocModel ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::onFirstViewActivation" ); + if ( _pDocModel && _pDocModel->GetAutoControlFocus() ) + m_nAutoFocusEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnAutoFocus ) ); +} + +//------------------------------------------------------------------------------ +void FmXFormView::suspendTabOrderUpdate() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::suspendTabOrderUpdate" ); + OSL_ENSURE( !m_isTabOrderUpdateSuspended, "FmXFormView::suspendTabOrderUpdate: nesting not allowed!" ); + m_isTabOrderUpdateSuspended = true; +} + +//------------------------------------------------------------------------------ +void FmXFormView::resumeTabOrderUpdate() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::resumeTabOrderUpdate" ); + OSL_ENSURE( m_isTabOrderUpdateSuspended, "FmXFormView::resumeTabOrderUpdate: not suspended!" ); + m_isTabOrderUpdateSuspended = false; + + // update the tab orders for all components which were collected since the suspendTabOrderUpdate call. + for ( MapControlContainerToSetOfForms::const_iterator container = m_aNeedTabOrderUpdate.begin(); + container != m_aNeedTabOrderUpdate.end(); + ++container + ) + { + FmWinRecList::iterator pos = findWindow( container->first ); + if ( pos == m_aWinList.end() ) + continue; + + for ( SetOfForms::const_iterator form = container->second.begin(); + form != container->second.end(); + ++form + ) + { + (*pos)->updateTabOrder( *form ); + } + } + m_aNeedTabOrderUpdate.clear(); +} + +//------------------------------------------------------------------------------ +IMPL_LINK(FmXFormView, OnActivate, void*, /*EMPTYTAG*/) +{ + m_nActivationEvent = 0; + + if ( !m_pView ) + { + DBG_ERROR( "FmXFormView::OnActivate: well .... seems we have a timing problem (the view already died)!" ); + return 0; + } + + // setting the controller to activate + if (m_pView->GetFormShell() && m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW) + { + Window* pWindow = const_cast<Window*>(static_cast<const Window*>(m_pView->GetActualOutDev())); + FmXPageViewWinRec* pFmRec = m_aWinList.size() ? m_aWinList[0] : NULL; + for (FmWinRecList::const_iterator i = m_aWinList.begin(); + i != m_aWinList.end(); ++i) + { + if (pWindow == (*i)->getWindow()) + pFmRec =*i; + } + + if (pFmRec) + { + for (::std::vector< Reference< XFormController > >::const_iterator i = pFmRec->GetList().begin(); + i != pFmRec->GetList().end(); i++) + { + const Reference< XFormController > & xController = *i; + if (xController.is()) + { + // Nur bei Datenbankformularen erfolgt eine aktivierung + Reference< XRowSet > xForm(xController->getModel(), UNO_QUERY); + if (xForm.is() && OStaticDataAccessTools().getRowSetConnection(xForm).is()) + { + Reference< XPropertySet > xFormSet(xForm, UNO_QUERY); + if (xFormSet.is()) + { + // wenn es eine Datenquelle gibt, dann als aktive ::com::sun::star::form setzen + ::rtl::OUString aSource = ::comphelper::getString(xFormSet->getPropertyValue(FM_PROP_COMMAND)); + if (aSource.getLength()) + { + // benachrichtigung der Shell + FmXFormShell* pShImpl = m_pView->GetFormShell()->GetImpl(); + if (pShImpl) + pShImpl->setActiveController(xController); + break; + } + } + } + } + } + } + } + return 0; +} + +//------------------------------------------------------------------------------ +void FmXFormView::Activate(sal_Bool bSync) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::Activate" ); + if (m_nActivationEvent) + { + Application::RemoveUserEvent(m_nActivationEvent); + m_nActivationEvent = 0; + } + + if (bSync) + { + LINK(this,FmXFormView,OnActivate).Call(NULL); + } + else + m_nActivationEvent = Application::PostUserEvent(LINK(this,FmXFormView,OnActivate)); +} + +//------------------------------------------------------------------------------ +void FmXFormView::Deactivate(BOOL bDeactivateController) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::Deactivate" ); + if (m_nActivationEvent) + { + Application::RemoveUserEvent(m_nActivationEvent); + m_nActivationEvent = 0; + } + + FmXFormShell* pShImpl = m_pView->GetFormShell() ? m_pView->GetFormShell()->GetImpl() : NULL; + if (pShImpl && bDeactivateController) + pShImpl->setActiveController( NULL ); +} + +//------------------------------------------------------------------------------ +FmFormShell* FmXFormView::GetFormShell() const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::GetFormShell" ); + return m_pView ? m_pView->GetFormShell() : NULL; +} +// ----------------------------------------------------------------------------- +void FmXFormView::AutoFocus( sal_Bool _bSync ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::AutoFocus" ); + if (m_nAutoFocusEvent) + Application::RemoveUserEvent(m_nAutoFocusEvent); + + if ( _bSync ) + OnAutoFocus( NULL ); + else + m_nAutoFocusEvent = Application::PostUserEvent(LINK(this, FmXFormView, OnAutoFocus)); +} + +// ----------------------------------------------------------------------------- +bool FmXFormView::isFocusable( const Reference< XControl >& i_rControl ) +{ + if ( !i_rControl.is() ) + return false; + + try + { + Reference< XPropertySet > xModelProps( i_rControl->getModel(), UNO_QUERY_THROW ); + + // only enabled controls are allowed to participate + sal_Bool bEnabled = sal_False; + OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_ENABLED ) >>= bEnabled ); + if ( !bEnabled ) + return false; + + // check the class id of the control model + sal_Int16 nClassId = FormComponentType::CONTROL; + OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId ); + + // controls which are not focussable + if ( ( FormComponentType::CONTROL != nClassId ) + && ( FormComponentType::IMAGEBUTTON != nClassId ) + && ( FormComponentType::GROUPBOX != nClassId ) + && ( FormComponentType::FIXEDTEXT != nClassId ) + && ( FormComponentType::HIDDENCONTROL != nClassId ) + && ( FormComponentType::IMAGECONTROL != nClassId ) + && ( FormComponentType::SCROLLBAR != nClassId ) + && ( FormComponentType::SPINBUTTON!= nClassId ) + ) + { + return true; + } + } + catch( const Exception& e ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return false; +} + +// ----------------------------------------------------------------------------- +static Reference< XControl > lcl_firstFocussableControl( const Sequence< Reference< XControl > >& _rControls ) +{ + Reference< XControl > xReturn; + + // loop through all the controls + const Reference< XControl >* pControls = _rControls.getConstArray(); + const Reference< XControl >* pControlsEnd = _rControls.getConstArray() + _rControls.getLength(); + for ( ; pControls != pControlsEnd; ++pControls ) + { + if ( !pControls->is() ) + continue; + + if ( FmXFormView::isFocusable( *pControls ) ) + { + xReturn = *pControls; + break; + } + } + + if ( !xReturn.is() && _rControls.getLength() ) + xReturn = _rControls[0]; + + return xReturn; +} + +// ----------------------------------------------------------------------------- +namespace +{ + // ......................................................................... + void lcl_ensureControlsOfFormExist_nothrow( const SdrPage& _rPage, const SdrView& _rView, const Window& _rWindow, const Reference< XForm >& _rxForm ) + { + try + { + Reference< XInterface > xNormalizedForm( _rxForm, UNO_QUERY_THROW ); + + SdrObjListIter aSdrObjectLoop( _rPage, IM_DEEPNOGROUPS ); + while ( aSdrObjectLoop.IsMore() ) + { + FmFormObj* pFormObject = FmFormObj::GetFormObject( aSdrObjectLoop.Next() ); + if ( !pFormObject ) + continue; + + Reference< XChild > xModel( pFormObject->GetUnoControlModel(), UNO_QUERY_THROW ); + Reference< XInterface > xModelParent( xModel->getParent(), UNO_QUERY_THROW ); + + if ( xNormalizedForm.get() != xModelParent.get() ) + continue; + + pFormObject->GetUnoControl( _rView, _rWindow ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } +} + +// ----------------------------------------------------------------------------- +Reference< XFormController > FmXFormView::getFormController( const Reference< XForm >& _rxForm, const OutputDevice& _rDevice ) const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::getFormController" ); + Reference< XFormController > xController; + + for ( FmWinRecList::const_iterator rec = m_aWinList.begin(); rec != m_aWinList.end(); ++rec ) + { + const FmXPageViewWinRec* pViewWinRec( *rec ); + OSL_ENSURE( pViewWinRec, "FmXFormView::getFormController: invalid PageViewWinRec!" ); + if ( !pViewWinRec || ( pViewWinRec->getWindow() != &_rDevice ) ) + // wrong device + continue; + + xController = pViewWinRec->getController( _rxForm ); + if ( xController.is() ) + break; + } + return xController; +} + +// ----------------------------------------------------------------------------- +IMPL_LINK(FmXFormView, OnAutoFocus, void*, /*EMPTYTAG*/) +{ + m_nAutoFocusEvent = 0; + + // go to the first form of our page, examine it's TabController, go to it's first (in terms of the tab order) + // control, give it the focus + + do + { + + // get the forms collection of the page we belong to + FmFormPage* pPage = m_pView ? PTR_CAST( FmFormPage, m_pView->GetSdrPageView()->GetPage() ) : NULL; + Reference< XIndexAccess > xForms( pPage ? Reference< XIndexAccess >( pPage->GetForms(), UNO_QUERY ) : Reference< XIndexAccess >() ); + + const FmXPageViewWinRec* pViewWinRec = m_aWinList.size() ? m_aWinList[0] : NULL; + const Window* pWindow = pViewWinRec ? pViewWinRec->getWindow() : NULL; + + OSL_ENSURE( xForms.is() && pWindow, "FmXFormView::OnAutoFocus: could not collect all essentials!" ); + if ( !xForms.is() || !pWindow ) + return 0L; + + try + { + // go for the tab controller of the first form + if ( !xForms->getCount() ) + break; + Reference< XForm > xForm( xForms->getByIndex( 0 ), UNO_QUERY_THROW ); + Reference< XTabController > xTabController( pViewWinRec->getController( xForm ), UNO_QUERY_THROW ); + + // go for the first control of the controller + Sequence< Reference< XControl > > aControls( xTabController->getControls() ); + if ( aControls.getLength() == 0 ) + { + Reference< XElementAccess > xFormElementAccess( xForm, UNO_QUERY_THROW ); + if ( xFormElementAccess->hasElements() ) + { + // there are control models in the form, but no controls, yet. + // Well, since some time controls are created on demand only. In particular, + // they're normally created when they're first painted. + // Unfortunately, the FormController does not have any way to + // trigger the creation itself, so we must hack this ... + lcl_ensureControlsOfFormExist_nothrow( *pPage, *m_pView, *pWindow, xForm ); + aControls = xTabController->getControls(); + OSL_ENSURE( aControls.getLength(), "FmXFormView::OnAutoFocus: no controls at all!" ); + } + } + + // set the focus to this first control + Reference< XWindow > xControlWindow( lcl_firstFocussableControl( aControls ), UNO_QUERY ); + if ( !xControlWindow.is() ) + break; + + xControlWindow->setFocus(); + + // ensure that the control is visible + // 80210 - 12/07/00 - FS + const Window* pCurrentWindow = dynamic_cast< const Window* >( m_pView->GetActualOutDev() ); + if ( pCurrentWindow ) + { + awt::Rectangle aRect = xControlWindow->getPosSize(); + ::Rectangle aNonUnoRect( aRect.X, aRect.Y, aRect.X + aRect.Width, aRect.Y + aRect.Height ); + m_pView->MakeVisible( pCurrentWindow->PixelToLogic( aNonUnoRect ), *const_cast< Window* >( pCurrentWindow ) ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + } // do + while ( false ); + + return 1L; +} + +// ----------------------------------------------------------------------------- +void FmXFormView::onCreatedFormObject( FmFormObj& _rFormObject ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::onCreatedFormObject" ); + FmFormShell* pShell = m_pView ? m_pView->GetFormShell() : NULL; + FmXFormShell* pShellImpl = pShell ? pShell->GetImpl() : NULL; + OSL_ENSURE( pShellImpl, "FmXFormView::onCreatedFormObject: no form shell!" ); + if ( !pShellImpl ) + return; + + // it is valid that the form shell's forms collection is not initialized, yet + pShellImpl->UpdateForms( sal_True ); + + m_xLastCreatedControlModel.set( _rFormObject.GetUnoControlModel(), UNO_QUERY ); + if ( !m_xLastCreatedControlModel.is() ) + return; + + // some initial property defaults + FormControlFactory aControlFactory( m_aContext ); + aControlFactory.initializeControlModel( pShellImpl->getDocumentType(), _rFormObject ); + + if ( !pShellImpl->GetWizardUsing() ) + return; + + // #i31958# don't call wizards in XForms mode + if ( pShellImpl->isEnhancedForm() ) + return; + + // #i46898# no wizards if there is no Base installed - currently, all wizards are + // database related + if ( !SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::E_SDATABASE ) ) + return; + + if ( m_nControlWizardEvent ) + Application::RemoveUserEvent( m_nControlWizardEvent ); + m_nControlWizardEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnStartControlWizard ) ); +} + +// ----------------------------------------------------------------------------- +IMPL_LINK( FmXFormView, OnStartControlWizard, void*, /**/ ) +{ + m_nControlWizardEvent = 0; + OSL_PRECOND( m_xLastCreatedControlModel.is(), "FmXFormView::OnStartControlWizard: illegal call!" ); + if ( !m_xLastCreatedControlModel.is() ) + return 0L; + + sal_Int16 nClassId = FormComponentType::CONTROL; + try + { + OSL_VERIFY( m_xLastCreatedControlModel->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + const sal_Char* pWizardAsciiName = NULL; + switch ( nClassId ) + { + case FormComponentType::GRIDCONTROL: + pWizardAsciiName = "com.sun.star.sdb.GridControlAutoPilot"; + break; + case FormComponentType::LISTBOX: + case FormComponentType::COMBOBOX: + pWizardAsciiName = "com.sun.star.sdb.ListComboBoxAutoPilot"; + break; + case FormComponentType::GROUPBOX: + pWizardAsciiName = "com.sun.star.sdb.GroupBoxAutoPilot"; + break; + } + + if ( pWizardAsciiName ) + { + // build the argument list + ::comphelper::NamedValueCollection aWizardArgs; + aWizardArgs.put( "ObjectModel", m_xLastCreatedControlModel ); + + // create the wizard object + Reference< XExecutableDialog > xWizard; + try + { + m_aContext.createComponentWithArguments( pWizardAsciiName, aWizardArgs.getWrappedPropertyValues(), xWizard ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + if ( !xWizard.is() ) + { + ShowServiceNotAvailableError( NULL, String::CreateFromAscii( pWizardAsciiName ), sal_True ); + } + else + { + // execute the wizard + try + { + xWizard->execute(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + } + + m_xLastCreatedControlModel.clear(); + return 1L; +} + +// ----------------------------------------------------------------------------- +namespace +{ + void lcl_insertIntoFormComponentHierarchy_throw( const FmFormView& _rView, const SdrUnoObj& _rSdrObj, + const Reference< XDataSource >& _rxDataSource = NULL, const ::rtl::OUString& _rDataSourceName = ::rtl::OUString(), + const ::rtl::OUString& _rCommand = ::rtl::OUString(), const sal_Int32 _nCommandType = -1 ) + { + FmFormPage& rPage = static_cast< FmFormPage& >( *_rView.GetSdrPageView()->GetPage() ); + + Reference< XFormComponent > xFormComponent( _rSdrObj.GetUnoControlModel(), UNO_QUERY_THROW ); + Reference< XForm > xTargetForm( + rPage.GetImpl().findPlaceInFormComponentHierarchy( xFormComponent, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType ), + UNO_SET_THROW ); + + rPage.GetImpl().setUniqueName( xFormComponent, xTargetForm ); + + Reference< XIndexContainer > xFormAsContainer( xTargetForm, UNO_QUERY_THROW ); + xFormAsContainer->insertByIndex( xFormAsContainer->getCount(), makeAny( xFormComponent ) ); + } +} + +// ----------------------------------------------------------------------------- +SdrObject* FmXFormView::implCreateFieldControl( const ::svx::ODataAccessDescriptor& _rColumnDescriptor ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::implCreateFieldControl" ); + // not if we're in design mode + if ( !m_pView->IsDesignMode() ) + return NULL; + + ::rtl::OUString sCommand, sFieldName; + sal_Int32 nCommandType = CommandType::COMMAND; + SharedConnection xConnection; + + ::rtl::OUString sDataSource = _rColumnDescriptor.getDataSource(); + _rColumnDescriptor[ daCommand ] >>= sCommand; + _rColumnDescriptor[ daColumnName ] >>= sFieldName; + _rColumnDescriptor[ daCommandType ] >>= nCommandType; + { + Reference< XConnection > xExternalConnection; + _rColumnDescriptor[ daConnection ] >>= xExternalConnection; + xConnection.reset( xExternalConnection, SharedConnection::NoTakeOwnership ); + } + + if ( !sCommand.getLength() + || !sFieldName.getLength() + || ( !sDataSource.getLength() + && !xConnection.is() + ) + ) + { + DBG_ERROR( "FmXFormView::implCreateFieldControl: nonsense!" ); + } + + Reference< XDataSource > xDataSource; + SQLErrorEvent aError; + try + { + if ( xConnection.is() && !xDataSource.is() && !sDataSource.getLength() ) + { + Reference< XChild > xChild( xConnection, UNO_QUERY ); + if ( xChild.is() ) + xDataSource = xDataSource.query( xChild->getParent() ); + } + + // obtain the data source + if ( !xDataSource.is() ) + xDataSource = OStaticDataAccessTools().getDataSource( sDataSource, m_aContext.getLegacyServiceFactory() ); + + // and the connection, if necessary + if ( !xConnection.is() ) + xConnection.reset( OStaticDataAccessTools().getConnection_withFeedback( + sDataSource, + ::rtl::OUString(), + ::rtl::OUString(), + m_aContext.getLegacyServiceFactory() + ) ); + } + catch ( const SQLException& ) + { + aError.Reason = ::cppu::getCaughtException(); + } + catch( const Exception& ) { /* will be asserted below */ } + if (aError.Reason.hasValue()) + { + displayAsyncErrorMessage( aError ); + return NULL; + } + + // need a data source and a connection here + if (!xDataSource.is() || !xConnection.is()) + { + DBG_ERROR("FmXFormView::implCreateFieldControl : could not retrieve the data source or the connection!"); + return NULL; + } + + OStaticDataAccessTools aDBATools; + Reference< XComponent > xKeepFieldsAlive; + // go + try + { + // determine the table/query field which we should create a control for + Reference< XPropertySet > xField; + + Reference< XNameAccess > xFields = aDBATools.getFieldsByCommandDescriptor( + xConnection, nCommandType, sCommand, xKeepFieldsAlive ); + + if (xFields.is() && xFields->hasByName(sFieldName)) + xFields->getByName(sFieldName) >>= xField; + if ( !xField.is() ) + return NULL; + + Reference< XNumberFormatsSupplier > xSupplier( aDBATools.getNumberFormats( xConnection, sal_False ), UNO_SET_THROW ); + Reference< XNumberFormats > xNumberFormats( xSupplier->getNumberFormats(), UNO_SET_THROW ); + + ::rtl::OUString sLabelPostfix; + + //////////////////////////////////////////////////////////////// + // nur fuer Textgroesse + OutputDevice* pOutDev = NULL; + if (m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW) + pOutDev = const_cast<OutputDevice*>(m_pView->GetActualOutDev()); + else + {// OutDev suchen + SdrPageView* pPageView = m_pView->GetSdrPageView(); + if( pPageView && !pOutDev ) + { + // const SdrPageViewWinList& rWinList = pPageView->GetWinList(); + // const SdrPageViewWindows& rPageViewWindows = pPageView->GetPageViewWindows(); + + for( sal_uInt32 i = 0L; i < pPageView->PageWindowCount(); i++ ) + { + const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i); + + if( rPageWindow.GetPaintWindow().OutputToWindow()) + { + pOutDev = &rPageWindow.GetPaintWindow().GetOutputDevice(); + break; + } + } + } + } + + if ( !pOutDev ) + return NULL; + + sal_Int32 nDataType = ::comphelper::getINT32(xField->getPropertyValue(FM_PROP_FIELDTYPE)); + if ((DataType::BINARY == nDataType) || (DataType::VARBINARY == nDataType)) + return NULL; + + ////////////////////////////////////////////////////////////////////// + // determine the control type by examining the data type of the bound column + sal_uInt16 nOBJID = 0; + sal_Bool bDateNTimeField = sal_False; + + sal_Bool bIsCurrency = sal_False; + if (::comphelper::hasProperty(FM_PROP_ISCURRENCY, xField)) + bIsCurrency = ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_ISCURRENCY)); + + if (bIsCurrency) + nOBJID = OBJ_FM_CURRENCYFIELD; + else + switch (nDataType) + { + case DataType::BLOB: + case DataType::LONGVARBINARY: + nOBJID = OBJ_FM_IMAGECONTROL; + break; + case DataType::LONGVARCHAR: + case DataType::CLOB: + nOBJID = OBJ_FM_EDIT; + break; + case DataType::BINARY: + case DataType::VARBINARY: + return NULL; + case DataType::BIT: + case DataType::BOOLEAN: + nOBJID = OBJ_FM_CHECKBOX; + break; + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + nOBJID = OBJ_FM_NUMERICFIELD; + break; + case DataType::REAL: + case DataType::DOUBLE: + case DataType::NUMERIC: + case DataType::DECIMAL: + nOBJID = OBJ_FM_FORMATTEDFIELD; + break; + case DataType::TIMESTAMP: + bDateNTimeField = sal_True; + sLabelPostfix = String( SVX_RES( RID_STR_POSTFIX_DATE ) ); + // DON'T break ! + case DataType::DATE: + nOBJID = OBJ_FM_DATEFIELD; + break; + case DataType::TIME: + nOBJID = OBJ_FM_TIMEFIELD; + break; + case DataType::CHAR: + case DataType::VARCHAR: + default: + nOBJID = OBJ_FM_EDIT; + break; + } + if (!nOBJID) + return NULL; + + SdrUnoObj* pLabel( NULL ); + SdrUnoObj* pControl( NULL ); + if ( !createControlLabelPair( *pOutDev, 0, 0, xField, xNumberFormats, nOBJID, sLabelPostfix, + pLabel, pControl, xDataSource, sDataSource, sCommand, nCommandType ) + ) + { + return NULL; + } + + ////////////////////////////////////////////////////////////////////// + // group objects + bool bCheckbox = ( OBJ_FM_CHECKBOX == nOBJID ); + OSL_ENSURE( !bCheckbox || !pLabel, "FmXFormView::implCreateFieldControl: why was there a label created for a check box?" ); + if ( bCheckbox ) + return pControl; + + SdrObjGroup* pGroup = new SdrObjGroup(); + SdrObjList* pObjList = pGroup->GetSubList(); + pObjList->InsertObject( pLabel ); + pObjList->InsertObject( pControl ); + + if ( bDateNTimeField ) + { // so far we created a date field only, but we also need a time field + pLabel = pControl = NULL; + if ( createControlLabelPair( *pOutDev, 0, 1000, xField, xNumberFormats, OBJ_FM_TIMEFIELD, + String( SVX_RES( RID_STR_POSTFIX_TIME ) ), pLabel, pControl, + xDataSource, sDataSource, sCommand, nCommandType ) + ) + { + pObjList->InsertObject( pLabel ); + pObjList->InsertObject( pControl ); + } + } + + return pGroup; // und fertig + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + + + return NULL; +} + +// ----------------------------------------------------------------------------- +SdrObject* FmXFormView::implCreateXFormsControl( const ::svx::OXFormsDescriptor &_rDesc ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::implCreateXFormsControl" ); + // not if we're in design mode + if ( !m_pView->IsDesignMode() ) + return NULL; + + Reference< XComponent > xKeepFieldsAlive; + + // go + try + { + // determine the table/query field which we should create a control for + Reference< XNumberFormats > xNumberFormats; + ::rtl::OUString sLabelPostfix = _rDesc.szName; + + //////////////////////////////////////////////////////////////// + // nur fuer Textgroesse + OutputDevice* pOutDev = NULL; + if (m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW) + pOutDev = const_cast<OutputDevice*>(m_pView->GetActualOutDev()); + else + {// OutDev suchen + SdrPageView* pPageView = m_pView->GetSdrPageView(); + if( pPageView && !pOutDev ) + { + // const SdrPageViewWinList& rWinList = pPageView->GetWinList(); + // const SdrPageViewWindows& rPageViewWindows = pPageView->GetPageViewWindows(); + + for( sal_uInt32 i = 0L; i < pPageView->PageWindowCount(); i++ ) + { + const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i); + + if( rPageWindow.GetPaintWindow().GetOutputDevice().GetOutDevType() == OUTDEV_WINDOW) + { + pOutDev = &rPageWindow.GetPaintWindow().GetOutputDevice(); + break; + } + } + } + } + + if ( !pOutDev ) + return NULL; + + ////////////////////////////////////////////////////////////////////// + // The service name decides which control should be created + sal_uInt16 nOBJID = OBJ_FM_EDIT; + if(::rtl::OUString(_rDesc.szServiceName).equals((::rtl::OUString)FM_SUN_COMPONENT_NUMERICFIELD)) + nOBJID = OBJ_FM_NUMERICFIELD; + if(::rtl::OUString(_rDesc.szServiceName).equals((::rtl::OUString)FM_SUN_COMPONENT_CHECKBOX)) + nOBJID = OBJ_FM_CHECKBOX; + if(::rtl::OUString(_rDesc.szServiceName).equals((::rtl::OUString)FM_COMPONENT_COMMANDBUTTON)) + nOBJID = OBJ_FM_BUTTON; + + typedef ::com::sun::star::form::submission::XSubmission XSubmission_t; + Reference< XSubmission_t > xSubmission(_rDesc.xPropSet, UNO_QUERY); + + // xform control or submission button? + if ( !xSubmission.is() ) + { + SdrUnoObj* pLabel( NULL ); + SdrUnoObj* pControl( NULL ); + if ( !createControlLabelPair( *pOutDev, 0, 0, NULL, xNumberFormats, nOBJID, sLabelPostfix, + pLabel, pControl ) + ) + { + return NULL; + } + + ////////////////////////////////////////////////////////////////////// + // Now build the connection between the control and the data item. + Reference< XValueBinding > xValueBinding(_rDesc.xPropSet,UNO_QUERY); + Reference< XBindableValue > xBindableValue(pControl->GetUnoControlModel(),UNO_QUERY); + + DBG_ASSERT( xBindableValue.is(), "FmXFormView::implCreateXFormsControl: control's not bindable!" ); + if ( xBindableValue.is() ) + xBindableValue->setValueBinding(xValueBinding); + + bool bCheckbox = ( OBJ_FM_CHECKBOX == nOBJID ); + OSL_ENSURE( !bCheckbox || !pLabel, "FmXFormView::implCreateXFormsControl: why was there a label created for a check box?" ); + if ( bCheckbox ) + return pControl; + + ////////////////////////////////////////////////////////////////////// + // group objects + SdrObjGroup* pGroup = new SdrObjGroup(); + SdrObjList* pObjList = pGroup->GetSubList(); + pObjList->InsertObject(pLabel); + pObjList->InsertObject(pControl); + + return pGroup; + } + else { + + // create a button control + const MapMode eTargetMode( pOutDev->GetMapMode() ); + const MapMode eSourceMode(MAP_100TH_MM); + const sal_uInt16 nObjID = OBJ_FM_BUTTON; + ::Size controlSize(4000, 500); + FmFormObj *pControl = static_cast<FmFormObj*>(SdrObjFactory::MakeNewObject( FmFormInventor, nObjID, NULL, NULL )); + controlSize.Width() = Fraction(controlSize.Width(), 1) * eTargetMode.GetScaleX(); + controlSize.Height() = Fraction(controlSize.Height(), 1) * eTargetMode.GetScaleY(); + ::Point controlPos( pOutDev->LogicToLogic( ::Point( controlSize.Width(), 0 ), eSourceMode, eTargetMode ) ); + ::Rectangle controlRect( controlPos, pOutDev->LogicToLogic( controlSize, eSourceMode, eTargetMode ) ); + pControl->SetLogicRect(controlRect); + + // set the button label + Reference< XPropertySet > xControlSet(pControl->GetUnoControlModel(), UNO_QUERY); + xControlSet->setPropertyValue(FM_PROP_LABEL, makeAny(::rtl::OUString(_rDesc.szName))); + + // connect the submission with the submission supplier (aka the button) + xControlSet->setPropertyValue( FM_PROP_BUTTON_TYPE, + makeAny( FormButtonType_SUBMIT ) ); + typedef ::com::sun::star::form::submission::XSubmissionSupplier XSubmissionSupplier_t; + Reference< XSubmissionSupplier_t > xSubmissionSupplier(pControl->GetUnoControlModel(), UNO_QUERY); + xSubmissionSupplier->setSubmission(xSubmission); + + return pControl; + } + } + catch(const Exception&) + { + DBG_ERROR("FmXFormView::implCreateXFormsControl: caught an exception while creating the control !"); + } + + + return NULL; +} + +//------------------------------------------------------------------------ +bool FmXFormView::createControlLabelPair( OutputDevice& _rOutDev, sal_Int32 _nXOffsetMM, sal_Int32 _nYOffsetMM, + const Reference< XPropertySet >& _rxField, const Reference< XNumberFormats >& _rxNumberFormats, + sal_uInt16 _nControlObjectID, const ::rtl::OUString& _rFieldPostfix, + SdrUnoObj*& _rpLabel, SdrUnoObj*& _rpControl, + const Reference< XDataSource >& _rxDataSource, const ::rtl::OUString& _rDataSourceName, + const ::rtl::OUString& _rCommand, const sal_Int32 _nCommandType ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::createControlLabelPair" ); + if ( !createControlLabelPair( m_aContext, _rOutDev, _nXOffsetMM, _nYOffsetMM, + _rxField, _rxNumberFormats, _nControlObjectID, _rFieldPostfix, FmFormInventor, OBJ_FM_FIXEDTEXT, + NULL, NULL, NULL, _rpLabel, _rpControl ) + ) + return false; + + // insert the control model(s) into the form component hierachy + if ( _rpLabel ) + lcl_insertIntoFormComponentHierarchy_throw( *m_pView, *_rpLabel, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType ); + lcl_insertIntoFormComponentHierarchy_throw( *m_pView, *_rpControl, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType ); + + // some context-dependent initializations + FormControlFactory aControlFactory( m_aContext ); + if ( _rpLabel ) + aControlFactory.initializeControlModel( impl_getDocumentType(), *_rpLabel ); + aControlFactory.initializeControlModel( impl_getDocumentType(), *_rpControl ); + + return true; +} + +//------------------------------------------------------------------------ +bool FmXFormView::createControlLabelPair( const ::comphelper::ComponentContext& _rContext, + OutputDevice& _rOutDev, sal_Int32 _nXOffsetMM, sal_Int32 _nYOffsetMM, const Reference< XPropertySet >& _rxField, + const Reference< XNumberFormats >& _rxNumberFormats, sal_uInt16 _nControlObjectID, + const ::rtl::OUString& _rFieldPostfix, UINT32 _nInventor, UINT16 _nLabelObjectID, + SdrPage* _pLabelPage, SdrPage* _pControlPage, SdrModel* _pModel, SdrUnoObj*& _rpLabel, SdrUnoObj*& _rpControl) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::createControlLabelPair" ); + sal_Int32 nDataType = 0; + ::rtl::OUString sFieldName; + Any aFieldName; + if ( _rxField.is() ) + { + nDataType = ::comphelper::getINT32(_rxField->getPropertyValue(FM_PROP_FIELDTYPE)); + aFieldName = Any(_rxField->getPropertyValue(FM_PROP_NAME)); + aFieldName >>= sFieldName; + } + + // calculate the positions, respecting the settings of the target device + ::Size aTextSize( _rOutDev.GetTextWidth(sFieldName + _rFieldPostfix), _rOutDev.GetTextHeight() ); + + MapMode eTargetMode( _rOutDev.GetMapMode() ), + eSourceMode( MAP_100TH_MM ); + + // Textbreite ist mindestens 4cm + // Texthoehe immer halber cm + ::Size aDefTxtSize(4000, 500); + ::Size aDefSize(4000, 500); + ::Size aDefImageSize(4000, 4000); + + ::Size aRealSize = _rOutDev.LogicToLogic(aTextSize, eTargetMode, eSourceMode); + aRealSize.Width() = std::max(aRealSize.Width(), aDefTxtSize.Width()); + aRealSize.Height()= aDefSize.Height(); + + // adjust to scaling of the target device (#53523#) + aRealSize.Width() = long(Fraction(aRealSize.Width(), 1) * eTargetMode.GetScaleX()); + aRealSize.Height() = long(Fraction(aRealSize.Height(), 1) * eTargetMode.GetScaleY()); + + // for boolean fields, we do not create a label, but just a checkbox + bool bNeedLabel = ( _nControlObjectID != OBJ_FM_CHECKBOX ); + + // the label + ::std::auto_ptr< SdrUnoObj > pLabel; + Reference< XPropertySet > xLabelModel; + if ( bNeedLabel ) + { + pLabel.reset( dynamic_cast< SdrUnoObj* >( + SdrObjFactory::MakeNewObject( _nInventor, _nLabelObjectID, _pLabelPage, _pModel ) ) ); + OSL_ENSURE( pLabel.get(), "FmXFormView::createControlLabelPair: could not create the label!" ); + if ( !pLabel.get() ) + return false; + + xLabelModel.set( pLabel->GetUnoControlModel(), UNO_QUERY ); + if ( xLabelModel.is() ) + { + ::rtl::OUString sLabel; + if ( _rxField.is() && _rxField->getPropertySetInfo()->hasPropertyByName(FM_PROP_LABEL) ) + _rxField->getPropertyValue(FM_PROP_LABEL) >>= sLabel; + if ( !sLabel.getLength() ) + sLabel = sFieldName; + + xLabelModel->setPropertyValue( FM_PROP_LABEL, makeAny( sLabel + _rFieldPostfix ) ); + String sObjectLabel( SVX_RES( RID_STR_OBJECT_LABEL ) ); + sObjectLabel.SearchAndReplaceAllAscii( "#object#", sFieldName ); + xLabelModel->setPropertyValue( FM_PROP_NAME, makeAny( ::rtl::OUString( sObjectLabel ) ) ); + } + + pLabel->SetLogicRect( ::Rectangle( + _rOutDev.LogicToLogic( ::Point( _nXOffsetMM, _nYOffsetMM ), eSourceMode, eTargetMode ), + _rOutDev.LogicToLogic( aRealSize, eSourceMode, eTargetMode ) + ) ); + } + + // the control + ::std::auto_ptr< SdrUnoObj > pControl( dynamic_cast< SdrUnoObj* >( + SdrObjFactory::MakeNewObject( _nInventor, _nControlObjectID, _pControlPage, _pModel ) ) ); + OSL_ENSURE( pControl.get(), "FmXFormView::createControlLabelPair: could not create the control!" ); + if ( !pControl.get() ) + return false; + + Reference< XPropertySet > xControlSet( pControl->GetUnoControlModel(), UNO_QUERY ); + if ( !xControlSet.is() ) + return false; + + // size of the control + ::Size aControlSize( aDefSize ); + switch ( nDataType ) + { + case DataType::BIT: + case DataType::BOOLEAN: + aControlSize = aDefSize; + break; + case DataType::LONGVARCHAR: + case DataType::CLOB: + case DataType::LONGVARBINARY: + case DataType::BLOB: + aControlSize = aDefImageSize; + break; + } + + if ( OBJ_FM_IMAGECONTROL == _nControlObjectID ) + aControlSize = aDefImageSize; + + aControlSize.Width() = long(Fraction(aControlSize.Width(), 1) * eTargetMode.GetScaleX()); + aControlSize.Height() = long(Fraction(aControlSize.Height(), 1) * eTargetMode.GetScaleY()); + + pControl->SetLogicRect( ::Rectangle( + _rOutDev.LogicToLogic( ::Point( aRealSize.Width() + _nXOffsetMM, _nYOffsetMM ), eSourceMode, eTargetMode ), + _rOutDev.LogicToLogic( aControlSize, eSourceMode, eTargetMode ) + ) ); + + // some initializations + Reference< XPropertySetInfo > xControlPropInfo = xControlSet->getPropertySetInfo(); + + if ( aFieldName.hasValue() ) + { + xControlSet->setPropertyValue( FM_PROP_CONTROLSOURCE, aFieldName ); + xControlSet->setPropertyValue( FM_PROP_NAME, aFieldName ); + if ( !bNeedLabel ) + { + // no dedicated label control => use the label property + if ( xControlPropInfo->hasPropertyByName( FM_PROP_LABEL ) ) + xControlSet->setPropertyValue( FM_PROP_LABEL, makeAny( sFieldName + _rFieldPostfix ) ); + else + OSL_ENSURE( false, "FmXFormView::createControlLabelPair: can't set a label for the control!" ); + } + } + + if ( (nDataType == DataType::LONGVARCHAR || nDataType == DataType::CLOB) && xControlPropInfo->hasPropertyByName( FM_PROP_MULTILINE ) ) + { + xControlSet->setPropertyValue( FM_PROP_MULTILINE, makeAny( sal_Bool( sal_True ) ) ); + } + + // announce the label to the control + if ( xControlPropInfo->hasPropertyByName( FM_PROP_CONTROLLABEL ) && xLabelModel.is() ) + { + try + { + xControlSet->setPropertyValue( FM_PROP_CONTROLLABEL, makeAny( xLabelModel ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + if ( _rxField.is() ) + { + FormControlFactory aControlFactory( _rContext ); + aControlFactory.initializeFieldDependentProperties( _rxField, xControlSet, _rxNumberFormats ); + } + + _rpLabel = pLabel.release(); + _rpControl = pControl.release(); + return true; +} + +//------------------------------------------------------------------------------ +FmXFormView::ObjectRemoveListener::ObjectRemoveListener( FmXFormView* pParent ) + :m_pParent( pParent ) +{ +} + +//------------------------------------------------------------------------------ +void FmXFormView::ObjectRemoveListener::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) +{ + if (rHint.ISA(SdrHint) && (((SdrHint&)rHint).GetKind() == HINT_OBJREMOVED)) + m_pParent->ObjectRemovedInAliveMode(((SdrHint&)rHint).GetObject()); +} + +//------------------------------------------------------------------------------ +void FmXFormView::ObjectRemovedInAliveMode( const SdrObject* pObject ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::ObjectRemovedInAliveMode" ); + // wenn das entfernte Objekt in meiner MarkList, die ich mir beim Umschalten in den Alive-Mode gemerkt habe, steht, + // muss ich es jetzt da rausnehmen, da ich sonst beim Zurueckschalten versuche, die Markierung wieder zu setzen + // (interesanterweise geht das nur bei gruppierten Objekten schief (beim Zugriff auf deren ObjList GPF), nicht bei einzelnen) + + ULONG nCount = m_aMark.GetMarkCount(); + for (ULONG i = 0; i < nCount; ++i) + { + SdrMark* pMark = m_aMark.GetMark(i); + SdrObject* pCurrent = pMark->GetMarkedSdrObj(); + if (pObject == pCurrent) + { + m_aMark.DeleteMark(i); + return; + } + // ich brauche nicht in GroupObjects absteigen : wenn dort unten ein Objekt geloescht wird, dann bleibt der + // Zeiger auf das GroupObject, den ich habe, trotzdem weiter gueltig bleibt ... + } +} + +//------------------------------------------------------------------------------ +void FmXFormView::stopMarkListWatching() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::stopMarkListWatching" ); + if ( m_pWatchStoredList ) + { + m_pWatchStoredList->EndListeningAll(); + delete m_pWatchStoredList; + m_pWatchStoredList = NULL; + } +} + +//------------------------------------------------------------------------------ +void FmXFormView::startMarkListWatching() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::startMarkListWatching" ); + if ( !m_pWatchStoredList ) + { + m_pWatchStoredList = new ObjectRemoveListener( this ); + FmFormModel* pModel = GetFormShell() ? GetFormShell()->GetFormModel() : NULL; + DBG_ASSERT( pModel != NULL, "FmXFormView::startMarkListWatching: shell has no model!" ); + m_pWatchStoredList->StartListening( *static_cast< SfxBroadcaster* >( pModel ) ); + } + else + { + DBG_ERROR( "FmXFormView::startMarkListWatching: already listening!" ); + } +} + +//------------------------------------------------------------------------------ +void FmXFormView::saveMarkList( sal_Bool _bSmartUnmark ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::saveMarkList" ); + if ( m_pView ) + { + m_aMark = m_pView->GetMarkedObjectList(); + if ( _bSmartUnmark ) + { + ULONG nCount = m_aMark.GetMarkCount( ); + for ( ULONG i = 0; i < nCount; ++i ) + { + SdrMark* pMark = m_aMark.GetMark(i); + SdrObject* pObj = pMark->GetMarkedSdrObj(); + + if ( m_pView->IsObjMarked( pObj ) ) + { + if ( pObj->IsGroupObject() ) + { + SdrObjListIter aIter( *pObj->GetSubList() ); + sal_Bool bMixed = sal_False; + while ( aIter.IsMore() && !bMixed ) + bMixed = ( aIter.Next()->GetObjInventor() != FmFormInventor ); + + if ( !bMixed ) + { + // all objects in the group are form objects + m_pView->MarkObj( pMark->GetMarkedSdrObj(), pMark->GetPageView(), sal_True /* unmark! */ ); + } + } + else + { + if ( pObj->GetObjInventor() == FmFormInventor ) + { // this is a form layer object + m_pView->MarkObj( pMark->GetMarkedSdrObj(), pMark->GetPageView(), sal_True /* unmark! */ ); + } + } + } + } + } + } + else + { + DBG_ERROR( "FmXFormView::saveMarkList: invalid view!" ); + m_aMark = SdrMarkList(); + } +} + +//-------------------------------------------------------------------------- +static sal_Bool lcl_hasObject( SdrObjListIter& rIter, SdrObject* pObj ) +{ + sal_Bool bFound = sal_False; + while (rIter.IsMore() && !bFound) + bFound = pObj == rIter.Next(); + + rIter.Reset(); + return bFound; +} + +//------------------------------------------------------------------------------ +void FmXFormView::restoreMarkList( SdrMarkList& _rRestoredMarkList ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::restoreMarkList" ); + if ( !m_pView ) + return; + + _rRestoredMarkList.Clear(); + + const SdrMarkList& rCurrentList = m_pView->GetMarkedObjectList(); + FmFormPage* pPage = GetFormShell() ? GetFormShell()->GetCurPage() : NULL; + if (pPage) + { + if (rCurrentList.GetMarkCount()) + { // there is a current mark ... hmm. Is it a subset of the mark we remembered in saveMarkList? + sal_Bool bMisMatch = sal_False; + + // loop through all current marks + ULONG nCurrentCount = rCurrentList.GetMarkCount(); + for ( ULONG i=0; i<nCurrentCount&& !bMisMatch; ++i ) + { + const SdrObject* pCurrentMarked = rCurrentList.GetMark( i )->GetMarkedSdrObj(); + + // loop through all saved marks, check for equality + sal_Bool bFound = sal_False; + ULONG nSavedCount = m_aMark.GetMarkCount(); + for ( ULONG j=0; j<nSavedCount && !bFound; ++j ) + { + if ( m_aMark.GetMark( j )->GetMarkedSdrObj() == pCurrentMarked ) + bFound = sal_True; + } + + // did not find a current mark in the saved marks + if ( !bFound ) + bMisMatch = sal_True; + } + + if ( bMisMatch ) + { + m_aMark.Clear(); + _rRestoredMarkList = rCurrentList; + return; + } + } + // wichtig ist das auf die Objecte der markliste nicht zugegriffen wird + // da diese bereits zerstoert sein koennen + SdrPageView* pCurPageView = m_pView->GetSdrPageView(); + SdrObjListIter aPageIter( *pPage ); + sal_Bool bFound = sal_True; + + // gibt es noch alle Objecte + ULONG nCount = m_aMark.GetMarkCount(); + for (ULONG i = 0; i < nCount && bFound; i++) + { + SdrMark* pMark = m_aMark.GetMark(i); + SdrObject* pObj = pMark->GetMarkedSdrObj(); + if (pObj->IsGroupObject()) + { + SdrObjListIter aIter(*pObj->GetSubList()); + while (aIter.IsMore() && bFound) + bFound = lcl_hasObject(aPageIter, aIter.Next()); + } + else + bFound = lcl_hasObject(aPageIter, pObj); + + bFound = bFound && pCurPageView == pMark->GetPageView(); + } + + if (bFound) + { + // Das LastObject auswerten + if (nCount) // Objecte jetzt Markieren + { + for (ULONG i = 0; i < nCount; i++) + { + SdrMark* pMark = m_aMark.GetMark(i); + SdrObject* pObj = pMark->GetMarkedSdrObj(); + if ( pObj->GetObjInventor() == FmFormInventor ) + if ( !m_pView->IsObjMarked( pObj ) ) + m_pView->MarkObj( pObj, pMark->GetPageView() ); + } + + _rRestoredMarkList = m_aMark; + } + } + m_aMark.Clear(); + } +} +// ----------------------------------------------------------------------------- +void SAL_CALL FmXFormView::focusGained( const FocusEvent& /*e*/ ) throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::focusGained" ); + if ( m_xWindow.is() && m_pView ) + { + m_pView->SetMoveOutside( TRUE, FmFormView::ImplAccess() ); + } +} +// ----------------------------------------------------------------------------- +void SAL_CALL FmXFormView::focusLost( const FocusEvent& /*e*/ ) throw (RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::focusLost" ); + // when switch the focus outside the office the mark didn't change + // so we can not remove us as focus listener + if ( m_xWindow.is() && m_pView ) + { + m_pView->SetMoveOutside( FALSE, FmFormView::ImplAccess() ); + } +} +// ----------------------------------------------------------------------------- +void FmXFormView::removeGridWindowListening() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::removeGridWindowListening" ); + if ( m_xWindow.is() ) + { + m_xWindow->removeFocusListener(this); + if ( m_pView ) + { + m_pView->SetMoveOutside( FALSE, FmFormView::ImplAccess() ); + } + m_xWindow = NULL; + } +} + +// ----------------------------------------------------------------------------- +DocumentType FmXFormView::impl_getDocumentType() const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormView::impl_getDocumentType" ); + if ( GetFormShell() && GetFormShell()->GetImpl() ) + return GetFormShell()->GetImpl()->getDocumentType(); + return eUnknownDocumentType; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/formcontrolfactory.cxx b/svx/source/form/formcontrolfactory.cxx new file mode 100644 index 000000000000..bb3f5c2b164f --- /dev/null +++ b/svx/source/form/formcontrolfactory.cxx @@ -0,0 +1,736 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * +************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include "svx/dbtoolsclient.hxx" +#include "formcontrolfactory.hxx" +#include "fmcontrollayout.hxx" +#include "fmprop.hrc" +#include "fmresids.hrc" +#include "fmservs.hxx" +#include "svx/dialmgr.hxx" +#include "svx/svdouno.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/form/XFormComponent.hpp> +#include <com/sun/star/form/FormComponentType.hpp> +#include <com/sun/star/awt/ScrollBarOrientation.hpp> +#include <com/sun/star/awt/MouseWheelBehavior.hpp> +#include <com/sun/star/form/XGridColumnFactory.hpp> +#include <com/sun/star/style/VerticalAlignment.hpp> +#include <com/sun/star/awt/LineEndFormat.hpp> +#include <com/sun/star/awt/ImageScaleMode.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/util/XNumberFormatTypes.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/text/WritingMode2.hpp> +#include <com/sun/star/awt/FontDescriptor.hpp> +/** === end UNO includes === **/ + +#include <comphelper/componentcontext.hxx> +#include <comphelper/numbers.hxx> +#include <unotools/syslocale.hxx> +#include <tools/gen.hxx> +#include <tools/diagnose_ex.h> + +#include <set> + +//........................................................................ +namespace svxform +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::makeAny; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Type; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::awt::XControlModel; + using ::com::sun::star::form::XFormComponent; + using ::com::sun::star::container::XIndexAccess; + using ::com::sun::star::beans::XPropertySetInfo; + using ::com::sun::star::beans::PropertyValue; + using ::com::sun::star::container::XChild; + using ::com::sun::star::form::XGridColumnFactory; + using ::com::sun::star::style::VerticalAlignment_MIDDLE; + using ::com::sun::star::beans::Property; + using ::com::sun::star::uno::TypeClass_DOUBLE; + using ::com::sun::star::uno::TypeClass_LONG; + using ::com::sun::star::util::XNumberFormats; + using ::com::sun::star::util::XNumberFormatTypes; + using ::com::sun::star::awt::FontDescriptor; + using ::com::sun::star::lang::Locale; + using ::com::sun::star::lang::XServiceInfo; + using ::com::sun::star::container::XNameAccess; + /** === end UNO using === **/ + namespace FormComponentType = ::com::sun::star::form::FormComponentType; + namespace ScrollBarOrientation = ::com::sun::star::awt::ScrollBarOrientation; + namespace MouseWheelBehavior = ::com::sun::star::awt::MouseWheelBehavior; + namespace LineEndFormat = ::com::sun::star::awt::LineEndFormat; + namespace ImageScaleMode = ::com::sun::star::awt::ImageScaleMode; + namespace DataType = ::com::sun::star::sdbc::DataType; + namespace ColumnValue = ::com::sun::star::sdbc::ColumnValue; + namespace WritingMode2 = ::com::sun::star::text::WritingMode2; + + //==================================================================== + //= FormControlFactory_Data + //==================================================================== + struct FormControlFactory_Data + { + ::comphelper::ComponentContext m_aContext; + + FormControlFactory_Data( const ::comphelper::ComponentContext& _rContext ) + :m_aContext( _rContext ) + { + } + }; + + //==================================================================== + //= FormControlFactory + //==================================================================== + //-------------------------------------------------------------------- + FormControlFactory::FormControlFactory( const ::comphelper::ComponentContext& _rContext ) + :m_pData( new FormControlFactory_Data( _rContext ) ) + { + } + + //-------------------------------------------------------------------- + FormControlFactory::~FormControlFactory() + { + } + + //-------------------------------------------------------------------- + sal_Int16 FormControlFactory::initializeControlModel( const DocumentType _eDocType, const SdrUnoObj& _rObject ) + { + return initializeControlModel( + _eDocType, + Reference< XPropertySet >( _rObject.GetUnoControlModel(), UNO_QUERY ), + _rObject.GetCurrentBoundRect() + ); + } + + //-------------------------------------------------------------------- + sal_Int16 FormControlFactory::initializeControlModel( const DocumentType _eDocType, const Reference< XPropertySet >& _rxControlModel ) + { + return initializeControlModel( + _eDocType, _rxControlModel, Rectangle() + ); + } + + // ----------------------------------------------------------------------------- + namespace + { + //.................................................................... + static ::rtl::OUString lcl_getUniqueLabel_nothrow( const Reference< XPropertySet >& _rxControlModel, const ::rtl::OUString& _rBaseLabel ) + { + ::rtl::OUString sLabel( _rBaseLabel ); + try + { + typedef ::std::set< ::rtl::OUString > StringBag; + StringBag aUsedLabels; + + Reference< XFormComponent > xFormComponent( _rxControlModel, UNO_QUERY_THROW ); + Reference< XIndexAccess > xContainer( xFormComponent->getParent(), UNO_QUERY_THROW ); + // loop through all siblings of the control model, and collect their labels + for ( sal_Int32 index=xContainer->getCount(); index>0; ) + { + Reference< XPropertySet > xElement( xContainer->getByIndex( --index ), UNO_QUERY_THROW ); + if ( xElement == _rxControlModel ) + continue; + + Reference< XPropertySetInfo > xPSI( xElement->getPropertySetInfo(), UNO_SET_THROW ); + if ( !xPSI->hasPropertyByName( FM_PROP_LABEL ) ) + continue; + + ::rtl::OUString sElementLabel; + OSL_VERIFY( xElement->getPropertyValue( FM_PROP_LABEL ) >>= sElementLabel ); + aUsedLabels.insert( sElementLabel ); + } + + // now find a free label + sal_Int32 i=2; + while ( aUsedLabels.find( sLabel ) != aUsedLabels.end() ) + { + ::rtl::OUStringBuffer aBuffer( _rBaseLabel ); + aBuffer.appendAscii( " " ); + aBuffer.append( (sal_Int32)i++ ); + sLabel = aBuffer.makeStringAndClear(); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return sLabel; + } + + //.................................................................... + static Sequence< PropertyValue > lcl_getDataSourceIndirectProperties( const Reference< XPropertySet >& _rxControlModel, + const ::comphelper::ComponentContext& _rContext ) + { + OSL_PRECOND( _rxControlModel.is(), "lcl_getDataSourceIndirectProperties: invalid model!" ); + + Sequence< PropertyValue > aInfo; + try + { + Reference< XChild > xChild( _rxControlModel, UNO_QUERY ); + Reference< XPropertySet > xForm; + if ( xChild.is() ) + xForm = xForm.query( xChild->getParent() ); + + if ( Reference< XGridColumnFactory >( xForm, UNO_QUERY ).is() ) + { // hmm. the model is a grid column, in real + xChild = xChild.query( xForm ); + xForm = xForm.query( xChild->getParent() ); + } + + OSL_ENSURE( xForm.is(), "lcl_getDataSourceIndirectProperties: could not determine the form!" ); + if ( !xForm.is() ) + return aInfo; + ::rtl::OUString sDataSourceName; + xForm->getPropertyValue( FM_PROP_DATASOURCE ) >>= sDataSourceName; + + Reference< XPropertySet > xDsProperties; + if ( sDataSourceName.getLength() ) + xDsProperties = xDsProperties.query( OStaticDataAccessTools().getDataSource( sDataSourceName, _rContext.getLegacyServiceFactory() ) ); + if ( xDsProperties.is() ) + xDsProperties->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Info" ) ) ) >>= aInfo; + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "lcl_getDataSourceIndirectProperties: caught an exception!" ); + } + return aInfo; + } + + //.................................................................... + static const sal_Char* aCharacterAndParagraphProperties[] = + { + "CharFontName", + "CharFontStyleName", + "CharFontFamily", + "CharFontCharSet", + "CharFontPitch", + "CharColor", + "CharEscapement", + "CharHeight", + "CharUnderline", + "CharWeight", + "CharPosture", + "CharAutoKerning", + "CharBackColor", + "CharBackTransparent", + "CharCaseMap", + "CharCrossedOut", + "CharFlash", + "CharStrikeout", + "CharWordMode", + "CharKerning", + "CharLocale", + "CharKeepTogether", + "CharNoLineBreak", + "CharShadowed", + "CharFontType", + "CharStyleName", + "CharContoured", + "CharCombineIsOn", + "CharCombinePrefix", + "CharCombineSuffix", + "CharEmphasize", + "CharRelief", + "RubyText", + "RubyAdjust", + "RubyCharStyleName", + "RubyIsAbove", + "CharRotation", + "CharRotationIsFitToLine", + "CharScaleWidth", + "HyperLinkURL", + "HyperLinkTarget", + "HyperLinkName", + "VisitedCharStyleName", + "UnvisitedCharStyleName", + "CharEscapementHeight", + "CharNoHyphenation", + "CharUnderlineColor", + "CharUnderlineHasColor", + "CharStyleNames", + "CharHeightAsian", + "CharWeightAsian", + "CharFontNameAsian", + "CharFontStyleNameAsian", + "CharFontFamilyAsian", + "CharFontCharSetAsian", + "CharFontPitchAsian", + "CharPostureAsian", + "CharLocaleAsian", + "ParaIsCharacterDistance", + "ParaIsForbiddenRules", + "ParaIsHangingPunctuation", + "CharHeightComplex", + "CharWeightComplex", + "CharFontNameComplex", + "CharFontStyleNameComplex", + "CharFontFamilyComplex", + "CharFontCharSetComplex", + "CharFontPitchComplex", + "CharPostureComplex", + "CharLocaleComplex", + "ParaAdjust", + "ParaLineSpacing", + "ParaBackColor", + "ParaBackTransparent", + "ParaBackGraphicURL", + "ParaBackGraphicFilter", + "ParaBackGraphicLocation", + "ParaLastLineAdjust", + "ParaExpandSingleWord", + "ParaLeftMargin", + "ParaRightMargin", + "ParaTopMargin", + "ParaBottomMargin", + "ParaLineNumberCount", + "ParaLineNumberStartValue", + "PageDescName", + "PageNumberOffset", + "ParaRegisterModeActive", + "ParaTabStops", + "ParaStyleName", + "DropCapFormat", + "DropCapWholeWord", + "ParaKeepTogether", + "Setting", + "ParaSplit", + "Setting", + "NumberingLevel", + "NumberingRules", + "NumberingStartValue", + "ParaIsNumberingRestart", + "NumberingStyleName", + "ParaOrphans", + "ParaWidows", + "ParaShadowFormat", + "LeftBorder", + "RightBorder", + "TopBorder", + "BottomBorder", + "BorderDistance", + "LeftBorderDistance", + "RightBorderDistance", + "TopBorderDistance", + "BottomBorderDistance", + "BreakType", + "DropCapCharStyleName", + "ParaFirstLineIndent", + "ParaIsAutoFirstLineIndent", + "ParaIsHyphenation", + "ParaHyphenationMaxHyphens", + "ParaHyphenationMaxLeadingChars", + "ParaHyphenationMaxTrailingChars", + "ParaVertAlignment", + "ParaUserDefinedAttributes", + "NumberingIsNumber", + "ParaIsConnectBorder", + NULL + }; + + //.................................................................... + static void lcl_initializeCharacterAttributes( const Reference< XPropertySet >& _rxModel ) + { + try + { + Reference< XPropertySet > xStyle( ControlLayouter::getDefaultDocumentTextStyle( _rxModel ), UNO_SET_THROW ); + + // transfer all properties which are described by the style + Reference< XPropertySetInfo > xSourcePropInfo( xStyle->getPropertySetInfo(), UNO_SET_THROW ); + Reference< XPropertySetInfo > xDestPropInfo( _rxModel->getPropertySetInfo(), UNO_SET_THROW ); + + ::rtl::OUString sPropertyName; + const sal_Char** pCharacterProperty = aCharacterAndParagraphProperties; + while ( *pCharacterProperty ) + { + sPropertyName = ::rtl::OUString::createFromAscii( *pCharacterProperty ); + + if ( xSourcePropInfo->hasPropertyByName( sPropertyName ) && xDestPropInfo->hasPropertyByName( sPropertyName ) ) + _rxModel->setPropertyValue( sPropertyName, xStyle->getPropertyValue( sPropertyName ) ); + + ++pCharacterProperty; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + } + + //-------------------------------------------------------------------- + sal_Int16 FormControlFactory::initializeControlModel( const DocumentType _eDocType, const Reference< XPropertySet >& _rxControlModel, + const Rectangle& _rControlBoundRect ) + { + sal_Int16 nClassId = FormComponentType::CONTROL; + + OSL_ENSURE( _rxControlModel.is(), "FormControlFactory::initializeControlModel: invalid model!" ); + if ( !_rxControlModel.is() ) + return nClassId; + + try + { + ControlLayouter::initializeControlLayout( _rxControlModel, _eDocType ); + + _rxControlModel->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId; + Reference< XPropertySetInfo > xPSI( _rxControlModel->getPropertySetInfo(), UNO_SET_THROW ); + switch ( nClassId ) + { + case FormComponentType::SCROLLBAR: + _rxControlModel->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LiveScroll" ) ), makeAny( (sal_Bool)sal_True ) ); + // NO break! + case FormComponentType::SPINBUTTON: + { + sal_Int32 eOrientation = ScrollBarOrientation::HORIZONTAL; + if ( !_rControlBoundRect.IsEmpty() && ( _rControlBoundRect.GetWidth() < _rControlBoundRect.GetHeight() ) ) + eOrientation = ScrollBarOrientation::VERTICAL; + _rxControlModel->setPropertyValue( FM_PROP_ORIENTATION, makeAny( eOrientation ) ); + } + break; + + case FormComponentType::LISTBOX: + case FormComponentType::COMBOBOX: + { + sal_Bool bDropDown = !_rControlBoundRect.IsEmpty() && ( _rControlBoundRect.GetWidth() >= 3 * _rControlBoundRect.GetHeight() ); + if ( xPSI->hasPropertyByName( FM_PROP_DROPDOWN ) ) + _rxControlModel->setPropertyValue( FM_PROP_DROPDOWN, makeAny( (sal_Bool)bDropDown ) ); + _rxControlModel->setPropertyValue( FM_PROP_LINECOUNT, makeAny( sal_Int16( 20 ) ) ); + } + break; + + case FormComponentType::TEXTFIELD: + { + initializeTextFieldLineEnds( _rxControlModel ); + lcl_initializeCharacterAttributes( _rxControlModel ); + + if ( !_rControlBoundRect.IsEmpty() + && !( _rControlBoundRect.GetWidth() > 4 * _rControlBoundRect.GetHeight() ) + ) + { + if ( xPSI->hasPropertyByName( FM_PROP_MULTILINE ) ) + _rxControlModel->setPropertyValue( FM_PROP_MULTILINE, makeAny( (sal_Bool)sal_True ) ); + } + } + break; + + case FormComponentType::RADIOBUTTON: + case FormComponentType::CHECKBOX: + case FormComponentType::FIXEDTEXT: + { + ::rtl::OUString sVertAlignPropertyName( RTL_CONSTASCII_USTRINGPARAM( "VerticalAlign" ) ); + if ( xPSI->hasPropertyByName( sVertAlignPropertyName ) ) + _rxControlModel->setPropertyValue( sVertAlignPropertyName, makeAny( VerticalAlignment_MIDDLE ) ); + } + break; + + case FormComponentType::IMAGEBUTTON: + case FormComponentType::IMAGECONTROL: + { + const ::rtl::OUString sScaleModeProperty( RTL_CONSTASCII_USTRINGPARAM( "ScaleMode" ) ); + if ( xPSI->hasPropertyByName( sScaleModeProperty ) ) + _rxControlModel->setPropertyValue( sScaleModeProperty, makeAny( ImageScaleMode::Isotropic ) ); + } + break; + } + + // initial default label for the control + if ( xPSI->hasPropertyByName( FM_PROP_LABEL ) ) + { + ::rtl::OUString sExistingLabel; + OSL_VERIFY( _rxControlModel->getPropertyValue( FM_PROP_LABEL ) >>= sExistingLabel ); + if ( !sExistingLabel.getLength() ) + { + ::rtl::OUString sInitialLabel; + OSL_VERIFY( _rxControlModel->getPropertyValue( FM_PROP_NAME ) >>= sInitialLabel ); + + sal_uInt16 nTitleResId = 0; + switch ( nClassId ) + { + case FormComponentType::COMMANDBUTTON: nTitleResId = RID_STR_PROPTITLE_PUSHBUTTON; break; + case FormComponentType::RADIOBUTTON: nTitleResId = RID_STR_PROPTITLE_RADIOBUTTON; break; + case FormComponentType::CHECKBOX: nTitleResId = RID_STR_PROPTITLE_CHECKBOX; break; + case FormComponentType::GROUPBOX: nTitleResId = RID_STR_PROPTITLE_GROUPBOX; break; + case FormComponentType::FIXEDTEXT: nTitleResId = RID_STR_PROPTITLE_FIXEDTEXT; break; + } + + if ( nTitleResId ) + sInitialLabel = String( SVX_RES( nTitleResId ) ); + + _rxControlModel->setPropertyValue( + FM_PROP_LABEL, + makeAny( lcl_getUniqueLabel_nothrow( _rxControlModel, sInitialLabel ) ) + ); + } + } + + // strict format = yes is the default (i93467) + if ( xPSI->hasPropertyByName( FM_PROP_STRICTFORMAT ) ) + { + _rxControlModel->setPropertyValue( FM_PROP_STRICTFORMAT, makeAny( sal_Bool( sal_True ) ) ); + } + + // mouse wheel: don't use it for scrolling by default (i110036) + if ( xPSI->hasPropertyByName( FM_PROP_MOUSE_WHEEL_BEHAVIOR ) ) + { + _rxControlModel->setPropertyValue( FM_PROP_MOUSE_WHEEL_BEHAVIOR, makeAny( MouseWheelBehavior::SCROLL_DISABLED ) ); + } + + if ( xPSI->hasPropertyByName( FM_PROP_WRITING_MODE ) ) + _rxControlModel->setPropertyValue( FM_PROP_WRITING_MODE, makeAny( WritingMode2::CONTEXT ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return nClassId; + } + + //------------------------------------------------------------------------------ + void FormControlFactory::initializeTextFieldLineEnds( const Reference< XPropertySet >& _rxModel ) + { + OSL_PRECOND( _rxModel.is(), "initializeTextFieldLineEnds: invalid model!" ); + if ( !_rxModel.is() ) + return; + + try + { + Reference< XPropertySetInfo > xInfo = _rxModel->getPropertySetInfo(); + if ( !xInfo.is() || !xInfo->hasPropertyByName( FM_PROP_LINEENDFORMAT ) ) + return; + + // let's see if the data source which the form belongs to (if any) + // has a setting for the preferred line end format + sal_Bool bDosLineEnds = sal_False; + Sequence< PropertyValue > aInfo = lcl_getDataSourceIndirectProperties( _rxModel, m_pData->m_aContext ); + const PropertyValue* pInfo = aInfo.getConstArray(); + const PropertyValue* pInfoEnd = pInfo + aInfo.getLength(); + for ( ; pInfo != pInfoEnd; ++pInfo ) + { + if ( pInfo->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "PreferDosLikeLineEnds" ) ) ) + { + pInfo->Value >>= bDosLineEnds; + break; + } + } + + sal_Int16 nLineEndFormat = bDosLineEnds ? LineEndFormat::CARRIAGE_RETURN_LINE_FEED : LineEndFormat::LINE_FEED; + _rxModel->setPropertyValue( FM_PROP_LINEENDFORMAT, makeAny( nLineEndFormat ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + //------------------------------------------------------------------------------ + void FormControlFactory::initializeFieldDependentProperties( const Reference< XPropertySet >& _rxDatabaseField, + const Reference< XPropertySet >& _rxControlModel, const Reference< XNumberFormats >& _rxNumberFormats ) + { + OSL_PRECOND( _rxDatabaseField.is() && _rxControlModel.is(), + "FormControlFactory::initializeFieldDependentProperties: illegal params!" ); + if ( !_rxDatabaseField.is() || !_rxControlModel.is() ) + return; + + try + { + //////////////////////////////////////////////////////////////////////// + // if the field has a numeric format, and the model has a "Scale" property, sync it + Reference< XPropertySetInfo > xFieldPSI( _rxDatabaseField->getPropertySetInfo(), UNO_SET_THROW ); + Reference< XPropertySetInfo > xModelPSI( _rxControlModel->getPropertySetInfo(), UNO_SET_THROW ); + + if ( xModelPSI->hasPropertyByName( FM_PROP_DECIMAL_ACCURACY ) ) + { + sal_Int32 nFormatKey = 0; + if ( xFieldPSI->hasPropertyByName( FM_PROP_FORMATKEY ) ) + { + _rxDatabaseField->getPropertyValue( FM_PROP_FORMATKEY ) >>= nFormatKey; + } + else + { + nFormatKey = OStaticDataAccessTools().getDefaultNumberFormat( + _rxDatabaseField, + Reference< XNumberFormatTypes >( _rxNumberFormats, UNO_QUERY ), + SvtSysLocale().GetLocaleData().getLocale() + ); + } + + Any aScaleVal( ::comphelper::getNumberFormatDecimals( _rxNumberFormats, nFormatKey ) ); + _rxControlModel->setPropertyValue( FM_PROP_DECIMAL_ACCURACY, aScaleVal ); + } + + //////////////////////////////////////////////////////////////////////// + // minimum and maximum of the control according to the type of the database field + sal_Int32 nDataType = DataType::OTHER; + OSL_VERIFY( _rxDatabaseField->getPropertyValue( FM_PROP_FIELDTYPE ) >>= nDataType ); + + if ( xModelPSI->hasPropertyByName( FM_PROP_VALUEMIN ) + && xModelPSI->hasPropertyByName( FM_PROP_VALUEMAX ) + ) + { + sal_Int32 nMinValue = -1000000000, nMaxValue = 1000000000; + switch ( nDataType ) + { + case DataType::TINYINT : nMinValue = 0; nMaxValue = 255; break; + case DataType::SMALLINT : nMinValue = -32768; nMaxValue = 32767; break; + case DataType::INTEGER : nMinValue = 0x80000000; nMaxValue = 0x7FFFFFFF; break; + // double and singles are ignored + } + + Any aValue; + + // both the minimum and the maximum value properties can be either Long or Double + Property aProperty = xModelPSI->getPropertyByName( FM_PROP_VALUEMIN ); + if ( aProperty.Type.getTypeClass() == TypeClass_DOUBLE ) + aValue <<= (double)nMinValue; + else if ( aProperty.Type.getTypeClass() == TypeClass_LONG ) + aValue <<= (sal_Int32)nMinValue; + else + { + DBG_ERROR( "FormControlFactory::initializeFieldDependentProperties: unexpected property type (MinValue)!" ); + } + _rxControlModel->setPropertyValue( FM_PROP_VALUEMIN, aValue ); + + // both the minimum and the maximum value properties can be either Long or Double + aProperty = xModelPSI->getPropertyByName( FM_PROP_VALUEMAX ); + if ( aProperty.Type.getTypeClass() == TypeClass_DOUBLE ) + aValue <<= (double)nMaxValue; + else if ( aProperty.Type.getTypeClass() == TypeClass_LONG ) + aValue <<= (sal_Int32)nMaxValue; + else + { + DBG_ERROR( "FormControlFactory::initializeFieldDependentProperties: unexpected property type (MaxValue)!" ); + } + _rxControlModel->setPropertyValue( FM_PROP_VALUEMAX, aValue ); + } + + //////////////////////////////////////////////////////////////////////// + // a check box can be tristate if and only if the column it is bound to is nullable + sal_Int16 nClassId = FormComponentType::CONTROL; + OSL_VERIFY( _rxControlModel->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId ); + if ( nClassId == FormComponentType::CHECKBOX ) + { + sal_Int32 nNullable = ColumnValue::NULLABLE_UNKNOWN; + OSL_VERIFY( _rxDatabaseField->getPropertyValue( FM_PROP_ISNULLABLE ) >>= nNullable ); + _rxControlModel->setPropertyValue( FM_PROP_TRISTATE, makeAny( sal_Bool( ColumnValue::NO_NULLS != nNullable ) ) ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + //------------------------------------------------------------------------------ + ::rtl::OUString FormControlFactory::getDefaultName( sal_Int16 _nClassId, const Reference< XServiceInfo >& _rxObject ) + { + sal_uInt16 nResId(0); + + switch ( _nClassId ) + { + case FormComponentType::COMMANDBUTTON: nResId = RID_STR_PROPTITLE_PUSHBUTTON; break; + case FormComponentType::RADIOBUTTON: nResId = RID_STR_PROPTITLE_RADIOBUTTON; break; + case FormComponentType::CHECKBOX: nResId = RID_STR_PROPTITLE_CHECKBOX; break; + case FormComponentType::LISTBOX: nResId = RID_STR_PROPTITLE_LISTBOX; break; + case FormComponentType::COMBOBOX: nResId = RID_STR_PROPTITLE_COMBOBOX; break; + case FormComponentType::GROUPBOX: nResId = RID_STR_PROPTITLE_GROUPBOX; break; + case FormComponentType::IMAGEBUTTON: nResId = RID_STR_PROPTITLE_IMAGEBUTTON; break; + case FormComponentType::FIXEDTEXT: nResId = RID_STR_PROPTITLE_FIXEDTEXT; break; + case FormComponentType::GRIDCONTROL: nResId = RID_STR_PROPTITLE_DBGRID; break; + case FormComponentType::FILECONTROL: nResId = RID_STR_PROPTITLE_FILECONTROL; break; + case FormComponentType::DATEFIELD: nResId = RID_STR_PROPTITLE_DATEFIELD; break; + case FormComponentType::TIMEFIELD: nResId = RID_STR_PROPTITLE_TIMEFIELD; break; + case FormComponentType::NUMERICFIELD: nResId = RID_STR_PROPTITLE_NUMERICFIELD; break; + case FormComponentType::CURRENCYFIELD: nResId = RID_STR_PROPTITLE_CURRENCYFIELD; break; + case FormComponentType::PATTERNFIELD: nResId = RID_STR_PROPTITLE_PATTERNFIELD; break; + case FormComponentType::IMAGECONTROL: nResId = RID_STR_PROPTITLE_IMAGECONTROL; break; + case FormComponentType::HIDDENCONTROL: nResId = RID_STR_PROPTITLE_HIDDEN; break; + case FormComponentType::SCROLLBAR: nResId = RID_STR_PROPTITLE_SCROLLBAR; break; + case FormComponentType::SPINBUTTON: nResId = RID_STR_PROPTITLE_SPINBUTTON; break; + case FormComponentType::NAVIGATIONBAR: nResId = RID_STR_PROPTITLE_NAVBAR; break; + + case FormComponentType::TEXTFIELD: + nResId = RID_STR_PROPTITLE_EDIT; + if ( _rxObject.is() && _rxObject->supportsService( FM_SUN_COMPONENT_FORMATTEDFIELD ) ) + nResId = RID_STR_PROPTITLE_FORMATTED; + break; + + default: + nResId = RID_STR_CONTROL; break; + } + + return String( SVX_RES( nResId ) ); + } + + //------------------------------------------------------------------------------ + ::rtl::OUString FormControlFactory::getDefaultUniqueName_ByComponentType( const Reference< XNameAccess >& _rxContainer, + const Reference< XPropertySet >& _rxObject ) + { + sal_Int16 nClassId = FormComponentType::CONTROL; + OSL_VERIFY( _rxObject->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId ); + ::rtl::OUString sBaseName = getDefaultName( nClassId, Reference< XServiceInfo >( _rxObject, UNO_QUERY ) ); + + return getUniqueName( _rxContainer, sBaseName ); + } + + //------------------------------------------------------------------------------ + ::rtl::OUString FormControlFactory::getUniqueName( const Reference< XNameAccess >& _rxContainer, const ::rtl::OUString& _rBaseName ) + { + sal_Int32 n = 0; + ::rtl::OUString sName; + do + { + ::rtl::OUStringBuffer aBuf( _rBaseName ); + aBuf.appendAscii( " " ); + aBuf.append( ++n ); + sName = aBuf.makeStringAndClear(); + } + while ( _rxContainer->hasByName( sName ) ); + + return sName; + } + +//........................................................................ +} // namespace svxform +//........................................................................ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/formcontroller.cxx b/svx/source/form/formcontroller.cxx new file mode 100644 index 000000000000..552744a30e02 --- /dev/null +++ b/svx/source/form/formcontroller.cxx @@ -0,0 +1,4320 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include "fmcontrolbordermanager.hxx" +#include "fmcontrollayout.hxx" +#include "formcontroller.hxx" +#include "formfeaturedispatcher.hxx" +#include "fmdocumentclassification.hxx" +#include "formcontrolling.hxx" +#include "fmprop.hrc" +#include "svx/dialmgr.hxx" +#include "fmresids.hrc" +#include "fmservs.hxx" +#include "svx/fmtools.hxx" +#include "fmurl.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/awt/FocusChangeReason.hpp> +#include <com/sun/star/awt/XCheckBox.hpp> +#include <com/sun/star/awt/XComboBox.hpp> +#include <com/sun/star/awt/XListBox.hpp> +#include <com/sun/star/awt/XVclWindowPeer.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/container/XIdentifierReplace.hpp> +#include <com/sun/star/form/TabulatorCycle.hpp> +#include <com/sun/star/form/validation/XValidatableFormComponent.hpp> +#include <com/sun/star/form/XBoundComponent.hpp> +#include <com/sun/star/form/XBoundControl.hpp> +#include <com/sun/star/form/XGridControl.hpp> +#include <com/sun/star/form/XLoadable.hpp> +#include <com/sun/star/form/XReset.hpp> +#include <com/sun/star/frame/XController.hpp> +#include <com/sun/star/sdb/ParametersRequest.hpp> +#include <com/sun/star/sdb/RowChangeAction.hpp> +#include <com/sun/star/sdb/XInteractionSupplyParameters.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/form/runtime/FormOperations.hpp> +#include <com/sun/star/form/runtime/FormFeature.hpp> +#include <com/sun/star/container/XContainer.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/util/XNumberFormatter.hpp> +#include <com/sun/star/sdb/SQLContext.hpp> +#include <com/sun/star/sdb/XColumn.hpp> +/** === end UNO includes === **/ + +#include <comphelper/enumhelper.hxx> +#include <comphelper/extract.hxx> +#include <comphelper/interaction.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <comphelper/propagg.hxx> +#include <comphelper/property.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/uno3.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <toolkit/controls/unocontrol.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <tools/shl.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> +#include <osl/mutex.hxx> +#include <rtl/logfile.hxx> + +#include <algorithm> +#include <functional> + +using namespace ::com::sun::star; +using namespace ::comphelper; +using namespace ::connectivity; +using namespace ::connectivity::simple; + +//------------------------------------------------------------------ +::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL + FormController_NewInstance_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & _rxORB ) +{ + return *( new ::svxform::FormController( _rxORB ) ); +} + +namespace svxform +{ + + /** === begin UNO using === **/ + using ::com::sun::star::sdb::XColumn; + using ::com::sun::star::awt::XControl; + using ::com::sun::star::awt::XTabController; + using ::com::sun::star::awt::XToolkit; + using ::com::sun::star::awt::XWindowPeer; + using ::com::sun::star::form::XGrid; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::container::XIndexAccess; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::beans::XPropertySetInfo; + using ::com::sun::star::beans::PropertyValue; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::lang::IndexOutOfBoundsException; + using ::com::sun::star::sdb::XInteractionSupplyParameters; + using ::com::sun::star::awt::XTextComponent; + using ::com::sun::star::awt::XTextListener; + using ::com::sun::star::uno::Any; + using ::com::sun::star::frame::XDispatch; + using ::com::sun::star::lang::XMultiServiceFactory; + using ::com::sun::star::uno::XAggregation; + using ::com::sun::star::uno::Type; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::sdbc::XConnection; + using ::com::sun::star::sdbc::XRowSet; + using ::com::sun::star::sdbc::XDatabaseMetaData; + using ::com::sun::star::util::XNumberFormatsSupplier; + using ::com::sun::star::util::XNumberFormatter; + using ::com::sun::star::sdbcx::XColumnsSupplier; + using ::com::sun::star::container::XNameAccess; + using ::com::sun::star::lang::EventObject; + using ::com::sun::star::beans::Property; + using ::com::sun::star::container::XEnumeration; + using ::com::sun::star::form::XFormComponent; + using ::com::sun::star::form::runtime::XFormOperations; + using ::com::sun::star::form::runtime::FilterEvent; + using ::com::sun::star::form::runtime::XFilterControllerListener; + using ::com::sun::star::awt::XControlContainer; + using ::com::sun::star::container::XIdentifierReplace; + using ::com::sun::star::lang::WrappedTargetException; + using ::com::sun::star::form::XFormControllerListener; + using ::com::sun::star::awt::XWindow; + using ::com::sun::star::sdbc::XResultSet; + using ::com::sun::star::awt::XControlModel; + using ::com::sun::star::awt::XTabControllerModel; + using ::com::sun::star::beans::PropertyChangeEvent; + using ::com::sun::star::form::validation::XValidatableFormComponent; + using ::com::sun::star::form::XLoadable; + using ::com::sun::star::script::XEventAttacherManager; + using ::com::sun::star::form::XBoundControl; + using ::com::sun::star::beans::XPropertyChangeListener; + using ::com::sun::star::awt::TextEvent; + using ::com::sun::star::form::XBoundComponent; + using ::com::sun::star::awt::XCheckBox; + using ::com::sun::star::awt::XComboBox; + using ::com::sun::star::awt::XListBox; + using ::com::sun::star::awt::ItemEvent; + using ::com::sun::star::util::XModifyListener; + using ::com::sun::star::form::XReset; + using ::com::sun::star::frame::XDispatchProviderInterception; + using ::com::sun::star::form::XGridControl; + using ::com::sun::star::awt::XVclWindowPeer; + using ::com::sun::star::form::validation::XValidator; + using ::com::sun::star::awt::FocusEvent; + using ::com::sun::star::sdb::SQLContext; + using ::com::sun::star::container::XChild; + using ::com::sun::star::form::TabulatorCycle_RECORDS; + using ::com::sun::star::container::ContainerEvent; + using ::com::sun::star::lang::DisposedException; + using ::com::sun::star::lang::Locale; + using ::com::sun::star::beans::NamedValue; + using ::com::sun::star::lang::NoSupportException; + using ::com::sun::star::sdb::RowChangeEvent; + using ::com::sun::star::frame::XStatusListener; + using ::com::sun::star::frame::XDispatchProviderInterceptor; + using ::com::sun::star::sdb::SQLErrorEvent; + using ::com::sun::star::form::DatabaseParameterEvent; + using ::com::sun::star::sdb::ParametersRequest; + using ::com::sun::star::task::XInteractionRequest; + using ::com::sun::star::util::URL; + using ::com::sun::star::frame::FeatureStateEvent; + using ::com::sun::star::form::runtime::XFormControllerContext; + using ::com::sun::star::task::XInteractionHandler; + using ::com::sun::star::form::runtime::FormOperations; + using ::com::sun::star::container::XContainer; + using ::com::sun::star::sdbc::SQLWarning; + /** === end UNO using === **/ + namespace ColumnValue = ::com::sun::star::sdbc::ColumnValue; + namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute; + namespace FocusChangeReason = ::com::sun::star::awt::FocusChangeReason; + namespace RowChangeAction = ::com::sun::star::sdb::RowChangeAction; + namespace FormFeature = ::com::sun::star::form::runtime::FormFeature; + +//============================================================================== +// ColumnInfo +//============================================================================== +struct ColumnInfo +{ + // information about the column itself + Reference< XColumn > xColumn; + sal_Int32 nNullable; + sal_Bool bAutoIncrement; + sal_Bool bReadOnly; + ::rtl::OUString sName; + + // information about the control(s) bound to this column + + /// the first control which is bound to the given column, and which requires input + Reference< XControl > xFirstControlWithInputRequired; + /** the first grid control which contains a column which is bound to the given database column, and requires + input + */ + Reference< XGrid > xFirstGridWithInputRequiredColumn; + /** if xFirstControlWithInputRequired is a grid control, then nRequiredGridColumn specifies the position + of the grid column which is actually bound + */ + sal_Int32 nRequiredGridColumn; + + ColumnInfo() + :xColumn() + ,nNullable( ColumnValue::NULLABLE_UNKNOWN ) + ,bAutoIncrement( sal_False ) + ,bReadOnly( sal_False ) + ,sName() + ,xFirstControlWithInputRequired() + ,xFirstGridWithInputRequiredColumn() + ,nRequiredGridColumn( -1 ) + { + } +}; + +//============================================================================== +//= ColumnInfoCache +//============================================================================== +class ColumnInfoCache +{ +public: + ColumnInfoCache( const Reference< XColumnsSupplier >& _rxColSupplier ); + + size_t getColumnCount() const { return m_aColumns.size(); } + const ColumnInfo& getColumnInfo( size_t _pos ); + + bool controlsInitialized() const { return m_bControlsInitialized; } + void initializeControls( const Sequence< Reference< XControl > >& _rControls ); + void deinitializeControls(); + +private: + typedef ::std::vector< ColumnInfo > ColumnInfos; + ColumnInfos m_aColumns; + bool m_bControlsInitialized; +}; + +//------------------------------------------------------------------------------ +ColumnInfoCache::ColumnInfoCache( const Reference< XColumnsSupplier >& _rxColSupplier ) + :m_aColumns() + ,m_bControlsInitialized( false ) +{ + try + { + m_aColumns.clear(); + + Reference< XColumnsSupplier > xSupplyCols( _rxColSupplier, UNO_SET_THROW ); + Reference< XIndexAccess > xColumns( xSupplyCols->getColumns(), UNO_QUERY_THROW ); + sal_Int32 nColumnCount = xColumns->getCount(); + m_aColumns.reserve( nColumnCount ); + + Reference< XPropertySet > xColumnProps; + for ( sal_Int32 i = 0; i < nColumnCount; ++i ) + { + ColumnInfo aColInfo; + aColInfo.xColumn.set( xColumns->getByIndex(i), UNO_QUERY_THROW ); + + xColumnProps.set( aColInfo.xColumn, UNO_QUERY_THROW ); + OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_ISNULLABLE ) >>= aColInfo.nNullable ); + OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_AUTOINCREMENT ) >>= aColInfo.bAutoIncrement ); + OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_NAME ) >>= aColInfo.sName ); + OSL_VERIFY( xColumnProps->getPropertyValue( FM_PROP_ISREADONLY ) >>= aColInfo.bReadOnly ); + + m_aColumns.push_back( aColInfo ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +//------------------------------------------------------------------------------ +namespace +{ + bool lcl_isBoundTo( const Reference< XPropertySet >& _rxControlModel, const Reference< XInterface >& _rxNormDBField ) + { + Reference< XInterface > xNormBoundField( _rxControlModel->getPropertyValue( FM_PROP_BOUNDFIELD ), UNO_QUERY ); + return ( xNormBoundField.get() == _rxNormDBField.get() ); + } + + bool lcl_isInputRequired( const Reference< XPropertySet >& _rxControlModel ) + { + sal_Bool bInputRequired = sal_True; + OSL_VERIFY( _rxControlModel->getPropertyValue( FM_PROP_INPUT_REQUIRED ) >>= bInputRequired ); + return ( bInputRequired != sal_False ); + } + + void lcl_resetColumnControlInfo( ColumnInfo& _rColInfo ) + { + _rColInfo.xFirstControlWithInputRequired.clear(); + _rColInfo.xFirstGridWithInputRequiredColumn.clear(); + _rColInfo.nRequiredGridColumn = -1; + } +} + +//------------------------------------------------------------------------------ +void ColumnInfoCache::deinitializeControls() +{ + for ( ColumnInfos::iterator col = m_aColumns.begin(); + col != m_aColumns.end(); + ++col + ) + { + lcl_resetColumnControlInfo( *col ); + } +} + +//------------------------------------------------------------------------------ +void ColumnInfoCache::initializeControls( const Sequence< Reference< XControl > >& _rControls ) +{ + try + { + // for every of our known columns, find the controls which are bound to this column + for ( ColumnInfos::iterator col = m_aColumns.begin(); + col != m_aColumns.end(); + ++col + ) + { + OSL_ENSURE( !col->xFirstControlWithInputRequired.is() && !col->xFirstGridWithInputRequiredColumn.is() + && ( col->nRequiredGridColumn == -1 ), "ColumnInfoCache::initializeControls: called me twice?" ); + + lcl_resetColumnControlInfo( *col ); + + Reference< XInterface > xNormColumn( col->xColumn, UNO_QUERY_THROW ); + + const Reference< XControl >* pControl( _rControls.getConstArray() ); + const Reference< XControl >* pControlEnd( pControl + _rControls.getLength() ); + for ( ; pControl != pControlEnd; ++pControl ) + { + if ( !pControl->is() ) + continue; + + Reference< XPropertySet > xModel( (*pControl)->getModel(), UNO_QUERY_THROW ); + Reference< XPropertySetInfo > xModelPSI( xModel->getPropertySetInfo(), UNO_SET_THROW ); + + // special handling for grid controls + Reference< XGrid > xGrid( *pControl, UNO_QUERY ); + if ( xGrid.is() ) + { + Reference< XIndexAccess > xGridColAccess( xModel, UNO_QUERY_THROW ); + sal_Int32 gridColCount = xGridColAccess->getCount(); + sal_Int32 gridCol = 0; + for ( gridCol = 0; gridCol < gridColCount; ++gridCol ) + { + Reference< XPropertySet > xGridColumnModel( xGridColAccess->getByIndex( gridCol ), UNO_QUERY_THROW ); + + if ( !lcl_isBoundTo( xGridColumnModel, xNormColumn ) + || !lcl_isInputRequired( xGridColumnModel ) + ) + continue; // with next grid column + + break; + } + + if ( gridCol < gridColCount ) + { + // found a grid column which is bound to the given + col->xFirstGridWithInputRequiredColumn = xGrid; + col->nRequiredGridColumn = gridCol; + break; + } + + continue; // with next control + } + + if ( !xModelPSI->hasPropertyByName( FM_PROP_BOUNDFIELD ) + || !lcl_isBoundTo( xModel, xNormColumn ) + || !lcl_isInputRequired( xModel ) + ) + continue; // with next control + + break; + } + + if ( pControl == pControlEnd ) + // did not find a control which is bound to this particular column, and for which the input is required + continue; // with next DB column + + col->xFirstControlWithInputRequired = *pControl; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + m_bControlsInitialized = true; +} + +//------------------------------------------------------------------------------ +const ColumnInfo& ColumnInfoCache::getColumnInfo( size_t _pos ) +{ + if ( _pos >= m_aColumns.size() ) + throw IndexOutOfBoundsException(); + + return m_aColumns[ _pos ]; +} + +//================================================================== +// OParameterContinuation +//================================================================== +class OParameterContinuation : public OInteraction< XInteractionSupplyParameters > +{ + Sequence< PropertyValue > m_aValues; + +public: + OParameterContinuation() { } + + Sequence< PropertyValue > getValues() const { return m_aValues; } + +// XInteractionSupplyParameters + virtual void SAL_CALL setParameters( const Sequence< PropertyValue >& _rValues ) throw(RuntimeException); +}; + +//------------------------------------------------------------------ +void SAL_CALL OParameterContinuation::setParameters( const Sequence< PropertyValue >& _rValues ) throw(RuntimeException) +{ + m_aValues = _rValues; +} + +//================================================================== +// FmXAutoControl +//================================================================== +struct FmFieldInfo +{ + rtl::OUString aFieldName; + Reference< XPropertySet > xField; + Reference< XTextComponent > xText; + + FmFieldInfo(const Reference< XPropertySet >& _xField, const Reference< XTextComponent >& _xText) + :xField(_xField) + ,xText(_xText) + {xField->getPropertyValue(FM_PROP_NAME) >>= aFieldName;} +}; + +//================================================================== +// FmXAutoControl +//================================================================== +class FmXAutoControl: public UnoControl + +{ + friend Reference< XInterface > SAL_CALL FmXAutoControl_NewInstance_Impl(); + +public: + FmXAutoControl(){} + + virtual ::rtl::OUString GetComponentServiceName() {return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Edit"));} + virtual void SAL_CALL createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer ) throw( RuntimeException ); + +protected: + virtual void ImplSetPeerProperty( const ::rtl::OUString& rPropName, const Any& rVal ); +}; + +//------------------------------------------------------------------------------ +void FmXAutoControl::createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer ) throw( RuntimeException ) +{ + UnoControl::createPeer( rxToolkit, rParentPeer ); + + Reference< XTextComponent > xText(getPeer() , UNO_QUERY); + if (xText.is()) + { + xText->setText(::rtl::OUString(String(SVX_RES(RID_STR_AUTOFIELD)))); + xText->setEditable(sal_False); + } +} + +//------------------------------------------------------------------------------ +void FmXAutoControl::ImplSetPeerProperty( const ::rtl::OUString& rPropName, const Any& rVal ) +{ + // these properties are ignored + if (rPropName == FM_PROP_TEXT) + return; + + UnoControl::ImplSetPeerProperty( rPropName, rVal ); +} + +//------------------------------------------------------------------------------ +IMPL_LINK( FormController, OnActivateTabOrder, void*, /*EMPTYTAG*/ ) +{ + activateTabOrder(); + return 1; +} + +//------------------------------------------------------------------------------ +struct UpdateAllListeners : public ::std::unary_function< Reference< XDispatch >, bool > +{ + bool operator()( const Reference< XDispatch >& _rxDispatcher ) const + { + static_cast< ::svx::OSingleFeatureDispatcher* >( _rxDispatcher.get() )->updateAllListeners(); + // the return is a dummy only so we can use this struct in a std::compose1 call + return true; + } +}; +//.............................................................................. +IMPL_LINK( FormController, OnInvalidateFeatures, void*, /*_pNotInterestedInThisParam*/ ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + for ( ::std::set< sal_Int16 >::const_iterator aLoop = m_aInvalidFeatures.begin(); + aLoop != m_aInvalidFeatures.end(); + ++aLoop + ) + { + DispatcherContainer::const_iterator aDispatcherPos = m_aFeatureDispatchers.find( *aLoop ); + if ( aDispatcherPos != m_aFeatureDispatchers.end() ) + { + // TODO: for the real and actual listener notifications, we should release + // our mutex + UpdateAllListeners( )( aDispatcherPos->second ); + } + } + return 1; +} + +/*************************************************************************/ + +DBG_NAME( FormController ) +//------------------------------------------------------------------ +FormController::FormController(const Reference< XMultiServiceFactory > & _rxORB ) + :FormController_BASE( m_aMutex ) + ,OPropertySetHelper( FormController_BASE::rBHelper ) + ,OSQLParserClient( _rxORB ) + ,m_aContext( _rxORB ) + ,m_aActivateListeners(m_aMutex) + ,m_aModifyListeners(m_aMutex) + ,m_aErrorListeners(m_aMutex) + ,m_aDeleteListeners(m_aMutex) + ,m_aRowSetApproveListeners(m_aMutex) + ,m_aParameterListeners(m_aMutex) + ,m_aFilterListeners(m_aMutex) + ,m_pControlBorderManager( new ::svxform::ControlBorderManager ) + ,m_xFormOperations() + ,m_aMode( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DataMode" ) ) ) + ,m_aLoadEvent( LINK( this, FormController, OnLoad ) ) + ,m_aToggleEvent( LINK( this, FormController, OnToggleAutoFields ) ) + ,m_aActivationEvent( LINK( this, FormController, OnActivated ) ) + ,m_aDeactivationEvent( LINK( this, FormController, OnDeactivated ) ) + ,m_nCurrentFilterPosition(-1) + ,m_bCurrentRecordModified(sal_False) + ,m_bCurrentRecordNew(sal_False) + ,m_bLocked(sal_False) + ,m_bDBConnection(sal_False) + ,m_bCycle(sal_False) + ,m_bCanInsert(sal_False) + ,m_bCanUpdate(sal_False) + ,m_bCommitLock(sal_False) + ,m_bModified(sal_False) + ,m_bControlsSorted(sal_False) + ,m_bFiltering(sal_False) + ,m_bAttachEvents(sal_True) + ,m_bDetachEvents(sal_True) + ,m_bAttemptedHandlerCreation( false ) +{ + DBG_CTOR( FormController, NULL ); + + ::comphelper::increment(m_refCount); + { + { + m_xAggregate = Reference< XAggregation >( + m_aContext.createComponent( "com.sun.star.awt.TabController" ), + UNO_QUERY + ); + DBG_ASSERT( m_xAggregate.is(), "FormController::FormController : could not create my aggregate !" ); + m_xTabController = Reference< XTabController >( m_xAggregate, UNO_QUERY ); + } + + if ( m_xAggregate.is() ) + m_xAggregate->setDelegator( *this ); + } + ::comphelper::decrement(m_refCount); + + m_aTabActivationTimer.SetTimeout( 500 ); + m_aTabActivationTimer.SetTimeoutHdl( LINK( this, FormController, OnActivateTabOrder ) ); + + m_aFeatureInvalidationTimer.SetTimeout( 200 ); + m_aFeatureInvalidationTimer.SetTimeoutHdl( LINK( this, FormController, OnInvalidateFeatures ) ); +} + +//------------------------------------------------------------------ +FormController::~FormController() +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + + m_aLoadEvent.CancelPendingCall(); + m_aToggleEvent.CancelPendingCall(); + m_aActivationEvent.CancelPendingCall(); + m_aDeactivationEvent.CancelPendingCall(); + + if ( m_aTabActivationTimer.IsActive() ) + m_aTabActivationTimer.Stop(); + } + + if ( m_aFeatureInvalidationTimer.IsActive() ) + m_aFeatureInvalidationTimer.Stop(); + + disposeAllFeaturesAndDispatchers(); + + if ( m_xFormOperations.is() ) + m_xFormOperations->dispose(); + m_xFormOperations.clear(); + + // Freigeben der Aggregation + if ( m_xAggregate.is() ) + { + m_xAggregate->setDelegator( NULL ); + m_xAggregate.clear(); + } + + DELETEZ( m_pControlBorderManager ); + + DBG_DTOR( FormController, NULL ); +} + +// ----------------------------------------------------------------------------- +void SAL_CALL FormController::acquire() throw () +{ + FormController_BASE::acquire(); +} + +// ----------------------------------------------------------------------------- +void SAL_CALL FormController::release() throw () +{ + FormController_BASE::release(); +} + +//------------------------------------------------------------------ +Any SAL_CALL FormController::queryInterface( const Type& _rType ) throw(RuntimeException) +{ + Any aRet = FormController_BASE::queryInterface( _rType ); + if ( !aRet.hasValue() ) + aRet = OPropertySetHelper::queryInterface( _rType ); + if ( !aRet.hasValue() ) + aRet = m_xAggregate->queryAggregation( _rType ); + return aRet; +} + +//------------------------------------------------------------------------------ +Sequence< sal_Int8 > SAL_CALL FormController::getImplementationId() throw( RuntimeException ) +{ + static ::cppu::OImplementationId* pId = NULL; + if ( !pId ) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if ( !pId ) + { + static ::cppu::OImplementationId aId; + pId = &aId; + } + } + return pId->getImplementationId(); +} + +//------------------------------------------------------------------------------ +Sequence< Type > SAL_CALL FormController::getTypes( ) throw(RuntimeException) +{ + return comphelper::concatSequences( + FormController_BASE::getTypes(), + ::cppu::OPropertySetHelper::getTypes() + ); +} + +// XServiceInfo +//------------------------------------------------------------------------------ +sal_Bool SAL_CALL FormController::supportsService(const ::rtl::OUString& ServiceName) throw( RuntimeException ) +{ + Sequence< ::rtl::OUString> aSNL(getSupportedServiceNames()); + const ::rtl::OUString * pArray = aSNL.getConstArray(); + for( sal_Int32 i = 0; i < aSNL.getLength(); i++ ) + if( pArray[i] == ServiceName ) + return sal_True; + return sal_False; +} + +//------------------------------------------------------------------------------ +::rtl::OUString SAL_CALL FormController::getImplementationName() throw( RuntimeException ) +{ + return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("org.openoffice.comp.svx.FormController")); +} + +//------------------------------------------------------------------------------ +Sequence< ::rtl::OUString> SAL_CALL FormController::getSupportedServiceNames(void) throw( RuntimeException ) +{ + // service names which are supported only, but cannot be used to created an + // instance at a service factory + Sequence< ::rtl::OUString > aNonCreatableServiceNames( 1 ); + aNonCreatableServiceNames[ 0 ] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.form.FormControllerDispatcher" ) ); + + // services which can be used to created an instance at a service factory + Sequence< ::rtl::OUString > aCreatableServiceNames( getSupportedServiceNames_Static() ); + return ::comphelper::concatSequences( aCreatableServiceNames, aNonCreatableServiceNames ); +} + +//------------------------------------------------------------------------------ +sal_Bool SAL_CALL FormController::approveReset(const EventObject& /*rEvent*/) throw( RuntimeException ) +{ + return sal_True; +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::resetted(const EventObject& rEvent) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + if (getCurrentControl().is() && (getCurrentControl()->getModel() == rEvent.Source)) + m_bModified = sal_False; +} + +//------------------------------------------------------------------------------ +Sequence< ::rtl::OUString> FormController::getSupportedServiceNames_Static(void) +{ + static Sequence< ::rtl::OUString> aServices; + if (!aServices.getLength()) + { + aServices.realloc(2); + aServices.getArray()[0] = FM_FORM_CONTROLLER; + aServices.getArray()[1] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.awt.control.TabController")); + } + return aServices; +} + +// ----------------------------------------------------------------------------- +namespace +{ + struct ResetComponentText : public ::std::unary_function< Reference< XTextComponent >, void > + { + void operator()( const Reference< XTextComponent >& _rxText ) + { + _rxText->setText( ::rtl::OUString() ); + } + }; + + struct RemoveComponentTextListener : public ::std::unary_function< Reference< XTextComponent >, void > + { + RemoveComponentTextListener( const Reference< XTextListener >& _rxListener ) + :m_xListener( _rxListener ) + { + } + + void operator()( const Reference< XTextComponent >& _rxText ) + { + _rxText->removeTextListener( m_xListener ); + } + + private: + Reference< XTextListener > m_xListener; + }; +} + +// ----------------------------------------------------------------------------- +void FormController::impl_setTextOnAllFilter_throw() +{ + // reset the text for all controls + ::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), ResetComponentText() ); + + if ( m_aFilterRows.empty() ) + // nothing to do anymore + return; + + if ( m_nCurrentFilterPosition < 0 ) + return; + + // set the text for all filters + OSL_ENSURE( m_aFilterRows.size() > (size_t)m_nCurrentFilterPosition, + "FormController::impl_setTextOnAllFilter_throw: m_nCurrentFilterPosition too big" ); + + if ( (size_t)m_nCurrentFilterPosition < m_aFilterRows.size() ) + { + FmFilterRow& rRow = m_aFilterRows[ m_nCurrentFilterPosition ]; + for ( FmFilterRow::const_iterator iter2 = rRow.begin(); + iter2 != rRow.end(); + ++iter2 + ) + { + iter2->first->setText( iter2->second ); + } + } +} +// OPropertySetHelper +//------------------------------------------------------------------------------ +sal_Bool FormController::convertFastPropertyValue( Any & /*rConvertedValue*/, Any & /*rOldValue*/, + sal_Int32 /*nHandle*/, const Any& /*rValue*/ ) + throw( IllegalArgumentException ) +{ + return sal_False; +} + +//------------------------------------------------------------------------------ +void FormController::setFastPropertyValue_NoBroadcast( sal_Int32 /*nHandle*/, const Any& /*rValue*/ ) + throw( Exception ) +{ +} + +//------------------------------------------------------------------------------ +void FormController::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const +{ + switch (nHandle) + { + case FM_ATTR_FILTER: + { + ::rtl::OUStringBuffer aFilter; + OStaticDataAccessTools aStaticTools; + Reference<XConnection> xConnection(aStaticTools.getRowSetConnection(Reference< XRowSet>(m_xModelAsIndex, UNO_QUERY))); + if (xConnection.is()) + { + Reference< XDatabaseMetaData> xMetaData(xConnection->getMetaData()); + Reference< XNumberFormatsSupplier> xFormatSupplier( aStaticTools.getNumberFormats( xConnection, sal_True ) ); + Reference< XNumberFormatter> xFormatter( m_aContext.createComponent( "com.sun.star.util.NumberFormatter" ), UNO_QUERY_THROW ); + xFormatter->attachNumberFormatsSupplier(xFormatSupplier); + + Reference< XColumnsSupplier> xSupplyCols(m_xModelAsIndex, UNO_QUERY); + Reference< XNameAccess> xFields(xSupplyCols->getColumns(), UNO_QUERY); + + ::rtl::OUString aQuote( xMetaData->getIdentifierQuoteString() ); + + // now add the filter rows + try + { + for ( FmFilterRows::const_iterator row = m_aFilterRows.begin(); row != m_aFilterRows.end(); ++row ) + { + const FmFilterRow& rRow = *row; + + if ( rRow.empty() ) + continue; + + if ( aFilter.getLength() ) + aFilter.appendAscii( " OR " ); + + aFilter.appendAscii( "( " ); + for ( FmFilterRow::const_iterator condition = rRow.begin(); condition != rRow.end(); ++condition ) + { + // get the field of the controls map + Reference< XControl > xControl( condition->first, UNO_QUERY_THROW ); + Reference< XPropertySet > xModelProps( xControl->getModel(), UNO_QUERY_THROW ); + Reference< XPropertySet > xField( xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ), UNO_QUERY_THROW ); + if ( condition != rRow.begin() ) + aFilter.appendAscii( " AND " ); + + ::rtl::OUString sFilterValue( condition->second ); + + ::rtl::OUString sErrorMsg, sCriteria; + ::rtl::Reference< ISQLParseNode > xParseNode = predicateTree( sErrorMsg, sFilterValue, xFormatter, xField ); + OSL_ENSURE( xParseNode.is(), "FormController::getFastPropertyValue: could not parse the field value predicate!" ); + if ( xParseNode.is() ) + { + // don't use a parse context here, we need it unlocalized + xParseNode->parseNodeToStr( sCriteria, xConnection, NULL ); + aFilter.append( sCriteria ); + } + } + aFilter.appendAscii( " )" ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + aFilter.setLength(0); + } + } + rValue <<= aFilter.makeStringAndClear(); + } + break; + + case FM_ATTR_FORM_OPERATIONS: + rValue <<= m_xFormOperations; + break; + } +} + +//------------------------------------------------------------------------------ +Reference< XPropertySetInfo > FormController::getPropertySetInfo() throw( RuntimeException ) +{ + static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +//------------------------------------------------------------------------------ +#define DECL_PROP_CORE(varname, type) \ +pDesc[nPos++] = Property(FM_PROP_##varname, FM_ATTR_##varname, ::getCppuType((const type*)0), + + +#define DECL_PROP1(varname, type, attrib1) \ + DECL_PROP_CORE(varname, type) PropertyAttribute::attrib1) + +//------------------------------------------------------------------------------ +void FormController::fillProperties( + Sequence< Property >& /* [out] */ _rProps, + Sequence< Property >& /* [out] */ /*_rAggregateProps*/ + ) const +{ + _rProps.realloc(2); + sal_Int32 nPos = 0; + Property* pDesc = _rProps.getArray(); + DECL_PROP1(FILTER, rtl::OUString, READONLY); + DECL_PROP1(FORM_OPERATIONS, Reference< XFormOperations >, READONLY); +} + +//------------------------------------------------------------------------------ +::cppu::IPropertyArrayHelper& FormController::getInfoHelper() +{ + return *getArrayHelper(); +} + +// XFilterController +//------------------------------------------------------------------------------ +void SAL_CALL FormController::addFilterControllerListener( const Reference< XFilterControllerListener >& _Listener ) throw( RuntimeException ) +{ + m_aFilterListeners.addInterface( _Listener ); +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::removeFilterControllerListener( const Reference< XFilterControllerListener >& _Listener ) throw( RuntimeException ) +{ + m_aFilterListeners.removeInterface( _Listener ); +} + +//------------------------------------------------------------------------------ +::sal_Int32 SAL_CALL FormController::getFilterComponents() throw( ::com::sun::star::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + return m_aFilterComponents.size(); +} + +//------------------------------------------------------------------------------ +::sal_Int32 SAL_CALL FormController::getDisjunctiveTerms() throw( ::com::sun::star::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + return m_aFilterRows.size(); +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::setPredicateExpression( ::sal_Int32 _Component, ::sal_Int32 _Term, const ::rtl::OUString& _PredicateExpression ) throw( RuntimeException, IndexOutOfBoundsException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + if ( ( _Component < 0 ) || ( _Component >= getFilterComponents() ) || ( _Term < 0 ) || ( _Term >= getDisjunctiveTerms() ) ) + throw IndexOutOfBoundsException( ::rtl::OUString(), *this ); + + Reference< XTextComponent > xText( m_aFilterComponents[ _Component ] ); + xText->setText( _PredicateExpression ); + + FmFilterRow& rFilterRow = m_aFilterRows[ _Term ]; + if ( _PredicateExpression.getLength() ) + rFilterRow[ xText ] = _PredicateExpression; + else + rFilterRow.erase( xText ); +} + +//------------------------------------------------------------------------------ +Reference< XControl > FormController::getFilterComponent( ::sal_Int32 _Component ) throw( RuntimeException, IndexOutOfBoundsException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + if ( ( _Component < 0 ) || ( _Component >= getFilterComponents() ) ) + throw IndexOutOfBoundsException( ::rtl::OUString(), *this ); + + return Reference< XControl >( m_aFilterComponents[ _Component ], UNO_QUERY ); +} + +//------------------------------------------------------------------------------ +Sequence< Sequence< ::rtl::OUString > > FormController::getPredicateExpressions() throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + Sequence< Sequence< ::rtl::OUString > > aExpressions( m_aFilterRows.size() ); + sal_Int32 termIndex = 0; + for ( FmFilterRows::const_iterator row = m_aFilterRows.begin(); + row != m_aFilterRows.end(); + ++row, ++termIndex + ) + { + const FmFilterRow& rRow( *row ); + + Sequence< ::rtl::OUString > aConjunction( m_aFilterComponents.size() ); + sal_Int32 componentIndex = 0; + for ( FilterComponents::const_iterator comp = m_aFilterComponents.begin(); + comp != m_aFilterComponents.end(); + ++comp, ++componentIndex + ) + { + FmFilterRow::const_iterator predicate = rRow.find( *comp ); + if ( predicate != rRow.end() ) + aConjunction[ componentIndex ] = predicate->second; + } + + aExpressions[ termIndex ] = aConjunction; + } + + return aExpressions; +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::removeDisjunctiveTerm( ::sal_Int32 _Term ) throw (IndexOutOfBoundsException, RuntimeException) +{ + // SYNCHRONIZED --> + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + if ( ( _Term < 0 ) || ( _Term >= getDisjunctiveTerms() ) ) + throw IndexOutOfBoundsException( ::rtl::OUString(), *this ); + + // if the to-be-deleted row is our current row, we need to shift + if ( _Term == m_nCurrentFilterPosition ) + { + if ( m_nCurrentFilterPosition < sal_Int32( m_aFilterRows.size() - 1 ) ) + ++m_nCurrentFilterPosition; + else + --m_nCurrentFilterPosition; + } + + FmFilterRows::iterator pos = m_aFilterRows.begin() + _Term; + m_aFilterRows.erase( pos ); + + // adjust m_nCurrentFilterPosition if the removed row preceeded it + if ( _Term < m_nCurrentFilterPosition ) + --m_nCurrentFilterPosition; + + OSL_POSTCOND( ( m_nCurrentFilterPosition < 0 ) == ( m_aFilterRows.empty() ), + "FormController::removeDisjunctiveTerm: inconsistency!" ); + + // update the texts in the filter controls + impl_setTextOnAllFilter_throw(); + + FilterEvent aEvent; + aEvent.Source = *this; + aEvent.DisjunctiveTerm = _Term; + aGuard.clear(); + // <-- SYNCHRONIZED + + m_aFilterListeners.notifyEach( &XFilterControllerListener::disjunctiveTermRemoved, aEvent ); +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::appendEmptyDisjunctiveTerm() throw (RuntimeException) +{ + // SYNCHRONIZED --> + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + impl_appendEmptyFilterRow( aGuard ); + // <-- SYNCHRONIZED +} + +//------------------------------------------------------------------------------ +::sal_Int32 SAL_CALL FormController::getActiveTerm() throw (RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + return m_nCurrentFilterPosition; +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::setActiveTerm( ::sal_Int32 _ActiveTerm ) throw (IndexOutOfBoundsException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + if ( ( _ActiveTerm < 0 ) || ( _ActiveTerm >= getDisjunctiveTerms() ) ) + throw IndexOutOfBoundsException( ::rtl::OUString(), *this ); + + if ( _ActiveTerm == getActiveTerm() ) + return; + + m_nCurrentFilterPosition = _ActiveTerm; + impl_setTextOnAllFilter_throw(); +} + +// XElementAccess +//------------------------------------------------------------------------------ +sal_Bool SAL_CALL FormController::hasElements(void) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + return !m_aChilds.empty(); +} + +//------------------------------------------------------------------------------ +Type SAL_CALL FormController::getElementType(void) throw( RuntimeException ) +{ + return ::getCppuType((const Reference< XFormController>*)0); + +} + +// XEnumerationAccess +//------------------------------------------------------------------------------ +Reference< XEnumeration > SAL_CALL FormController::createEnumeration(void) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + return new ::comphelper::OEnumerationByIndex(this); +} + +// XIndexAccess +//------------------------------------------------------------------------------ +sal_Int32 SAL_CALL FormController::getCount(void) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + return m_aChilds.size(); +} + +//------------------------------------------------------------------------------ +Any SAL_CALL FormController::getByIndex(sal_Int32 Index) throw( IndexOutOfBoundsException, WrappedTargetException, RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if (Index < 0 || + Index >= (sal_Int32)m_aChilds.size()) + throw IndexOutOfBoundsException(); + + return makeAny( m_aChilds[ Index ] ); +} + +// EventListener +//------------------------------------------------------------------------------ +void SAL_CALL FormController::disposing(const EventObject& e) throw( RuntimeException ) +{ + // Ist der Container disposed worden + ::osl::MutexGuard aGuard( m_aMutex ); + Reference< XControlContainer > xContainer(e.Source, UNO_QUERY); + if (xContainer.is()) + { + setContainer(Reference< XControlContainer > ()); + } + else + { + // ist ein Control disposed worden + Reference< XControl > xControl(e.Source, UNO_QUERY); + if (xControl.is()) + { + if (getContainer().is()) + removeControl(xControl); + } + } +} + +// OComponentHelper +//----------------------------------------------------------------------------- +void FormController::disposeAllFeaturesAndDispatchers() SAL_THROW(()) +{ + for ( DispatcherContainer::iterator aDispatcher = m_aFeatureDispatchers.begin(); + aDispatcher != m_aFeatureDispatchers.end(); + ++aDispatcher + ) + { + try + { + ::comphelper::disposeComponent( aDispatcher->second ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + m_aFeatureDispatchers.clear(); +} + +//----------------------------------------------------------------------------- +void FormController::disposing(void) +{ + EventObject aEvt( *this ); + + // if we're still active, simulate a "deactivated" event + if ( m_xActiveControl.is() ) + m_aActivateListeners.notifyEach( &XFormControllerListener::formDeactivated, aEvt ); + + // notify all our listeners + m_aActivateListeners.disposeAndClear(aEvt); + m_aModifyListeners.disposeAndClear(aEvt); + m_aErrorListeners.disposeAndClear(aEvt); + m_aDeleteListeners.disposeAndClear(aEvt); + m_aRowSetApproveListeners.disposeAndClear(aEvt); + m_aParameterListeners.disposeAndClear(aEvt); + m_aFilterListeners.disposeAndClear(aEvt); + + removeBoundFieldListener(); + stopFiltering(); + + m_pControlBorderManager->restoreAll(); + + m_aFilterRows.clear(); + + ::osl::MutexGuard aGuard( m_aMutex ); + m_xActiveControl = NULL; + implSetCurrentControl( NULL ); + + // clean up our children + for (FmFormControllers::const_iterator i = m_aChilds.begin(); + i != m_aChilds.end(); ++i) + { + // search the position of the model within the form + Reference< XFormComponent > xForm((*i)->getModel(), UNO_QUERY); + sal_uInt32 nPos = m_xModelAsIndex->getCount(); + Reference< XFormComponent > xTemp; + for( ; nPos; ) + { + + m_xModelAsIndex->getByIndex( --nPos ) >>= xTemp; + if ( xForm.get() == xTemp.get() ) + { + Reference< XInterface > xIfc( *i, UNO_QUERY ); + m_xModelAsManager->detach( nPos, xIfc ); + break; + } + } + + Reference< XComponent > (*i, UNO_QUERY)->dispose(); + } + m_aChilds.clear(); + + disposeAllFeaturesAndDispatchers(); + + if ( m_xFormOperations.is() ) + m_xFormOperations->dispose(); + m_xFormOperations.clear(); + + if (m_bDBConnection) + unload(); + + setContainer( NULL ); + setModel( NULL ); + setParent( NULL ); + + ::comphelper::disposeComponent( m_xComposer ); + + m_bDBConnection = sal_False; +} + +//------------------------------------------------------------------------------ +namespace +{ + static bool lcl_shouldUseDynamicControlBorder( const Reference< XInterface >& _rxForm, const Any& _rDynamicColorProp ) + { + bool bDoUse = false; + if ( !( _rDynamicColorProp >>= bDoUse ) ) + { + DocumentType eDocType = DocumentClassification::classifyHostDocument( _rxForm ); + return ControlLayouter::useDynamicBorderColor( eDocType ); + } + return bDoUse; + } +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::propertyChange(const PropertyChangeEvent& evt) throw( RuntimeException ) +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + if ( evt.PropertyName == FM_PROP_BOUNDFIELD ) + { + Reference<XPropertySet> xOldBound; + evt.OldValue >>= xOldBound; + if ( !xOldBound.is() && evt.NewValue.hasValue() ) + { + Reference< XControlModel > xControlModel(evt.Source,UNO_QUERY); + Reference< XControl > xControl = findControl(m_aControls,xControlModel,sal_False,sal_False); + if ( xControl.is() ) + { + startControlModifyListening( xControl ); + Reference<XPropertySet> xProp(xControlModel,UNO_QUERY); + if ( xProp.is() ) + xProp->removePropertyChangeListener(FM_PROP_BOUNDFIELD, this); + } + } + } + else + { + sal_Bool bModifiedChanged = (evt.PropertyName == FM_PROP_ISMODIFIED); + sal_Bool bNewChanged = (evt.PropertyName == FM_PROP_ISNEW); + if (bModifiedChanged || bNewChanged) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if (bModifiedChanged) + m_bCurrentRecordModified = ::comphelper::getBOOL(evt.NewValue); + else + m_bCurrentRecordNew = ::comphelper::getBOOL(evt.NewValue); + + // toggle the locking + if (m_bLocked != determineLockState()) + { + m_bLocked = !m_bLocked; + setLocks(); + if (isListeningForChanges()) + startListening(); + else + stopListening(); + } + + if ( bNewChanged ) + m_aToggleEvent.Call(); + + if (!m_bCurrentRecordModified) + m_bModified = sal_False; + } + else if ( evt.PropertyName == FM_PROP_DYNAMIC_CONTROL_BORDER ) + { + bool bEnable = lcl_shouldUseDynamicControlBorder( evt.Source, evt.NewValue ); + if ( bEnable ) + { + m_pControlBorderManager->enableDynamicBorderColor(); + if ( m_xActiveControl.is() ) + m_pControlBorderManager->focusGained( m_xActiveControl.get() ); + } + else + { + m_pControlBorderManager->disableDynamicBorderColor(); + } + } + } +} + +//------------------------------------------------------------------------------ +bool FormController::replaceControl( const Reference< XControl >& _rxExistentControl, const Reference< XControl >& _rxNewControl ) +{ + bool bSuccess = false; + try + { + Reference< XIdentifierReplace > xContainer( getContainer(), UNO_QUERY ); + DBG_ASSERT( xContainer.is(), "FormController::replaceControl: yes, it's not required by the service description, but XItentifierReplaces would be nice!" ); + if ( xContainer.is() ) + { + // look up the ID of _rxExistentControl + Sequence< sal_Int32 > aIdentifiers( xContainer->getIdentifiers() ); + const sal_Int32* pIdentifiers = aIdentifiers.getConstArray(); + const sal_Int32* pIdentifiersEnd = aIdentifiers.getConstArray() + aIdentifiers.getLength(); + for ( ; pIdentifiers != pIdentifiersEnd; ++pIdentifiers ) + { + Reference< XControl > xCheck( xContainer->getByIdentifier( *pIdentifiers ), UNO_QUERY ); + if ( xCheck == _rxExistentControl ) + break; + } + DBG_ASSERT( pIdentifiers != pIdentifiersEnd, "FormController::replaceControl: did not find the control in the container!" ); + if ( pIdentifiers != pIdentifiersEnd ) + { + bool bReplacedWasActive = ( m_xActiveControl.get() == _rxExistentControl.get() ); + bool bReplacedWasCurrent = ( m_xCurrentControl.get() == _rxExistentControl.get() ); + + if ( bReplacedWasActive ) + { + m_xActiveControl = NULL; + implSetCurrentControl( NULL ); + } + else if ( bReplacedWasCurrent ) + { + implSetCurrentControl( _rxNewControl ); + } + + // carry over the model + _rxNewControl->setModel( _rxExistentControl->getModel() ); + + xContainer->replaceByIdentifer( *pIdentifiers, makeAny( _rxNewControl ) ); + bSuccess = true; + + if ( bReplacedWasActive ) + { + Reference< XWindow > xControlWindow( _rxNewControl, UNO_QUERY ); + if ( xControlWindow.is() ) + xControlWindow->setFocus(); + } + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + Reference< XControl > xDisposeIt( bSuccess ? _rxExistentControl : _rxNewControl ); + ::comphelper::disposeComponent( xDisposeIt ); + return bSuccess; +} + +//------------------------------------------------------------------------------ +void FormController::toggleAutoFields(sal_Bool bAutoFields) +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + + + Sequence< Reference< XControl > > aControlsCopy( m_aControls ); + const Reference< XControl >* pControls = aControlsCopy.getConstArray(); + sal_Int32 nControls = aControlsCopy.getLength(); + + if (bAutoFields) + { + // as we don't want new controls to be attached to the scripting environment + // we change attach flags + m_bAttachEvents = sal_False; + for (sal_Int32 i = nControls; i > 0;) + { + Reference< XControl > xControl = pControls[--i]; + if (xControl.is()) + { + Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY); + if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet)) + { + // does the model use a bound field ? + Reference< XPropertySet > xField; + xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField; + + // is it a autofield? + if ( xField.is() + && ::comphelper::hasProperty( FM_PROP_AUTOINCREMENT, xField ) + && ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_AUTOINCREMENT ) ) + ) + { + replaceControl( xControl, new FmXAutoControl ); + } + } + } + } + m_bAttachEvents = sal_True; + } + else + { + m_bDetachEvents = sal_False; + for (sal_Int32 i = nControls; i > 0;) + { + Reference< XControl > xControl = pControls[--i]; + if (xControl.is()) + { + Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY); + if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet)) + { + // does the model use a bound field ? + Reference< XPropertySet > xField; + xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField; + + // is it a autofield? + if ( xField.is() + && ::comphelper::hasProperty( FM_PROP_AUTOINCREMENT, xField ) + && ::comphelper::getBOOL( xField->getPropertyValue(FM_PROP_AUTOINCREMENT ) ) + ) + { + ::rtl::OUString sServiceName; + OSL_VERIFY( xSet->getPropertyValue( FM_PROP_DEFAULTCONTROL ) >>= sServiceName ); + Reference< XControl > xNewControl( m_aContext.createComponent( sServiceName ), UNO_QUERY ); + replaceControl( xControl, xNewControl ); + } + } + } + } + m_bDetachEvents = sal_True; + } +} + +//------------------------------------------------------------------------------ +IMPL_LINK(FormController, OnToggleAutoFields, void*, EMPTYARG) +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + + toggleAutoFields(m_bCurrentRecordNew); + return 1L; +} + +// XTextListener +//------------------------------------------------------------------------------ +void SAL_CALL FormController::textChanged(const TextEvent& e) throw( RuntimeException ) +{ + // SYNCHRONIZED --> + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + if (m_bFiltering) + { + Reference< XTextComponent > xText(e.Source,UNO_QUERY); + ::rtl::OUString aText = xText->getText(); + + if ( m_aFilterRows.empty() ) + appendEmptyDisjunctiveTerm(); + + // Suchen der aktuellen Row + if ( ( (size_t)m_nCurrentFilterPosition >= m_aFilterRows.size() ) || ( m_nCurrentFilterPosition < 0 ) ) + { + OSL_ENSURE( false, "FormController::textChanged: m_nCurrentFilterPosition is wrong!" ); + return; + } + + FmFilterRow& rRow = m_aFilterRows[ m_nCurrentFilterPosition ]; + + // do we have a new filter + if (aText.getLength()) + rRow[xText] = aText; + else + { + // do we have the control in the row + FmFilterRow::iterator iter = rRow.find(xText); + // erase the entry out of the row + if (iter != rRow.end()) + rRow.erase(iter); + } + + // multiplex the event to our FilterControllerListeners + FilterEvent aEvent; + aEvent.Source = *this; + aEvent.FilterComponent = ::std::find( m_aFilterComponents.begin(), m_aFilterComponents.end(), xText ) - m_aFilterComponents.begin(); + aEvent.DisjunctiveTerm = getActiveTerm(); + aEvent.PredicateExpression = aText; + + aGuard.clear(); + // <-- SYNCHRONIZED + + // notify the changed filter expression + m_aFilterListeners.notifyEach( &XFilterControllerListener::predicateExpressionChanged, aEvent ); + } + else + impl_onModify(); +} + +// XItemListener +//------------------------------------------------------------------------------ +void SAL_CALL FormController::itemStateChanged(const ItemEvent& /*rEvent*/) throw( RuntimeException ) +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + impl_onModify(); +} + +// XModificationBroadcaster +//------------------------------------------------------------------------------ +void SAL_CALL FormController::addModifyListener(const Reference< XModifyListener > & l) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + m_aModifyListeners.addInterface( l ); +} + +//------------------------------------------------------------------------------ +void FormController::removeModifyListener(const Reference< XModifyListener > & l) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + m_aModifyListeners.removeInterface( l ); +} + +// XModificationListener +//------------------------------------------------------------------------------ +void FormController::modified( const EventObject& _rEvent ) throw( RuntimeException ) +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + + try + { + if ( _rEvent.Source != m_xActiveControl ) + { // let this control grab the focus + // (this case may happen if somebody moves the scroll wheel of the mouse over a control + // which does not have the focus) + // 85511 - 29.05.2001 - frank.schoenheit@germany.sun.com + // + // also, it happens when an image control gets a new image by double-clicking it + // #i88458# / 2009-01-12 / frank.schoenheit@sun.com + Reference< XWindow > xControlWindow( _rEvent.Source, UNO_QUERY_THROW ); + xControlWindow->setFocus(); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + impl_onModify(); +} + +//------------------------------------------------------------------------------ +void FormController::impl_checkDisposed_throw() const +{ + if ( impl_isDisposed_nofail() ) + throw DisposedException( ::rtl::OUString(), *const_cast< FormController* >( this ) ); +} + +//------------------------------------------------------------------------------ +void FormController::impl_onModify() +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_bModified ) + m_bModified = sal_True; + } + + EventObject aEvt(static_cast<cppu::OWeakObject*>(this)); + m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvt ); +} + +//------------------------------------------------------------------------------ +void FormController::impl_addFilterRow( const FmFilterRow& _row ) +{ + m_aFilterRows.push_back( _row ); + + if ( m_aFilterRows.size() == 1 ) + { // that's the first row ever + OSL_ENSURE( m_nCurrentFilterPosition == -1, "FormController::impl_addFilterRow: inconsistency!" ); + m_nCurrentFilterPosition = 0; + } +} + +//------------------------------------------------------------------------------ +void FormController::impl_appendEmptyFilterRow( ::osl::ClearableMutexGuard& _rClearBeforeNotify ) +{ + // SYNCHRONIZED --> + impl_addFilterRow( FmFilterRow() ); + + // notify the listeners + FilterEvent aEvent; + aEvent.Source = *this; + aEvent.DisjunctiveTerm = (sal_Int32)m_aFilterRows.size() - 1; + _rClearBeforeNotify.clear(); + // <-- SYNCHRONIZED + m_aFilterListeners.notifyEach( &XFilterControllerListener::disjunctiveTermAdded, aEvent ); +} + +//------------------------------------------------------------------------------ +sal_Bool FormController::determineLockState() const +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + // a.) in filter mode we are always locked + // b.) if we have no valid model or our model (a result set) is not alive -> we're locked + // c.) if we are inserting everything is OK and we are not locked + // d.) if are not updatable or on invalid position + Reference< XResultSet > xResultSet(m_xModelAsIndex, UNO_QUERY); + if (m_bFiltering || !xResultSet.is() || !isRowSetAlive(xResultSet)) + return sal_True; + else + return (m_bCanInsert && m_bCurrentRecordNew) ? sal_False + : xResultSet->isBeforeFirst() || xResultSet->isAfterLast() || xResultSet->rowDeleted() || !m_bCanUpdate; +} + +// FocusListener +//------------------------------------------------------------------------------ +void FormController::focusGained(const FocusEvent& e) throw( RuntimeException ) +{ + // SYNCHRONIZED --> + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + m_pControlBorderManager->focusGained( e.Source ); + + Reference< XControl > xControl(e.Source, UNO_QUERY); + if (m_bDBConnection) + { + // do we need to keep the locking of the commit + // we hold the lock as long as the control differs from the current + // otherwhise we disabled the lock + m_bCommitLock = m_bCommitLock && (XControl*)xControl.get() != (XControl*)m_xCurrentControl.get(); + if (m_bCommitLock) + return; + + // when do we have to commit a value to form or a filter + // a.) if the current value is modified + // b.) there must be a current control + // c.) and it must be different from the new focus owning control or + // d.) the focus is moving around (so we have only one control) + + if ( ( m_bModified || m_bFiltering ) + && m_xCurrentControl.is() + && ( ( xControl.get() != m_xCurrentControl.get() ) + || ( ( e.FocusFlags & FocusChangeReason::AROUND ) + && ( m_bCycle || m_bFiltering ) + ) + ) + ) + { + // check the old control if the content is ok +#if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL + Reference< XBoundControl > xLockingTest(m_xCurrentControl, UNO_QUERY); + sal_Bool bControlIsLocked = xLockingTest.is() && xLockingTest->getLock(); + OSL_ENSURE(!bControlIsLocked, "FormController::Gained: I'm modified and the current control is locked ? How this ?"); + // normalerweise sollte ein gelocktes Control nicht modified sein, also muss wohl mein bModified aus einem anderen Kontext + // gesetzt worden sein, was ich nicht verstehen wuerde ... +#endif + DBG_ASSERT(m_xCurrentControl.is(), "kein CurrentControl gesetzt"); + // zunaechst das Control fragen ob es das IFace unterstuetzt + Reference< XBoundComponent > xBound(m_xCurrentControl, UNO_QUERY); + if (!xBound.is() && m_xCurrentControl.is()) + xBound = Reference< XBoundComponent > (m_xCurrentControl->getModel(), UNO_QUERY); + + // lock if we lose the focus during commit + m_bCommitLock = sal_True; + + // Commit nicht erfolgreich, Focus zuruecksetzen + if (xBound.is() && !xBound->commit()) + { + // the commit failed and we don't commit again until the current control + // which couldn't be commit gains the focus again + Reference< XWindow > xWindow(m_xCurrentControl, UNO_QUERY); + if (xWindow.is()) + xWindow->setFocus(); + return; + } + else + { + m_bModified = sal_False; + m_bCommitLock = sal_False; + } + } + + if (!m_bFiltering && m_bCycle && (e.FocusFlags & FocusChangeReason::AROUND) && m_xCurrentControl.is()) + { + SQLErrorEvent aErrorEvent; + OSL_ENSURE( m_xFormOperations.is(), "FormController::focusGained: hmm?" ); + // should have been created in setModel + try + { + if ( e.FocusFlags & FocusChangeReason::FORWARD ) + { + if ( m_xFormOperations.is() && m_xFormOperations->isEnabled( FormFeature::MoveToNext ) ) + m_xFormOperations->execute( FormFeature::MoveToNext ); + } + else // backward + { + if ( m_xFormOperations.is() && m_xFormOperations->isEnabled( FormFeature::MoveToPrevious ) ) + m_xFormOperations->execute( FormFeature::MoveToPrevious ); + } + } + catch ( const Exception& ) + { + // don't handle this any further. That's an ... admissible error. + DBG_UNHANDLED_EXCEPTION(); + } + } + } + + // Immer noch ein und dasselbe Control + if ( ( m_xActiveControl == xControl ) + && ( xControl == m_xCurrentControl ) + ) + { + DBG_ASSERT(m_xCurrentControl.is(), "Kein CurrentControl selektiert"); + return; + } + + sal_Bool bActivated = !m_xActiveControl.is() && xControl.is(); + + m_xActiveControl = xControl; + + implSetCurrentControl( xControl ); + OSL_POSTCOND( m_xCurrentControl.is(), "implSetCurrentControl did nonsense!" ); + + if ( bActivated ) + { + // (asynchronously) call activation handlers + m_aActivationEvent.Call(); + + // call modify listeners + if ( m_bModified ) + m_aModifyListeners.notifyEach( &XModifyListener::modified, EventObject( *this ) ); + } + + // invalidate all features which depend on the currently focused control + if ( m_bDBConnection && !m_bFiltering ) + implInvalidateCurrentControlDependentFeatures(); + + if ( !m_xCurrentControl.is() ) + return; + + // Control erhaelt Focus, dann eventuell in den sichtbaren Bereich + Reference< XFormControllerContext > xContext( m_xContext ); + Reference< XControl > xCurrentControl( m_xCurrentControl ); + aGuard.clear(); + // <-- SYNCHRONIZED + + if ( xContext.is() ) + xContext->makeVisible( xCurrentControl ); +} + +//------------------------------------------------------------------------------ +IMPL_LINK( FormController, OnActivated, void*, /**/ ) +{ + EventObject aEvent; + aEvent.Source = *this; + m_aActivateListeners.notifyEach( &XFormControllerListener::formActivated, aEvent ); + + return 0L; +} + +//------------------------------------------------------------------------------ +IMPL_LINK( FormController, OnDeactivated, void*, /**/ ) +{ + EventObject aEvent; + aEvent.Source = *this; + m_aActivateListeners.notifyEach( &XFormControllerListener::formDeactivated, aEvent ); + + return 0L; +} + +//------------------------------------------------------------------------------ +void FormController::focusLost(const FocusEvent& e) throw( RuntimeException ) +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + + m_pControlBorderManager->focusLost( e.Source ); + + Reference< XControl > xControl(e.Source, UNO_QUERY); + Reference< XWindowPeer > xNext(e.NextFocus, UNO_QUERY); + Reference< XControl > xNextControl = isInList(xNext); + if (!xNextControl.is()) + { + m_xActiveControl = NULL; + m_aDeactivationEvent.Call(); + } +} + +//-------------------------------------------------------------------- +void SAL_CALL FormController::mousePressed( const awt::MouseEvent& /*_rEvent*/ ) throw (RuntimeException) +{ + // not interested in +} + +//-------------------------------------------------------------------- +void SAL_CALL FormController::mouseReleased( const awt::MouseEvent& /*_rEvent*/ ) throw (RuntimeException) +{ + // not interested in +} + +//-------------------------------------------------------------------- +void SAL_CALL FormController::mouseEntered( const awt::MouseEvent& _rEvent ) throw (RuntimeException) +{ + m_pControlBorderManager->mouseEntered( _rEvent.Source ); +} + +//-------------------------------------------------------------------- +void SAL_CALL FormController::mouseExited( const awt::MouseEvent& _rEvent ) throw (RuntimeException) +{ + m_pControlBorderManager->mouseExited( _rEvent.Source ); +} + +//-------------------------------------------------------------------- +void SAL_CALL FormController::componentValidityChanged( const EventObject& _rSource ) throw (RuntimeException) +{ + Reference< XControl > xControl( findControl( m_aControls, Reference< XControlModel >( _rSource.Source, UNO_QUERY ), sal_False, sal_False ) ); + Reference< XValidatableFormComponent > xValidatable( _rSource.Source, UNO_QUERY ); + + OSL_ENSURE( xControl.is() && xValidatable.is(), "FormController::componentValidityChanged: huh?" ); + + if ( xControl.is() && xValidatable.is() ) + m_pControlBorderManager->validityChanged( xControl, xValidatable ); +} + +//-------------------------------------------------------------------- +void FormController::setModel(const Reference< XTabControllerModel > & Model) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + DBG_ASSERT(m_xTabController.is(), "FormController::setModel : invalid aggregate !"); + + try + { + // disconnect from the old model + if (m_xModelAsIndex.is()) + { + if (m_bDBConnection) + { + // we are currently working on the model + EventObject aEvt(m_xModelAsIndex); + unloaded(aEvt); + } + + Reference< XLoadable > xForm(m_xModelAsIndex, UNO_QUERY); + if (xForm.is()) + xForm->removeLoadListener(this); + + Reference< XSQLErrorBroadcaster > xBroadcaster(m_xModelAsIndex, UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removeSQLErrorListener(this); + + Reference< XDatabaseParameterBroadcaster > xParamBroadcaster(m_xModelAsIndex, UNO_QUERY); + if (xParamBroadcaster.is()) + xParamBroadcaster->removeParameterListener(this); + + } + + disposeAllFeaturesAndDispatchers(); + + if ( m_xFormOperations.is() ) + m_xFormOperations->dispose(); + m_xFormOperations.clear(); + + // set the new model wait for the load event + if (m_xTabController.is()) + m_xTabController->setModel(Model); + m_xModelAsIndex = Reference< XIndexAccess > (Model, UNO_QUERY); + m_xModelAsManager = Reference< XEventAttacherManager > (Model, UNO_QUERY); + + // only if both ifaces exit, the controller will work successful + if (!m_xModelAsIndex.is() || !m_xModelAsManager.is()) + { + m_xModelAsManager = NULL; + m_xModelAsIndex = NULL; + } + + if (m_xModelAsIndex.is()) + { + // re-create m_xFormOperations + m_xFormOperations.set( FormOperations::createWithFormController( m_aContext.getUNOContext(), this ), UNO_SET_THROW ); + m_xFormOperations->setFeatureInvalidation( this ); + + // adding load and ui interaction listeners + Reference< XLoadable > xForm(Model, UNO_QUERY); + if (xForm.is()) + xForm->addLoadListener(this); + + Reference< XSQLErrorBroadcaster > xBroadcaster(Model, UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addSQLErrorListener(this); + + Reference< XDatabaseParameterBroadcaster > xParamBroadcaster(Model, UNO_QUERY); + if (xParamBroadcaster.is()) + xParamBroadcaster->addParameterListener(this); + + // well, is the database already loaded? + // then we have to simulate a load event + Reference< XLoadable > xCursor(m_xModelAsIndex, UNO_QUERY); + if (xCursor.is() && xCursor->isLoaded()) + { + EventObject aEvt(xCursor); + loaded(aEvt); + } + + Reference< XPropertySet > xModelProps( m_xModelAsIndex, UNO_QUERY ); + Reference< XPropertySetInfo > xPropInfo( xModelProps->getPropertySetInfo() ); + if ( xPropInfo.is() + && xPropInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER ) + && xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_FOCUS ) + && xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_MOUSE ) + && xPropInfo->hasPropertyByName( FM_PROP_CONTROL_BORDER_COLOR_INVALID ) + ) + { + bool bEnableDynamicControlBorder = lcl_shouldUseDynamicControlBorder( + xModelProps.get(), xModelProps->getPropertyValue( FM_PROP_DYNAMIC_CONTROL_BORDER ) ); + if ( bEnableDynamicControlBorder ) + m_pControlBorderManager->enableDynamicBorderColor(); + else + m_pControlBorderManager->disableDynamicBorderColor(); + + sal_Int32 nColor = 0; + if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_FOCUS ) >>= nColor ) + m_pControlBorderManager->setStatusColor( CONTROL_STATUS_FOCUSED, nColor ); + if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_MOUSE ) >>= nColor ) + m_pControlBorderManager->setStatusColor( CONTROL_STATUS_MOUSE_HOVER, nColor ); + if ( xModelProps->getPropertyValue( FM_PROP_CONTROL_BORDER_COLOR_INVALID ) >>= nColor ) + m_pControlBorderManager->setStatusColor( CONTROL_STATUS_INVALID, nColor ); + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +//------------------------------------------------------------------------------ +Reference< XTabControllerModel > FormController::getModel() throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + DBG_ASSERT(m_xTabController.is(), "FormController::getModel : invalid aggregate !"); + if (!m_xTabController.is()) + return Reference< XTabControllerModel > (); + return m_xTabController->getModel(); +} + +//------------------------------------------------------------------------------ +void FormController::addToEventAttacher(const Reference< XControl > & xControl) +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + OSL_ENSURE( xControl.is(), "FormController::addToEventAttacher: invalid control - how did you reach this?" ); + if ( !xControl.is() ) + return; /* throw IllegalArgumentException(); */ + + // anmelden beim Eventattacher + Reference< XFormComponent > xComp(xControl->getModel(), UNO_QUERY); + if (xComp.is() && m_xModelAsIndex.is()) + { + // Und die Position des ControlModel darin suchen + sal_uInt32 nPos = m_xModelAsIndex->getCount(); + Reference< XFormComponent > xTemp; + for( ; nPos; ) + { + m_xModelAsIndex->getByIndex(--nPos) >>= xTemp; + if ((XFormComponent*)xComp.get() == (XFormComponent*)xTemp.get()) + { + Reference< XInterface > xIfc(xControl, UNO_QUERY); + m_xModelAsManager->attach( nPos, xIfc, makeAny(xControl) ); + break; + } + } + } +} + +//------------------------------------------------------------------------------ +void FormController::removeFromEventAttacher(const Reference< XControl > & xControl) +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + OSL_ENSURE( xControl.is(), "FormController::removeFromEventAttacher: invalid control - how did you reach this?" ); + if ( !xControl.is() ) + return; /* throw IllegalArgumentException(); */ + + // abmelden beim Eventattacher + Reference< XFormComponent > xComp(xControl->getModel(), UNO_QUERY); + if ( xComp.is() && m_xModelAsIndex.is() ) + { + // Und die Position des ControlModel darin suchen + sal_uInt32 nPos = m_xModelAsIndex->getCount(); + Reference< XFormComponent > xTemp; + for( ; nPos; ) + { + m_xModelAsIndex->getByIndex(--nPos) >>= xTemp; + if ((XFormComponent*)xComp.get() == (XFormComponent*)xTemp.get()) + { + Reference< XInterface > xIfc(xControl, UNO_QUERY); + m_xModelAsManager->detach( nPos, xIfc ); + break; + } + } + } +} + +//------------------------------------------------------------------------------ +void FormController::setContainer(const Reference< XControlContainer > & xContainer) throw( RuntimeException ) +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + Reference< XTabControllerModel > xTabModel(getModel()); + DBG_ASSERT(xTabModel.is() || !xContainer.is(), "No Model defined"); + // if we have a new container we need a model + DBG_ASSERT(m_xTabController.is(), "FormController::setContainer : invalid aggregate !"); + + ::osl::MutexGuard aGuard( m_aMutex ); + Reference< XContainer > xCurrentContainer; + if (m_xTabController.is()) + xCurrentContainer = Reference< XContainer > (m_xTabController->getContainer(), UNO_QUERY); + if (xCurrentContainer.is()) + { + xCurrentContainer->removeContainerListener(this); + + if ( m_aTabActivationTimer.IsActive() ) + m_aTabActivationTimer.Stop(); + + // clear the filter map + ::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), RemoveComponentTextListener( this ) ); + m_aFilterComponents.clear(); + + // einsammeln der Controls + const Reference< XControl >* pControls = m_aControls.getConstArray(); + const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength(); + while ( pControls != pControlsEnd ) + implControlRemoved( *pControls++, true ); + + // Datenbank spezifische Dinge vornehmen + if (m_bDBConnection && isListeningForChanges()) + stopListening(); + + m_aControls.realloc( 0 ); + } + + if (m_xTabController.is()) + m_xTabController->setContainer(xContainer); + + // Welche Controls gehoeren zum Container ? + if (xContainer.is() && xTabModel.is()) + { + Sequence< Reference< XControlModel > > aModels = xTabModel->getControlModels(); + const Reference< XControlModel > * pModels = aModels.getConstArray(); + Sequence< Reference< XControl > > aAllControls = xContainer->getControls(); + + sal_Int32 nCount = aModels.getLength(); + m_aControls = Sequence< Reference< XControl > >( nCount ); + Reference< XControl > * pControls = m_aControls.getArray(); + + // einsammeln der Controls + sal_Int32 i, j; + for (i = 0, j = 0; i < nCount; ++i, ++pModels ) + { + Reference< XControl > xControl = findControl( aAllControls, *pModels, sal_False, sal_True ); + if ( xControl.is() ) + { + pControls[j++] = xControl; + implControlInserted( xControl, true ); + } + } + + // not every model had an associated control + if (j != i) + m_aControls.realloc(j); + + // am Container horchen + Reference< XContainer > xNewContainer(xContainer, UNO_QUERY); + if (xNewContainer.is()) + xNewContainer->addContainerListener(this); + + // Datenbank spezifische Dinge vornehmen + if (m_bDBConnection) + { + m_bLocked = determineLockState(); + setLocks(); + if (!isLocked()) + startListening(); + } + } + // befinden sich die Controls in der richtigen Reihenfolge + m_bControlsSorted = sal_True; +} + +//------------------------------------------------------------------------------ +Reference< XControlContainer > FormController::getContainer() throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + DBG_ASSERT(m_xTabController.is(), "FormController::getContainer : invalid aggregate !"); + if (!m_xTabController.is()) + return Reference< XControlContainer > (); + return m_xTabController->getContainer(); +} + +//------------------------------------------------------------------------------ +Sequence< Reference< XControl > > FormController::getControls(void) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + if (!m_bControlsSorted) + { + Reference< XTabControllerModel > xModel = getModel(); + if (!xModel.is()) + return m_aControls; + + Sequence< Reference< XControlModel > > aControlModels = xModel->getControlModels(); + const Reference< XControlModel > * pModels = aControlModels.getConstArray(); + sal_Int32 nModels = aControlModels.getLength(); + + Sequence< Reference< XControl > > aNewControls(nModels); + + Reference< XControl > * pControls = aNewControls.getArray(); + Reference< XControl > xControl; + + // Umsortieren der Controls entsprechend der TabReihenfolge + sal_Int32 j = 0; + for (sal_Int32 i = 0; i < nModels; ++i, ++pModels ) + { + xControl = findControl( m_aControls, *pModels, sal_True, sal_True ); + if ( xControl.is() ) + pControls[j++] = xControl; + } + + // not every model had an associated control + if ( j != nModels ) + aNewControls.realloc( j ); + + m_aControls = aNewControls; + m_bControlsSorted = sal_True; + } + return m_aControls; +} + +//------------------------------------------------------------------------------ +void FormController::autoTabOrder() throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + DBG_ASSERT(m_xTabController.is(), "FormController::autoTabOrder : invalid aggregate !"); + if (m_xTabController.is()) + m_xTabController->autoTabOrder(); +} + +//------------------------------------------------------------------------------ +void FormController::activateTabOrder() throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + DBG_ASSERT(m_xTabController.is(), "FormController::activateTabOrder : invalid aggregate !"); + if (m_xTabController.is()) + m_xTabController->activateTabOrder(); +} + +//------------------------------------------------------------------------------ +void FormController::setControlLock(const Reference< XControl > & xControl) +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + sal_Bool bLocked = isLocked(); + + // es wird gelockt + // a.) wenn der ganze Datensatz gesperrt ist + // b.) wenn das zugehoerige Feld gespeert ist + Reference< XBoundControl > xBound(xControl, UNO_QUERY); + if (xBound.is() && (( (bLocked && bLocked != xBound->getLock()) || + !bLocked))) // beim entlocken immer einzelne Felder ueberprüfen + { + // gibt es eine Datenquelle + Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY); + if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet)) + { + // wie sieht mit den Properties ReadOnly und Enable aus + sal_Bool bTouch = sal_True; + if (::comphelper::hasProperty(FM_PROP_ENABLED, xSet)) + bTouch = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ENABLED)); + if (::comphelper::hasProperty(FM_PROP_READONLY, xSet)) + bTouch = !::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_READONLY)); + + if (bTouch) + { + Reference< XPropertySet > xField; + xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField; + if (xField.is()) + { + if (bLocked) + xBound->setLock(bLocked); + else + { + try + { + Any aVal = xField->getPropertyValue(FM_PROP_ISREADONLY); + if (aVal.hasValue() && ::comphelper::getBOOL(aVal)) + xBound->setLock(sal_True); + else + xBound->setLock(bLocked); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + } + } + } + } + } +} + +//------------------------------------------------------------------------------ +void FormController::setLocks() +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + // alle Controls, die mit einer Datenquelle verbunden sind locken/unlocken + const Reference< XControl >* pControls = m_aControls.getConstArray(); + const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength(); + while ( pControls != pControlsEnd ) + setControlLock( *pControls++ ); +} + +//------------------------------------------------------------------------------ +namespace +{ + bool lcl_shouldListenForModifications( const Reference< XControl >& _rxControl, const Reference< XPropertyChangeListener >& _rxBoundFieldListener ) + { + bool bShould = false; + + Reference< XBoundComponent > xBound( _rxControl, UNO_QUERY ); + if ( xBound.is() ) + { + bShould = true; + } + else if ( _rxControl.is() ) + { + Reference< XPropertySet > xModelProps( _rxControl->getModel(), UNO_QUERY ); + if ( xModelProps.is() && ::comphelper::hasProperty( FM_PROP_BOUNDFIELD, xModelProps ) ) + { + Reference< XPropertySet > xField; + xModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ) >>= xField; + bShould = xField.is(); + + if ( !bShould && _rxBoundFieldListener.is() ) + xModelProps->addPropertyChangeListener( FM_PROP_BOUNDFIELD, _rxBoundFieldListener ); + } + } + + return bShould; + } +} + +//------------------------------------------------------------------------------ +void FormController::startControlModifyListening(const Reference< XControl > & xControl) +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + + bool bModifyListening = lcl_shouldListenForModifications( xControl, this ); + + // artificial while + while ( bModifyListening ) + { + Reference< XModifyBroadcaster > xMod(xControl, UNO_QUERY); + if (xMod.is()) + { + xMod->addModifyListener(this); + break; + } + + // alle die Text um vorzeitig ein modified zu erkennen + Reference< XTextComponent > xText(xControl, UNO_QUERY); + if (xText.is()) + { + xText->addTextListener(this); + break; + } + + Reference< XCheckBox > xBox(xControl, UNO_QUERY); + if (xBox.is()) + { + xBox->addItemListener(this); + break; + } + + Reference< XComboBox > xCbBox(xControl, UNO_QUERY); + if (xCbBox.is()) + { + xCbBox->addItemListener(this); + break; + } + + Reference< XListBox > xListBox(xControl, UNO_QUERY); + if (xListBox.is()) + { + xListBox->addItemListener(this); + break; + } + break; + } +} + +//------------------------------------------------------------------------------ +void FormController::stopControlModifyListening(const Reference< XControl > & xControl) +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + + bool bModifyListening = lcl_shouldListenForModifications( xControl, NULL ); + + // kuenstliches while + while (bModifyListening) + { + Reference< XModifyBroadcaster > xMod(xControl, UNO_QUERY); + if (xMod.is()) + { + xMod->removeModifyListener(this); + break; + } + // alle die Text um vorzeitig ein modified zu erkennen + Reference< XTextComponent > xText(xControl, UNO_QUERY); + if (xText.is()) + { + xText->removeTextListener(this); + break; + } + + Reference< XCheckBox > xBox(xControl, UNO_QUERY); + if (xBox.is()) + { + xBox->removeItemListener(this); + break; + } + + Reference< XComboBox > xCbBox(xControl, UNO_QUERY); + if (xCbBox.is()) + { + xCbBox->removeItemListener(this); + break; + } + + Reference< XListBox > xListBox(xControl, UNO_QUERY); + if (xListBox.is()) + { + xListBox->removeItemListener(this); + break; + } + break; + } +} + +//------------------------------------------------------------------------------ +void FormController::startListening() +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + m_bModified = sal_False; + + // jetzt anmelden bei gebundenen feldern + const Reference< XControl >* pControls = m_aControls.getConstArray(); + const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength(); + while ( pControls != pControlsEnd ) + startControlModifyListening( *pControls++ ); +} + +//------------------------------------------------------------------------------ +void FormController::stopListening() +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + m_bModified = sal_False; + + // jetzt anmelden bei gebundenen feldern + const Reference< XControl >* pControls = m_aControls.getConstArray(); + const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength(); + while ( pControls != pControlsEnd ) + stopControlModifyListening( *pControls++ ); +} + + +//------------------------------------------------------------------------------ +Reference< XControl > FormController::findControl(Sequence< Reference< XControl > >& _rControls, const Reference< XControlModel > & xCtrlModel ,sal_Bool _bRemove,sal_Bool _bOverWrite) const +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + DBG_ASSERT( xCtrlModel.is(), "findControl - welches ?!" ); + + Reference< XControl >* pControls = _rControls.getArray(); + Reference< XControlModel > xModel; + for ( sal_Int32 i = 0, nCount = _rControls.getLength(); i < nCount; ++i, ++pControls ) + { + if ( pControls->is() ) + { + xModel = (*pControls)->getModel(); + if ( xModel.get() == xCtrlModel.get() ) + { + Reference< XControl > xControl( *pControls ); + if ( _bRemove ) + ::comphelper::removeElementAt( _rControls, i ); + else if ( _bOverWrite ) + *pControls = Reference< XControl >(); + return xControl; + } + } + } + return Reference< XControl > (); +} + +//------------------------------------------------------------------------------ +void FormController::implControlInserted( const Reference< XControl>& _rxControl, bool _bAddToEventAttacher ) +{ + Reference< XWindow > xWindow( _rxControl, UNO_QUERY ); + if ( xWindow.is() ) + { + xWindow->addFocusListener( this ); + xWindow->addMouseListener( this ); + + if ( _bAddToEventAttacher ) + addToEventAttacher( _rxControl ); + } + + // add a dispatch interceptor to the control (if supported) + Reference< XDispatchProviderInterception > xInterception( _rxControl, UNO_QUERY ); + if ( xInterception.is() ) + createInterceptor( xInterception ); + + if ( _rxControl.is() ) + { + Reference< XControlModel > xModel( _rxControl->getModel() ); + + // we want to know about the reset of the the model of our controls + // (for correctly resetting m_bModified) + Reference< XReset > xReset( xModel, UNO_QUERY ); + if ( xReset.is() ) + xReset->addResetListener( this ); + + // and we want to know about the validity, to visually indicate it + Reference< XValidatableFormComponent > xValidatable( xModel, UNO_QUERY ); + if ( xValidatable.is() ) + { + xValidatable->addFormComponentValidityListener( this ); + m_pControlBorderManager->validityChanged( _rxControl, xValidatable ); + } + } + +} + +//------------------------------------------------------------------------------ +void FormController::implControlRemoved( const Reference< XControl>& _rxControl, bool _bRemoveFromEventAttacher ) +{ + Reference< XWindow > xWindow( _rxControl, UNO_QUERY ); + if ( xWindow.is() ) + { + xWindow->removeFocusListener( this ); + xWindow->removeMouseListener( this ); + + if ( _bRemoveFromEventAttacher ) + removeFromEventAttacher( _rxControl ); + } + + Reference< XDispatchProviderInterception > xInterception( _rxControl, UNO_QUERY); + if ( xInterception.is() ) + deleteInterceptor( xInterception ); + + if ( _rxControl.is() ) + { + Reference< XControlModel > xModel( _rxControl->getModel() ); + + Reference< XReset > xReset( xModel, UNO_QUERY ); + if ( xReset.is() ) + xReset->removeResetListener( this ); + + Reference< XValidatableFormComponent > xValidatable( xModel, UNO_QUERY ); + if ( xValidatable.is() ) + xValidatable->removeFormComponentValidityListener( this ); + } +} + +//------------------------------------------------------------------------------ +void FormController::implSetCurrentControl( const Reference< XControl >& _rxControl ) +{ + if ( m_xCurrentControl.get() == _rxControl.get() ) + return; + + Reference< XGridControl > xGridControl( m_xCurrentControl, UNO_QUERY ); + if ( xGridControl.is() ) + xGridControl->removeGridControlListener( this ); + + m_xCurrentControl = _rxControl; + + xGridControl.set( m_xCurrentControl, UNO_QUERY ); + if ( xGridControl.is() ) + xGridControl->addGridControlListener( this ); +} + +//------------------------------------------------------------------------------ +void FormController::insertControl(const Reference< XControl > & xControl) +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + m_bControlsSorted = sal_False; + m_aControls.realloc(m_aControls.getLength() + 1); + m_aControls.getArray()[m_aControls.getLength() - 1] = xControl; + + if ( m_pColumnInfoCache.get() ) + m_pColumnInfoCache->deinitializeControls(); + + implControlInserted( xControl, m_bAttachEvents ); + + if (m_bDBConnection && !m_bFiltering) + setControlLock(xControl); + + if (isListeningForChanges() && m_bAttachEvents) + startControlModifyListening( xControl ); +} + +//------------------------------------------------------------------------------ +void FormController::removeControl(const Reference< XControl > & xControl) +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + const Reference< XControl >* pControls = m_aControls.getConstArray(); + const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength(); + while ( pControls != pControlsEnd ) + { + if ( xControl.get() == (*pControls++).get() ) + { + ::comphelper::removeElementAt( m_aControls, pControls - m_aControls.getConstArray() - 1 ); + break; + } + } + + FilterComponents::iterator componentPos = ::std::find( m_aFilterComponents.begin(), m_aFilterComponents.end(), xControl ); + if ( componentPos != m_aFilterComponents.end() ) + m_aFilterComponents.erase( componentPos ); + + implControlRemoved( xControl, m_bDetachEvents ); + + if ( isListeningForChanges() && m_bDetachEvents ) + stopControlModifyListening( xControl ); +} + +// XLoadListener +//------------------------------------------------------------------------------ +void FormController::loaded(const EventObject& rEvent) throw( RuntimeException ) +{ + OSL_ENSURE( rEvent.Source == m_xModelAsIndex, "FormController::loaded: where did this come from?" ); + + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + ::osl::MutexGuard aGuard( m_aMutex ); + Reference< XRowSet > xForm(rEvent.Source, UNO_QUERY); + // do we have a connected data source + OStaticDataAccessTools aStaticTools; + if (xForm.is() && aStaticTools.getRowSetConnection(xForm).is()) + { + Reference< XPropertySet > xSet(xForm, UNO_QUERY); + if (xSet.is()) + { + Any aVal = xSet->getPropertyValue(FM_PROP_CYCLE); + sal_Int32 aVal2 = 0; + ::cppu::enum2int(aVal2,aVal); + m_bCycle = !aVal.hasValue() || aVal2 == TabulatorCycle_RECORDS; + m_bCanUpdate = aStaticTools.canUpdate(xSet); + m_bCanInsert = aStaticTools.canInsert(xSet); + m_bCurrentRecordModified = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISMODIFIED)); + m_bCurrentRecordNew = ::comphelper::getBOOL(xSet->getPropertyValue(FM_PROP_ISNEW)); + + startFormListening( xSet, sal_False ); + + // set the locks for the current controls + if (getContainer().is()) + { + m_aLoadEvent.Call(); + } + } + else + { + m_bCanInsert = m_bCanUpdate = m_bCycle = sal_False; + m_bCurrentRecordModified = sal_False; + m_bCurrentRecordNew = sal_False; + m_bLocked = sal_False; + } + m_bDBConnection = sal_True; + } + else + { + m_bDBConnection = sal_False; + m_bCanInsert = m_bCanUpdate = m_bCycle = sal_False; + m_bCurrentRecordModified = sal_False; + m_bCurrentRecordNew = sal_False; + m_bLocked = sal_False; + } + + Reference< XColumnsSupplier > xFormColumns( xForm, UNO_QUERY ); + m_pColumnInfoCache.reset( xFormColumns.is() ? new ColumnInfoCache( xFormColumns ) : NULL ); + + updateAllDispatchers(); +} + +//------------------------------------------------------------------------------ +void FormController::updateAllDispatchers() const +{ + ::std::for_each( + m_aFeatureDispatchers.begin(), + m_aFeatureDispatchers.end(), + ::std::compose1( + UpdateAllListeners(), + ::std::select2nd< DispatcherContainer::value_type >() + ) + ); +} + +//------------------------------------------------------------------------------ +IMPL_LINK(FormController, OnLoad, void*, EMPTYARG) +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + m_bLocked = determineLockState(); + + setLocks(); + + if (!m_bLocked) + startListening(); + + // just one exception toggle the auto values + if (m_bCurrentRecordNew) + toggleAutoFields(sal_True); + + return 1L; +} + +//------------------------------------------------------------------------------ +void FormController::unloaded(const EventObject& /*rEvent*/) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + updateAllDispatchers(); +} + +//------------------------------------------------------------------------------ +void FormController::reloading(const EventObject& /*aEvent*/) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + // do the same like in unloading + // just one exception toggle the auto values + m_aToggleEvent.CancelPendingCall(); + unload(); +} + +//------------------------------------------------------------------------------ +void FormController::reloaded(const EventObject& aEvent) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + loaded(aEvent); +} + +//------------------------------------------------------------------------------ +void FormController::unloading(const EventObject& /*aEvent*/) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + unload(); +} + +//------------------------------------------------------------------------------ +void FormController::unload() throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + m_aLoadEvent.CancelPendingCall(); + + // be sure not to have autofields + if (m_bCurrentRecordNew) + toggleAutoFields(sal_False); + + // remove bound field listing again + removeBoundFieldListener(); + + if (m_bDBConnection && isListeningForChanges()) + stopListening(); + + Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY ); + if ( m_bDBConnection && xSet.is() ) + stopFormListening( xSet, sal_False ); + + m_bDBConnection = sal_False; + m_bCanInsert = m_bCanUpdate = m_bCycle = sal_False; + m_bCurrentRecordModified = m_bCurrentRecordNew = m_bLocked = sal_False; + + m_pColumnInfoCache.reset( NULL ); +} + +// ----------------------------------------------------------------------------- +void FormController::removeBoundFieldListener() +{ + const Reference< XControl >* pControls = m_aControls.getConstArray(); + const Reference< XControl >* pControlsEnd = pControls + m_aControls.getLength(); + while ( pControls != pControlsEnd ) + { + Reference< XPropertySet > xProp( *pControls++, UNO_QUERY ); + if ( xProp.is() ) + xProp->removePropertyChangeListener( FM_PROP_BOUNDFIELD, this ); + } +} + +//------------------------------------------------------------------------------ +void FormController::startFormListening( const Reference< XPropertySet >& _rxForm, sal_Bool _bPropertiesOnly ) +{ + try + { + if ( m_bCanInsert || m_bCanUpdate ) // form can be modified + { + _rxForm->addPropertyChangeListener( FM_PROP_ISNEW, this ); + _rxForm->addPropertyChangeListener( FM_PROP_ISMODIFIED, this ); + + if ( !_bPropertiesOnly ) + { + // set the Listener for UI interaction + Reference< XRowSetApproveBroadcaster > xApprove( _rxForm, UNO_QUERY ); + if ( xApprove.is() ) + xApprove->addRowSetApproveListener( this ); + + // listener for row set changes + Reference< XRowSet > xRowSet( _rxForm, UNO_QUERY ); + if ( xRowSet.is() ) + xRowSet->addRowSetListener( this ); + } + } + + Reference< XPropertySetInfo > xInfo = _rxForm->getPropertySetInfo(); + if ( xInfo.is() && xInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER ) ) + _rxForm->addPropertyChangeListener( FM_PROP_DYNAMIC_CONTROL_BORDER, this ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +//------------------------------------------------------------------------------ +void FormController::stopFormListening( const Reference< XPropertySet >& _rxForm, sal_Bool _bPropertiesOnly ) +{ + try + { + if ( m_bCanInsert || m_bCanUpdate ) + { + _rxForm->removePropertyChangeListener( FM_PROP_ISNEW, this ); + _rxForm->removePropertyChangeListener( FM_PROP_ISMODIFIED, this ); + + if ( !_bPropertiesOnly ) + { + Reference< XRowSetApproveBroadcaster > xApprove( _rxForm, UNO_QUERY ); + if (xApprove.is()) + xApprove->removeRowSetApproveListener(this); + + Reference< XRowSet > xRowSet( _rxForm, UNO_QUERY ); + if ( xRowSet.is() ) + xRowSet->removeRowSetListener( this ); + } + } + + Reference< XPropertySetInfo > xInfo = _rxForm->getPropertySetInfo(); + if ( xInfo.is() && xInfo->hasPropertyByName( FM_PROP_DYNAMIC_CONTROL_BORDER ) ) + _rxForm->removePropertyChangeListener( FM_PROP_DYNAMIC_CONTROL_BORDER, this ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +// com::sun::star::sdbc::XRowSetListener +//------------------------------------------------------------------------------ +void FormController::cursorMoved(const EventObject& /*event*/) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + // toggle the locking ? + if (m_bLocked != determineLockState()) + { + m_bLocked = !m_bLocked; + setLocks(); + if (isListeningForChanges()) + startListening(); + else + stopListening(); + } + + // neither the current control nor the current record are modified anymore + m_bCurrentRecordModified = m_bModified = sal_False; +} + +//------------------------------------------------------------------------------ +void FormController::rowChanged(const EventObject& /*event*/) throw( RuntimeException ) +{ + // not interested in ... +} +//------------------------------------------------------------------------------ +void FormController::rowSetChanged(const EventObject& /*event*/) throw( RuntimeException ) +{ + // not interested in ... +} + + +// XContainerListener +//------------------------------------------------------------------------------ +void SAL_CALL FormController::elementInserted(const ContainerEvent& evt) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + Reference< XControl > xControl( evt.Element, UNO_QUERY ); + if ( !xControl.is() ) + return; + + Reference< XFormComponent > xModel(xControl->getModel(), UNO_QUERY); + if (xModel.is() && m_xModelAsIndex == xModel->getParent()) + { + insertControl(xControl); + + if ( m_aTabActivationTimer.IsActive() ) + m_aTabActivationTimer.Stop(); + + m_aTabActivationTimer.Start(); + } + // are we in filtermode and a XModeSelector has inserted an element + else if (m_bFiltering && Reference< XModeSelector > (evt.Source, UNO_QUERY).is()) + { + xModel = Reference< XFormComponent > (evt.Source, UNO_QUERY); + if (xModel.is() && m_xModelAsIndex == xModel->getParent()) + { + Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY); + if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet)) + { + // does the model use a bound field ? + Reference< XPropertySet > xField; + xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField; + + Reference< XTextComponent > xText(xControl, UNO_QUERY); + // may we filter the field? + if (xText.is() && xField.is() && ::comphelper::hasProperty(FM_PROP_SEARCHABLE, xField) && + ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_SEARCHABLE))) + { + m_aFilterComponents.push_back( xText ); + xText->addTextListener( this ); + } + } + } + } +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::elementReplaced(const ContainerEvent& evt) throw( RuntimeException ) +{ + // simulate an elementRemoved + ContainerEvent aRemoveEvent( evt ); + aRemoveEvent.Element = evt.ReplacedElement; + aRemoveEvent.ReplacedElement = Any(); + elementRemoved( aRemoveEvent ); + + // simulate an elementInserted + ContainerEvent aInsertEvent( evt ); + aInsertEvent.ReplacedElement = Any(); + elementInserted( aInsertEvent ); +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::elementRemoved(const ContainerEvent& evt) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + Reference< XControl > xControl; + evt.Element >>= xControl; + if (!xControl.is()) + return; + + Reference< XFormComponent > xModel(xControl->getModel(), UNO_QUERY); + if (xModel.is() && m_xModelAsIndex == xModel->getParent()) + { + removeControl(xControl); + // TabOrder nicht neu berechnen, da das intern schon funktionieren muß! + } + // are we in filtermode and a XModeSelector has inserted an element + else if (m_bFiltering && Reference< XModeSelector > (evt.Source, UNO_QUERY).is()) + { + FilterComponents::iterator componentPos = ::std::find( + m_aFilterComponents.begin(), m_aFilterComponents.end(), xControl ); + if ( componentPos != m_aFilterComponents.end() ) + m_aFilterComponents.erase( componentPos ); + } +} + +//------------------------------------------------------------------------------ +Reference< XControl > FormController::isInList(const Reference< XWindowPeer > & xPeer) const +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + const Reference< XControl >* pControls = m_aControls.getConstArray(); + + sal_uInt32 nCtrls = m_aControls.getLength(); + for ( sal_uInt32 n = 0; n < nCtrls && xPeer.is(); ++n, ++pControls ) + { + if ( pControls->is() ) + { + Reference< XVclWindowPeer > xCtrlPeer( (*pControls)->getPeer(), UNO_QUERY); + if ( ( xCtrlPeer.get() == xPeer.get() ) || xCtrlPeer->isChild( xPeer ) ) + return *pControls; + } + } + return Reference< XControl > (); +} + +//------------------------------------------------------------------------------ +void FormController::activateFirst() throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + DBG_ASSERT(m_xTabController.is(), "FormController::activateFirst : invalid aggregate !"); + if (m_xTabController.is()) + m_xTabController->activateFirst(); +} + +//------------------------------------------------------------------------------ +void FormController::activateLast() throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + DBG_ASSERT(m_xTabController.is(), "FormController::activateLast : invalid aggregate !"); + if (m_xTabController.is()) + m_xTabController->activateLast(); +} + +// XFormController +//------------------------------------------------------------------------------ +Reference< XFormOperations > SAL_CALL FormController::getFormOperations() throw (RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + return m_xFormOperations; +} + +//------------------------------------------------------------------------------ +Reference< XControl> SAL_CALL FormController::getCurrentControl(void) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + return m_xCurrentControl; +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::addActivateListener(const Reference< XFormControllerListener > & l) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + m_aActivateListeners.addInterface(l); +} +//------------------------------------------------------------------------------ +void SAL_CALL FormController::removeActivateListener(const Reference< XFormControllerListener > & l) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + m_aActivateListeners.removeInterface(l); +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::addChildController( const Reference< XFormController >& _ChildController ) throw( RuntimeException, IllegalArgumentException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + if ( !_ChildController.is() ) + throw IllegalArgumentException( ::rtl::OUString(), *this, 1 ); + // TODO: (localized) error message + + // the parent of our (to-be-)child must be our own model + Reference< XFormComponent > xFormOfChild( _ChildController->getModel(), UNO_QUERY ); + if ( !xFormOfChild.is() ) + throw IllegalArgumentException( ::rtl::OUString(), *this, 1 ); + // TODO: (localized) error message + + if ( xFormOfChild->getParent() != m_xModelAsIndex ) + throw IllegalArgumentException( ::rtl::OUString(), *this, 1 ); + // TODO: (localized) error message + + m_aChilds.push_back( _ChildController ); + _ChildController->setParent( *this ); + + // search the position of the model within the form + sal_uInt32 nPos = m_xModelAsIndex->getCount(); + Reference< XFormComponent > xTemp; + for( ; nPos; ) + { + m_xModelAsIndex->getByIndex(--nPos) >>= xTemp; + if ( xFormOfChild == xTemp ) + { + Reference< XInterface > xIfc( _ChildController, UNO_QUERY ); + m_xModelAsManager->attach( nPos, xIfc, makeAny( _ChildController) ); + break; + } + } +} + +//------------------------------------------------------------------------------ +Reference< XFormControllerContext > SAL_CALL FormController::getContext() throw (RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + return m_xContext; +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::setContext( const Reference< XFormControllerContext >& _context ) throw (RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + m_xContext = _context; +} + +//------------------------------------------------------------------------------ +Reference< XInteractionHandler > SAL_CALL FormController::getInteractionHandler() throw (RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + return m_xInteractionHandler; +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::setInteractionHandler( const Reference< XInteractionHandler >& _interactionHandler ) throw (RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + m_xInteractionHandler = _interactionHandler; +} + +//------------------------------------------------------------------------------ +void FormController::setFilter(::std::vector<FmFieldInfo>& rFieldInfos) +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + // create the composer + Reference< XRowSet > xForm(m_xModelAsIndex, UNO_QUERY); + Reference< XConnection > xConnection(OStaticDataAccessTools().getRowSetConnection(xForm)); + if (xForm.is()) + { + try + { + Reference< XMultiServiceFactory > xFactory( xConnection, UNO_QUERY_THROW ); + m_xComposer.set( + xFactory->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sdb.SingleSelectQueryComposer" ) ) ), + UNO_QUERY_THROW ); + + Reference< XPropertySet > xSet( xForm, UNO_QUERY ); + ::rtl::OUString sStatement = ::comphelper::getString( xSet->getPropertyValue( FM_PROP_ACTIVECOMMAND ) ); + ::rtl::OUString sFilter = ::comphelper::getString( xSet->getPropertyValue( FM_PROP_FILTER ) ); + m_xComposer->setElementaryQuery( sStatement ); + m_xComposer->setFilter( sFilter ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + if (m_xComposer.is()) + { + Sequence < PropertyValue> aLevel; + Sequence< Sequence < PropertyValue > > aFilterRows = m_xComposer->getStructuredFilter(); + + // ok, we recieve the list of filters as sequence of fieldnames, value + // now we have to transform the fieldname into UI names, that could be a label of the field or + // a aliasname or the fieldname itself + + // first adjust the field names if necessary + Reference< XNameAccess > xQueryColumns = + Reference< XColumnsSupplier >( m_xComposer, UNO_QUERY_THROW )->getColumns(); + + for (::std::vector<FmFieldInfo>::iterator iter = rFieldInfos.begin(); + iter != rFieldInfos.end(); iter++) + { + if ( xQueryColumns->hasByName((*iter).aFieldName) ) + { + if ( (xQueryColumns->getByName((*iter).aFieldName) >>= (*iter).xField) && (*iter).xField.is() ) + (*iter).xField->getPropertyValue(FM_PROP_REALNAME) >>= (*iter).aFieldName; + } + } + + Reference< XDatabaseMetaData> xMetaData(xConnection->getMetaData()); + // now transfer the filters into Value/TextComponent pairs + ::comphelper::UStringMixEqual aCompare(xMetaData->storesMixedCaseQuotedIdentifiers()); + + // need to parse criteria localized + OStaticDataAccessTools aStaticTools; + Reference< XNumberFormatsSupplier> xFormatSupplier( aStaticTools.getNumberFormats(xConnection, sal_True)); + Reference< XNumberFormatter> xFormatter( m_aContext.createComponent( "com.sun.star.util.NumberFormatter" ), UNO_QUERY ); + xFormatter->attachNumberFormatsSupplier(xFormatSupplier); + Locale aAppLocale = Application::GetSettings().GetUILocale(); + LocaleDataWrapper aLocaleWrapper( m_aContext.getLegacyServiceFactory(), aAppLocale ); + + // retrieving the filter + const Sequence < PropertyValue >* pRow = aFilterRows.getConstArray(); + for (sal_Int32 i = 0, nLen = aFilterRows.getLength(); i < nLen; ++i) + { + FmFilterRow aRow; + + // search a field for the given name + const PropertyValue* pRefValues = pRow[i].getConstArray(); + for (sal_Int32 j = 0, nLen1 = pRow[i].getLength(); j < nLen1; j++) + { + // look for the text component + Reference< XPropertySet > xField; + try + { + Reference< XPropertySet > xSet; + ::rtl::OUString aRealName; + + // first look with the given name + if (xQueryColumns->hasByName(pRefValues[j].Name)) + { + xQueryColumns->getByName(pRefValues[j].Name) >>= xSet; + + // get the RealName + xSet->getPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("RealName"))) >>= aRealName; + + // compare the condition field name and the RealName + if (aCompare(aRealName, pRefValues[j].Name)) + xField = xSet; + } + if (!xField.is()) + { + // no we have to check every column to find the realname + Reference< XIndexAccess > xColumnsByIndex(xQueryColumns, UNO_QUERY); + for (sal_Int32 n = 0, nCount = xColumnsByIndex->getCount(); n < nCount; n++) + { + xColumnsByIndex->getByIndex(n) >>= xSet; + xSet->getPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("RealName"))) >>= aRealName; + if (aCompare(aRealName, pRefValues[j].Name)) + { + // get the column by its alias + xField = xSet; + break; + } + } + } + if (!xField.is()) + continue; + } + catch (const Exception&) + { + continue; + } + + // find the text component + for (::std::vector<FmFieldInfo>::iterator iter = rFieldInfos.begin(); + iter != rFieldInfos.end(); iter++) + { + // we found the field so insert a new entry to the filter row + if ((*iter).xField == xField) + { + // do we already have the control ? + if (aRow.find((*iter).xText) != aRow.end()) + { + ::rtl::OUString aCompText = aRow[(*iter).xText]; + aCompText += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" ")); + ::rtl::OString aVal = m_xParser->getContext().getIntlKeywordAscii(OParseContext::KEY_AND); + aCompText += ::rtl::OUString(aVal.getStr(),aVal.getLength(),RTL_TEXTENCODING_ASCII_US); + aCompText += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" ")); + aCompText += ::comphelper::getString(pRefValues[j].Value); + aRow[(*iter).xText] = aCompText; + } + else + { + ::rtl::OUString sPredicate,sErrorMsg; + pRefValues[j].Value >>= sPredicate; + ::rtl::Reference< ISQLParseNode > xParseNode = predicateTree(sErrorMsg, sPredicate, xFormatter, xField); + if ( xParseNode.is() ) + { + ::rtl::OUString sCriteria; + xParseNode->parseNodeToPredicateStr( sCriteria + ,xConnection + ,xFormatter + ,xField + ,aAppLocale + ,(sal_Char)aLocaleWrapper.getNumDecimalSep().GetChar(0) + ,getParseContext()); + aRow[(*iter).xText] = sCriteria; + } + } + } + } + } + + if (aRow.empty()) + continue; + + impl_addFilterRow( aRow ); + } + } + + // now set the filter controls + for ( ::std::vector<FmFieldInfo>::iterator field = rFieldInfos.begin(); + field != rFieldInfos.end(); + ++field + ) + { + m_aFilterComponents.push_back( field->xText ); + } +} + +//------------------------------------------------------------------------------ +void FormController::startFiltering() +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + + OStaticDataAccessTools aStaticTools; + Reference< XConnection > xConnection( aStaticTools.getRowSetConnection( Reference< XRowSet >( m_xModelAsIndex, UNO_QUERY ) ) ); + if ( !xConnection.is() ) + // nothing to do - can't filter a form which is not connected + // 98023 - 19.03.2002 - fs@openoffice.org + return; + + // stop listening for controls + if (isListeningForChanges()) + stopListening(); + + m_bFiltering = sal_True; + + // as we don't want new controls to be attached to the scripting environment + // we change attach flags + m_bAttachEvents = sal_False; + + // Austauschen der Kontrols fuer das aktuelle Formular + Sequence< Reference< XControl > > aControlsCopy( m_aControls ); + const Reference< XControl >* pControls = aControlsCopy.getConstArray(); + sal_Int32 nControlCount = aControlsCopy.getLength(); + + // the control we have to activate after replacement + Reference< XDatabaseMetaData > xMetaData(xConnection->getMetaData()); + Reference< XNumberFormatsSupplier > xFormatSupplier = aStaticTools.getNumberFormats(xConnection, sal_True); + Reference< XNumberFormatter > xFormatter( m_aContext.createComponent( "com.sun.star.util.NumberFormatter" ), UNO_QUERY ); + xFormatter->attachNumberFormatsSupplier(xFormatSupplier); + + // structure for storing the field info + ::std::vector<FmFieldInfo> aFieldInfos; + + for (sal_Int32 i = nControlCount; i > 0;) + { + Reference< XControl > xControl = pControls[--i]; + if (xControl.is()) + { + // no events for the control anymore + removeFromEventAttacher(xControl); + + // do we have a mode selector + Reference< XModeSelector > xSelector(xControl, UNO_QUERY); + if (xSelector.is()) + { + xSelector->setMode( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterMode" ) ) ); + + // listening for new controls of the selector + Reference< XContainer > xContainer(xSelector, UNO_QUERY); + if (xContainer.is()) + xContainer->addContainerListener(this); + + Reference< XEnumerationAccess > xElementAccess(xSelector, UNO_QUERY); + if (xElementAccess.is()) + { + Reference< XEnumeration > xEnumeration(xElementAccess->createEnumeration()); + Reference< XControl > xSubControl; + while (xEnumeration->hasMoreElements()) + { + xEnumeration->nextElement() >>= xSubControl; + if (xSubControl.is()) + { + Reference< XPropertySet > xSet(xSubControl->getModel(), UNO_QUERY); + if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet)) + { + // does the model use a bound field ? + Reference< XPropertySet > xField; + xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField; + + Reference< XTextComponent > xText(xSubControl, UNO_QUERY); + // may we filter the field? + if (xText.is() && xField.is() && ::comphelper::hasProperty(FM_PROP_SEARCHABLE, xField) && + ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_SEARCHABLE))) + { + aFieldInfos.push_back(FmFieldInfo(xField, xText)); + xText->addTextListener(this); + } + } + } + } + } + continue; + } + + Reference< XPropertySet > xModel( xControl->getModel(), UNO_QUERY ); + if (xModel.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xModel)) + { + // does the model use a bound field ? + Any aVal = xModel->getPropertyValue(FM_PROP_BOUNDFIELD); + Reference< XPropertySet > xField; + aVal >>= xField; + + // may we filter the field? + + if ( xField.is() + && ::comphelper::hasProperty( FM_PROP_SEARCHABLE, xField ) + && ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_SEARCHABLE ) ) + ) + { + // create a filter control + Sequence< Any > aCreationArgs( 3 ); + aCreationArgs[ 0 ] <<= NamedValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("MessageParent")), makeAny( VCLUnoHelper::GetInterface( getDialogParentWindow() ) ) ); + aCreationArgs[ 1 ] <<= NamedValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("NumberFormatter")), makeAny( xFormatter ) ); + aCreationArgs[ 2 ] <<= NamedValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ControlModel")), makeAny( xModel ) ); + Reference< XControl > xFilterControl( + m_aContext.createComponentWithArguments( "com.sun.star.form.control.FilterControl", aCreationArgs ), + UNO_QUERY + ); + DBG_ASSERT( xFilterControl.is(), "FormController::startFiltering: could not create a filter control!" ); + + if ( replaceControl( xControl, xFilterControl ) ) + { + Reference< XTextComponent > xFilterText( xFilterControl, UNO_QUERY ); + aFieldInfos.push_back( FmFieldInfo( xField, xFilterText ) ); + xFilterText->addTextListener(this); + } + } + } + else + { + // abmelden vom EventManager + } + } + } + + // we have all filter controls now, so the next step is to read the filters from the form + // resolve all aliases and set the current filter to the according structure + setFilter(aFieldInfos); + + Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY ); + if ( xSet.is() ) + stopFormListening( xSet, sal_True ); + + impl_setTextOnAllFilter_throw(); + + // lock all controls which are not used for filtering + m_bLocked = determineLockState(); + setLocks(); + m_bAttachEvents = sal_True; +} + +//------------------------------------------------------------------------------ +void FormController::stopFiltering() +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + if ( !m_bFiltering ) // #104693# OJ + { // nothing to do + return; + } + + m_bFiltering = sal_False; + m_bDetachEvents = sal_False; + + ::comphelper::disposeComponent(m_xComposer); + + // Austauschen der Kontrols fuer das aktuelle Formular + Sequence< Reference< XControl > > aControlsCopy( m_aControls ); + const Reference< XControl > * pControls = aControlsCopy.getConstArray(); + sal_Int32 nControlCount = aControlsCopy.getLength(); + + // clear the filter control map + ::std::for_each( m_aFilterComponents.begin(), m_aFilterComponents.end(), RemoveComponentTextListener( this ) ); + m_aFilterComponents.clear(); + + for ( sal_Int32 i = nControlCount; i > 0; ) + { + Reference< XControl > xControl = pControls[--i]; + if (xControl.is()) + { + // now enable eventhandling again + addToEventAttacher(xControl); + + Reference< XModeSelector > xSelector(xControl, UNO_QUERY); + if (xSelector.is()) + { + xSelector->setMode( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DataMode" ) ) ); + + // listening for new controls of the selector + Reference< XContainer > xContainer(xSelector, UNO_QUERY); + if (xContainer.is()) + xContainer->removeContainerListener(this); + continue; + } + + Reference< XPropertySet > xSet(xControl->getModel(), UNO_QUERY); + if (xSet.is() && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet)) + { + // does the model use a bound field ? + Reference< XPropertySet > xField; + xSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField; + + // may we filter the field? + if ( xField.is() + && ::comphelper::hasProperty( FM_PROP_SEARCHABLE, xField ) + && ::comphelper::getBOOL( xField->getPropertyValue( FM_PROP_SEARCHABLE ) ) + ) + { + ::rtl::OUString sServiceName; + OSL_VERIFY( xSet->getPropertyValue( FM_PROP_DEFAULTCONTROL ) >>= sServiceName ); + Reference< XControl > xNewControl( m_aContext.createComponent( sServiceName ), UNO_QUERY ); + replaceControl( xControl, xNewControl ); + } + } + } + } + + Reference< XPropertySet > xSet( m_xModelAsIndex, UNO_QUERY ); + if ( xSet.is() ) + startFormListening( xSet, sal_True ); + + m_bDetachEvents = sal_True; + + m_aFilterRows.clear(); + m_nCurrentFilterPosition = -1; + + // release the locks if possible + // lock all controls which are not used for filtering + m_bLocked = determineLockState(); + setLocks(); + + // restart listening for control modifications + if (isListeningForChanges()) + startListening(); +} + +// XModeSelector +//------------------------------------------------------------------------------ +void FormController::setMode(const ::rtl::OUString& Mode) throw( NoSupportException, RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + if (!supportsMode(Mode)) + throw NoSupportException(); + + if (Mode == m_aMode) + return; + + m_aMode = Mode; + + if ( Mode.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "FilterMode" ) ) ) + startFiltering(); + else + stopFiltering(); + + for (FmFormControllers::const_iterator i = m_aChilds.begin(); + i != m_aChilds.end(); ++i) + { + Reference< XModeSelector > xMode(*i, UNO_QUERY); + if ( xMode.is() ) + xMode->setMode(Mode); + } +} + +//------------------------------------------------------------------------------ +::rtl::OUString SAL_CALL FormController::getMode(void) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + return m_aMode; +} + +//------------------------------------------------------------------------------ +Sequence< ::rtl::OUString > SAL_CALL FormController::getSupportedModes(void) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + static Sequence< ::rtl::OUString > aModes; + if (!aModes.getLength()) + { + aModes.realloc(2); + ::rtl::OUString* pModes = aModes.getArray(); + pModes[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DataMode" ) ); + pModes[1] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterMode" ) ); + } + return aModes; +} + +//------------------------------------------------------------------------------ +sal_Bool SAL_CALL FormController::supportsMode(const ::rtl::OUString& Mode) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + Sequence< ::rtl::OUString > aModes(getSupportedModes()); + const ::rtl::OUString* pModes = aModes.getConstArray(); + for (sal_Int32 i = aModes.getLength(); i > 0; ) + { + if (pModes[--i] == Mode) + return sal_True; + } + return sal_False; +} + +//------------------------------------------------------------------------------ +Window* FormController::getDialogParentWindow() +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + Window* pParentWindow = NULL; + try + { + Reference< XControl > xContainerControl( getContainer(), UNO_QUERY_THROW ); + Reference< XWindowPeer > xContainerPeer( xContainerControl->getPeer(), UNO_QUERY_THROW ); + pParentWindow = VCLUnoHelper::GetWindow( xContainerPeer ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return pParentWindow; +} +//------------------------------------------------------------------------------ +bool FormController::checkFormComponentValidity( ::rtl::OUString& /* [out] */ _rFirstInvalidityExplanation, Reference< XControlModel >& /* [out] */ _rxFirstInvalidModel ) SAL_THROW(()) +{ + try + { + Reference< XEnumerationAccess > xControlEnumAcc( getModel(), UNO_QUERY ); + Reference< XEnumeration > xControlEnumeration; + if ( xControlEnumAcc.is() ) + xControlEnumeration = xControlEnumAcc->createEnumeration(); + OSL_ENSURE( xControlEnumeration.is(), "FormController::checkFormComponentValidity: cannot enumerate the controls!" ); + if ( !xControlEnumeration.is() ) + // assume all valid + return true; + + Reference< XValidatableFormComponent > xValidatable; + while ( xControlEnumeration->hasMoreElements() ) + { + if ( !( xControlEnumeration->nextElement() >>= xValidatable ) ) + // control does not support validation + continue; + + if ( xValidatable->isValid() ) + continue; + + Reference< XValidator > xValidator( xValidatable->getValidator() ); + OSL_ENSURE( xValidator.is(), "FormController::checkFormComponentValidity: invalid, but no validator?" ); + if ( !xValidator.is() ) + // this violates the interface definition of css.form.validation.XValidatableFormComponent ... + continue; + + _rFirstInvalidityExplanation = xValidator->explainInvalid( xValidatable->getCurrentValue() ); + _rxFirstInvalidModel = _rxFirstInvalidModel.query( xValidatable ); + return false; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return true; +} + +//------------------------------------------------------------------------------ +Reference< XControl > FormController::locateControl( const Reference< XControlModel >& _rxModel ) SAL_THROW(()) +{ + try + { + Sequence< Reference< XControl > > aControls( getControls() ); + const Reference< XControl >* pControls = aControls.getConstArray(); + const Reference< XControl >* pControlsEnd = aControls.getConstArray() + aControls.getLength(); + + for ( ; pControls != pControlsEnd; ++pControls ) + { + OSL_ENSURE( pControls->is(), "FormController::locateControl: NULL-control?" ); + if ( pControls->is() ) + { + if ( ( *pControls)->getModel() == _rxModel ) + return *pControls; + } + } + OSL_ENSURE( sal_False, "FormController::locateControl: did not find a control for this model!" ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return NULL; +} + +//------------------------------------------------------------------------------ +namespace +{ + void displayErrorSetFocus( const String& _rMessage, const Reference< XControl >& _rxFocusControl, Window* _pDialogParent ) + { + SQLContext aError; + aError.Message = String( SVX_RES( RID_STR_WRITEERROR ) ); + aError.Details = _rMessage; + displayException( aError, _pDialogParent ); + + if ( _rxFocusControl.is() ) + { + Reference< XWindow > xControlWindow( _rxFocusControl, UNO_QUERY ); + OSL_ENSURE( xControlWindow.is(), "displayErrorSetFocus: invalid control!" ); + if ( xControlWindow.is() ) + xControlWindow->setFocus(); + } + } + + sal_Bool lcl_shouldValidateRequiredFields_nothrow( const Reference< XInterface >& _rxForm ) + { + try + { + static ::rtl::OUString s_sFormsCheckRequiredFields( RTL_CONSTASCII_USTRINGPARAM( "FormsCheckRequiredFields" ) ); + + // first, check whether the form has a property telling us the answer + // this allows people to use the XPropertyContainer interface of a form to control + // the behaviour on a per-form basis. + Reference< XPropertySet > xFormProps( _rxForm, UNO_QUERY_THROW ); + Reference< XPropertySetInfo > xPSI( xFormProps->getPropertySetInfo() ); + if ( xPSI->hasPropertyByName( s_sFormsCheckRequiredFields ) ) + { + sal_Bool bShouldValidate = true; + OSL_VERIFY( xFormProps->getPropertyValue( s_sFormsCheckRequiredFields ) >>= bShouldValidate ); + return bShouldValidate; + } + + // next, check the data source which created the connection + Reference< XChild > xConnectionAsChild( xFormProps->getPropertyValue( FM_PROP_ACTIVE_CONNECTION ), UNO_QUERY_THROW ); + Reference< XPropertySet > xDataSource( xConnectionAsChild->getParent(), UNO_QUERY ); + if ( !xDataSource.is() ) + // seldom (but possible): this is not a connection created by a data source + return sal_True; + + Reference< XPropertySet > xDataSourceSettings( + xDataSource->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Settings" ) ) ), + UNO_QUERY_THROW ); + + sal_Bool bShouldValidate = true; + OSL_VERIFY( xDataSourceSettings->getPropertyValue( s_sFormsCheckRequiredFields ) >>= bShouldValidate ); + return bShouldValidate; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + return sal_True; + } +} + +// XRowSetApproveListener +//------------------------------------------------------------------------------ +sal_Bool SAL_CALL FormController::approveRowChange(const RowChangeEvent& _rEvent) throw( RuntimeException ) +{ + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + ::cppu::OInterfaceIteratorHelper aIter(m_aRowSetApproveListeners); + sal_Bool bValid = sal_True; + if (aIter.hasMoreElements()) + { + RowChangeEvent aEvt( _rEvent ); + aEvt.Source = *this; + bValid = ((XRowSetApproveListener*)aIter.next())->approveRowChange(aEvt); + } + + if ( !bValid ) + return bValid; + + if ( ( _rEvent.Action != RowChangeAction::INSERT ) + && ( _rEvent.Action != RowChangeAction::UPDATE ) + ) + return bValid; + + // if some of the control models are bound to validators, check them + ::rtl::OUString sInvalidityExplanation; + Reference< XControlModel > xInvalidModel; + if ( !checkFormComponentValidity( sInvalidityExplanation, xInvalidModel ) ) + { + Reference< XControl > xControl( locateControl( xInvalidModel ) ); + aGuard.clear(); + displayErrorSetFocus( sInvalidityExplanation, xControl, getDialogParentWindow() ); + return false; + } + + // check values on NULL and required flag + if ( !lcl_shouldValidateRequiredFields_nothrow( _rEvent.Source ) ) + return sal_True; + + OSL_ENSURE( m_pColumnInfoCache.get(), "FormController::approveRowChange: no column infos!" ); + if ( !m_pColumnInfoCache.get() ) + return sal_True; + + try + { + if ( !m_pColumnInfoCache->controlsInitialized() ) + m_pColumnInfoCache->initializeControls( getControls() ); + + size_t colCount = m_pColumnInfoCache->getColumnCount(); + for ( size_t col = 0; col < colCount; ++col ) + { + const ColumnInfo& rColInfo = m_pColumnInfoCache->getColumnInfo( col ); + if ( rColInfo.nNullable != ColumnValue::NO_NULLS ) + continue; + + if ( rColInfo.bAutoIncrement ) + continue; + + if ( rColInfo.bReadOnly ) + continue; + + if ( !rColInfo.xFirstControlWithInputRequired.is() && !rColInfo.xFirstGridWithInputRequiredColumn.is() ) + continue; + + // TODO: in case of binary fields, this "getString" below is extremely expensive + if ( rColInfo.xColumn->getString().getLength() || !rColInfo.xColumn->wasNull() ) + continue; + + String sMessage( SVX_RES( RID_ERR_FIELDREQUIRED ) ); + sMessage.SearchAndReplace( '#', rColInfo.sName ); + + // the control to focus + Reference< XControl > xControl( rColInfo.xFirstControlWithInputRequired ); + if ( !xControl.is() ) + xControl.set( rColInfo.xFirstGridWithInputRequiredColumn, UNO_QUERY ); + + aGuard.clear(); + displayErrorSetFocus( sMessage, rColInfo.xFirstControlWithInputRequired, getDialogParentWindow() ); + return sal_False; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + return true; +} + +//------------------------------------------------------------------------------ +sal_Bool SAL_CALL FormController::approveCursorMove(const EventObject& event) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + ::cppu::OInterfaceIteratorHelper aIter(m_aRowSetApproveListeners); + if (aIter.hasMoreElements()) + { + EventObject aEvt(event); + aEvt.Source = *this; + return ((XRowSetApproveListener*)aIter.next())->approveCursorMove(aEvt); + } + + return sal_True; +} + +//------------------------------------------------------------------------------ +sal_Bool SAL_CALL FormController::approveRowSetChange(const EventObject& event) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + ::cppu::OInterfaceIteratorHelper aIter(m_aRowSetApproveListeners); + if (aIter.hasMoreElements()) + { + EventObject aEvt(event); + aEvt.Source = *this; + return ((XRowSetApproveListener*)aIter.next())->approveRowSetChange(aEvt); + } + + return sal_True; +} + +// XRowSetApproveBroadcaster +//------------------------------------------------------------------------------ +void SAL_CALL FormController::addRowSetApproveListener(const Reference< XRowSetApproveListener > & _rxListener) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + m_aRowSetApproveListeners.addInterface(_rxListener); +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::removeRowSetApproveListener(const Reference< XRowSetApproveListener > & _rxListener) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + m_aRowSetApproveListeners.removeInterface(_rxListener); +} + +// XErrorListener +//------------------------------------------------------------------------------ +void SAL_CALL FormController::errorOccured(const SQLErrorEvent& aEvent) throw( RuntimeException ) +{ + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + ::cppu::OInterfaceIteratorHelper aIter(m_aErrorListeners); + if (aIter.hasMoreElements()) + { + SQLErrorEvent aEvt(aEvent); + aEvt.Source = *this; + ((XSQLErrorListener*)aIter.next())->errorOccured(aEvt); + } + else + { + aGuard.clear(); + displayException( aEvent ); + } +} + +// XErrorBroadcaster +//------------------------------------------------------------------------------ +void SAL_CALL FormController::addSQLErrorListener(const Reference< XSQLErrorListener > & aListener) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + m_aErrorListeners.addInterface(aListener); +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::removeSQLErrorListener(const Reference< XSQLErrorListener > & aListener) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + m_aErrorListeners.removeInterface(aListener); +} + +// XDatabaseParameterBroadcaster2 +//------------------------------------------------------------------------------ +void SAL_CALL FormController::addDatabaseParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + m_aParameterListeners.addInterface(aListener); +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::removeDatabaseParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + m_aParameterListeners.removeInterface(aListener); +} + +// XDatabaseParameterBroadcaster +//------------------------------------------------------------------------------ +void SAL_CALL FormController::addParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException ) +{ + FormController::addDatabaseParameterListener( aListener ); +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::removeParameterListener(const Reference< XDatabaseParameterListener > & aListener) throw( RuntimeException ) +{ + FormController::removeDatabaseParameterListener( aListener ); +} + +// XDatabaseParameterListener +//------------------------------------------------------------------------------ +sal_Bool SAL_CALL FormController::approveParameter(const DatabaseParameterEvent& aEvent) throw( RuntimeException ) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + ::cppu::OInterfaceIteratorHelper aIter(m_aParameterListeners); + if (aIter.hasMoreElements()) + { + DatabaseParameterEvent aEvt(aEvent); + aEvt.Source = *this; + return ((XDatabaseParameterListener*)aIter.next())->approveParameter(aEvt); + } + else + { + // default handling: instantiate an interaction handler and let it handle the parameter request + try + { + if ( !ensureInteractionHandler() ) + return sal_False; + + // two continuations allowed: OK and Cancel + OParameterContinuation* pParamValues = new OParameterContinuation; + OInteractionAbort* pAbort = new OInteractionAbort; + // the request + ParametersRequest aRequest; + aRequest.Parameters = aEvent.Parameters; + aRequest.Connection = OStaticDataAccessTools().getRowSetConnection(Reference< XRowSet >(aEvent.Source, UNO_QUERY)); + OInteractionRequest* pParamRequest = new OInteractionRequest(makeAny(aRequest)); + Reference< XInteractionRequest > xParamRequest(pParamRequest); + // some knittings + pParamRequest->addContinuation(pParamValues); + pParamRequest->addContinuation(pAbort); + + // handle the request + m_xInteractionHandler->handle(xParamRequest); + + if (!pParamValues->wasSelected()) + // canceled + return sal_False; + + // transfer the values into the parameter supplier + Sequence< PropertyValue > aFinalValues = pParamValues->getValues(); + if (aFinalValues.getLength() != aRequest.Parameters->getCount()) + { + DBG_ERROR("FormController::approveParameter: the InteractionHandler returned nonsense!"); + return sal_False; + } + const PropertyValue* pFinalValues = aFinalValues.getConstArray(); + for (sal_Int32 i=0; i<aFinalValues.getLength(); ++i, ++pFinalValues) + { + Reference< XPropertySet > xParam; + ::cppu::extractInterface(xParam, aRequest.Parameters->getByIndex(i)); + if (xParam.is()) + { +#ifdef DBG_UTIL + ::rtl::OUString sName; + xParam->getPropertyValue(FM_PROP_NAME) >>= sName; + DBG_ASSERT(sName.equals(pFinalValues->Name), "FormController::approveParameter: suspicious value names!"); +#endif + try { xParam->setPropertyValue(FM_PROP_VALUE, pFinalValues->Value); } + catch(Exception&) + { + DBG_ERROR("FormController::approveParameter: setting one of the properties failed!"); + } + } + } + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + return sal_True; +} + +// XConfirmDeleteBroadcaster +//------------------------------------------------------------------------------ +void SAL_CALL FormController::addConfirmDeleteListener(const Reference< XConfirmDeleteListener > & aListener) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + m_aDeleteListeners.addInterface(aListener); +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::removeConfirmDeleteListener(const Reference< XConfirmDeleteListener > & aListener) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + m_aDeleteListeners.removeInterface(aListener); +} + +// XConfirmDeleteListener +//------------------------------------------------------------------------------ +sal_Bool SAL_CALL FormController::confirmDelete(const RowChangeEvent& aEvent) throw( RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + ::cppu::OInterfaceIteratorHelper aIter(m_aDeleteListeners); + if (aIter.hasMoreElements()) + { + RowChangeEvent aEvt(aEvent); + aEvt.Source = *this; + return ((XConfirmDeleteListener*)aIter.next())->confirmDelete(aEvt); + } + // default handling: instantiate an interaction handler and let it handle the request + + String sTitle; + sal_Int32 nLength = aEvent.Rows; + if ( nLength > 1 ) + { + sTitle = SVX_RES( RID_STR_DELETECONFIRM_RECORDS ); + sTitle.SearchAndReplace( '#', String::CreateFromInt32( nLength ) ); + } + else + sTitle = SVX_RES( RID_STR_DELETECONFIRM_RECORD ); + + try + { + if ( !ensureInteractionHandler() ) + return sal_False; + + // two continuations allowed: Yes and No + OInteractionApprove* pApprove = new OInteractionApprove; + OInteractionDisapprove* pDisapprove = new OInteractionDisapprove; + + // the request + SQLWarning aWarning; + aWarning.Message = sTitle; + SQLWarning aDetails; + aDetails.Message = String( SVX_RES( RID_STR_DELETECONFIRM ) ); + aWarning.NextException <<= aDetails; + + OInteractionRequest* pRequest = new OInteractionRequest( makeAny( aWarning ) ); + Reference< XInteractionRequest > xRequest( pRequest ); + + // some knittings + pRequest->addContinuation( pApprove ); + pRequest->addContinuation( pDisapprove ); + + // handle the request + m_xInteractionHandler->handle( xRequest ); + + if ( pApprove->wasSelected() ) + return sal_True; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + return sal_False; +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::invalidateFeatures( const Sequence< ::sal_Int16 >& _Features ) throw (RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + // for now, just copy the ids of the features, because .... + ::std::copy( _Features.getConstArray(), _Features.getConstArray() + _Features.getLength(), + ::std::insert_iterator< ::std::set< sal_Int16 > >( m_aInvalidFeatures, m_aInvalidFeatures.begin() ) + ); + + // ... we will do the real invalidation asynchronously + if ( !m_aFeatureInvalidationTimer.IsActive() ) + m_aFeatureInvalidationTimer.Start(); +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::invalidateAllFeatures( ) throw (RuntimeException) +{ + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + + Sequence< sal_Int16 > aInterceptedFeatures( m_aFeatureDispatchers.size() ); + ::std::transform( + m_aFeatureDispatchers.begin(), + m_aFeatureDispatchers.end(), + aInterceptedFeatures.getArray(), + ::std::select1st< DispatcherContainer::value_type >() + ); + + aGuard.clear(); + if ( aInterceptedFeatures.getLength() ) + invalidateFeatures( aInterceptedFeatures ); +} + +//------------------------------------------------------------------------------ +Reference< XDispatch > +FormController::interceptedQueryDispatch( const URL& aURL, + const ::rtl::OUString& /*aTargetFrameName*/, sal_Int32 /*nSearchFlags*/) + throw( RuntimeException ) +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + Reference< XDispatch > xReturn; + // dispatches handled by ourself + if ( ( aURL.Complete == FMURL_CONFIRM_DELETION ) + || ( ( aURL.Complete.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "private:/InteractionHandler" ) ) ) + && ensureInteractionHandler() + ) + ) + xReturn = static_cast< XDispatch* >( this ); + + // dispatches of FormSlot-URLs we have to translate + if ( !xReturn.is() && m_xFormOperations.is() ) + { + // find the slot id which corresponds to the URL + sal_Int32 nFeatureSlotId = ::svx::FeatureSlotTranslation::getControllerFeatureSlotIdForURL( aURL.Main ); + sal_Int16 nFormFeature = ( nFeatureSlotId != -1 ) ? ::svx::FeatureSlotTranslation::getFormFeatureForSlotId( nFeatureSlotId ) : -1; + if ( nFormFeature > 0 ) + { + // get the dispatcher for this feature, create if necessary + DispatcherContainer::const_iterator aDispatcherPos = m_aFeatureDispatchers.find( nFormFeature ); + if ( aDispatcherPos == m_aFeatureDispatchers.end() ) + { + aDispatcherPos = m_aFeatureDispatchers.insert( + DispatcherContainer::value_type( nFormFeature, new ::svx::OSingleFeatureDispatcher( aURL, nFormFeature, m_xFormOperations, m_aMutex ) ) + ).first; + } + + OSL_ENSURE( aDispatcherPos->second.is(), "FormController::interceptedQueryDispatch: should have a dispatcher by now!" ); + return aDispatcherPos->second; + } + } + + // no more to offer + return xReturn; +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::dispatch( const URL& _rURL, const Sequence< PropertyValue >& _rArgs ) throw (RuntimeException) +{ + if ( _rArgs.getLength() != 1 ) + { + DBG_ERROR( "FormController::dispatch: no arguments -> no dispatch!" ); + return; + } + + if ( _rURL.Complete.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "private:/InteractionHandler" ) ) ) + { + Reference< XInteractionRequest > xRequest; + OSL_VERIFY( _rArgs[0].Value >>= xRequest ); + if ( xRequest.is() ) + handle( xRequest ); + return; + } + + if ( _rURL.Complete == FMURL_CONFIRM_DELETION ) + { + DBG_ERROR( "FormController::dispatch: How do you expect me to return something via this call?" ); + // confirmDelete has a return value - dispatch hasn't + return; + } + + DBG_ERROR( "FormController::dispatch: unknown URL!" ); +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::addStatusListener( const Reference< XStatusListener >& _rxListener, const URL& _rURL ) throw (RuntimeException) +{ + if (_rURL.Complete == FMURL_CONFIRM_DELETION) + { + if (_rxListener.is()) + { // send an initial statusChanged event + FeatureStateEvent aEvent; + aEvent.FeatureURL = _rURL; + aEvent.IsEnabled = sal_True; + _rxListener->statusChanged(aEvent); + // and don't add the listener at all (the status will never change) + } + } + else + OSL_ENSURE(sal_False, "FormController::addStatusListener: invalid (unsupported) URL!"); +} + +//------------------------------------------------------------------------------ +Reference< XInterface > SAL_CALL FormController::getParent() throw( RuntimeException ) +{ + return m_xParent; +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::setParent( const Reference< XInterface >& Parent) throw( NoSupportException, RuntimeException ) +{ + m_xParent = Parent; +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::removeStatusListener( const Reference< XStatusListener >& /*_rxListener*/, const URL& _rURL ) throw (RuntimeException) +{ + (void)_rURL; + OSL_ENSURE(_rURL.Complete == FMURL_CONFIRM_DELETION, "FormController::removeStatusListener: invalid (unsupported) URL!"); + // we never really added the listener, so we don't need to remove it +} + +//------------------------------------------------------------------------------ +Reference< XDispatchProviderInterceptor > FormController::createInterceptor(const Reference< XDispatchProviderInterception > & _xInterception) +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); +#ifdef DBG_UTIL + // check if we already have a interceptor for the given object + for ( ConstInterceptorsIterator aIter = m_aControlDispatchInterceptors.begin(); + aIter != m_aControlDispatchInterceptors.end(); + ++aIter + ) + { + if ((*aIter)->getIntercepted() == _xInterception) + DBG_ERROR("FormController::createInterceptor : we already do intercept this objects dispatches !"); + } +#endif + + DispatchInterceptionMultiplexer* pInterceptor = new DispatchInterceptionMultiplexer( _xInterception, this ); + pInterceptor->acquire(); + m_aControlDispatchInterceptors.insert( m_aControlDispatchInterceptors.end(), pInterceptor ); + + return pInterceptor; +} + +//------------------------------------------------------------------------------ +bool FormController::ensureInteractionHandler() +{ + if ( m_xInteractionHandler.is() ) + return true; + if ( m_bAttemptedHandlerCreation ) + return false; + m_bAttemptedHandlerCreation = true; + + m_xInteractionHandler.set( m_aContext.createComponent( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.task.InteractionHandler" ) ) ), UNO_QUERY ); + OSL_ENSURE( m_xInteractionHandler.is(), "FormController::ensureInteractionHandler: could not create an interaction handler!" ); + return m_xInteractionHandler.is(); +} + +//------------------------------------------------------------------------------ +void SAL_CALL FormController::handle( const Reference< XInteractionRequest >& _rRequest ) throw (RuntimeException) +{ + if ( !ensureInteractionHandler() ) + return; + m_xInteractionHandler->handle( _rRequest ); +} + +//------------------------------------------------------------------------------ +void FormController::deleteInterceptor(const Reference< XDispatchProviderInterception > & _xInterception) +{ + OSL_ENSURE( !impl_isDisposed_nofail(), "FormController: already disposed!" ); + // search the interceptor responsible for the given object + InterceptorsIterator aIter; + for ( aIter = m_aControlDispatchInterceptors.begin(); + aIter != m_aControlDispatchInterceptors.end(); + ++aIter + ) + { + if ((*aIter)->getIntercepted() == _xInterception) + break; + } + if (aIter == m_aControlDispatchInterceptors.end()) + { + return; + } + + // log off the interception from it's interception object + DispatchInterceptionMultiplexer* pInterceptorImpl = *aIter; + pInterceptorImpl->dispose(); + pInterceptorImpl->release(); + + // remove the interceptor from our array + m_aControlDispatchInterceptors.erase(aIter); +} + +//-------------------------------------------------------------------- +void FormController::implInvalidateCurrentControlDependentFeatures() +{ + Sequence< sal_Int16 > aCurrentControlDependentFeatures(4); + + aCurrentControlDependentFeatures[0] = FormFeature::SortAscending; + aCurrentControlDependentFeatures[1] = FormFeature::SortDescending; + aCurrentControlDependentFeatures[2] = FormFeature::AutoFilter; + aCurrentControlDependentFeatures[3] = FormFeature::RefreshCurrentControl; + + invalidateFeatures( aCurrentControlDependentFeatures ); +} + +//-------------------------------------------------------------------- +void SAL_CALL FormController::columnChanged( const EventObject& /*_event*/ ) throw (RuntimeException) +{ + implInvalidateCurrentControlDependentFeatures(); +} + +} // namespace svxform + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/formcontrolling.cxx b/svx/source/form/formcontrolling.cxx new file mode 100644 index 000000000000..b76213fe84b7 --- /dev/null +++ b/svx/source/form/formcontrolling.cxx @@ -0,0 +1,608 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include <sal/macros.h> +#include "formcontrolling.hxx" +#include "fmurl.hxx" +#include "svx/svxids.hrc" +#include "fmprop.hrc" +#include "svx/fmtools.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/form/runtime/FormOperations.hpp> +#include <com/sun/star/form/runtime/FormFeature.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdb/XSQLErrorBroadcaster.hpp> +/** === end UNO includes === **/ + +#include <tools/diagnose_ex.h> +#include <comphelper/anytostring.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <osl/diagnose.h> + +#include <functional> +#include <algorithm> + +//........................................................................ +namespace svx +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::lang::XMultiServiceFactory; + using ::com::sun::star::form::runtime::XFormController; + using ::com::sun::star::form::XForm; + using ::com::sun::star::form::runtime::FormOperations; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::sdbc::XRowSet; + using ::com::sun::star::form::runtime::FeatureState; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::beans::NamedValue; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::sdbc::SQLException; + using ::com::sun::star::sdb::XSQLErrorBroadcaster; + using ::com::sun::star::sdb::SQLErrorEvent; + using ::com::sun::star::lang::EventObject; + /** === end UNO using === **/ + namespace FormFeature = ::com::sun::star::form::runtime::FormFeature; + + //==================================================================== + //= FeatureSlotTranslation + //==================================================================== + namespace + { + struct FeatureDescription + { + ::rtl::OUString sURL; // the URL + sal_Int32 nSlotId; // the SFX-compatible slot ID + sal_Int16 nFormFeature; // the css.form.runtime.FormFeature ID + }; + typedef ::std::vector< FeatureDescription > FeatureDescriptions; + + //................................................................ + const FeatureDescriptions& getFeatureDescriptions() + { + static FeatureDescriptions s_aFeatureDescriptions; + if ( s_aFeatureDescriptions.empty() ) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if ( s_aFeatureDescriptions.empty() ) + { + FeatureDescription aDescriptions[] = { + { FMURL_FORM_POSITION, SID_FM_RECORD_ABSOLUTE, FormFeature::MoveAbsolute }, + { FMURL_FORM_RECORDCOUNT, SID_FM_RECORD_TOTAL, FormFeature::TotalRecords }, + { FMURL_RECORD_MOVEFIRST, SID_FM_RECORD_FIRST, FormFeature::MoveToFirst }, + { FMURL_RECORD_MOVEPREV, SID_FM_RECORD_PREV, FormFeature::MoveToPrevious }, + { FMURL_RECORD_MOVENEXT, SID_FM_RECORD_NEXT, FormFeature::MoveToNext }, + { FMURL_RECORD_MOVELAST, SID_FM_RECORD_LAST, FormFeature::MoveToLast }, + { FMURL_RECORD_MOVETONEW, SID_FM_RECORD_NEW, FormFeature::MoveToInsertRow }, + { FMURL_RECORD_SAVE, SID_FM_RECORD_SAVE, FormFeature::SaveRecordChanges }, + { FMURL_RECORD_DELETE, SID_FM_RECORD_DELETE, FormFeature::DeleteRecord }, + { FMURL_FORM_REFRESH, SID_FM_REFRESH, FormFeature::ReloadForm }, + { FMURL_FORM_REFRESH_CURRENT_CONTROL, + SID_FM_REFRESH_FORM_CONTROL,FormFeature::RefreshCurrentControl }, + { FMURL_RECORD_UNDO, SID_FM_RECORD_UNDO, FormFeature::UndoRecordChanges }, + { FMURL_FORM_SORT_UP, SID_FM_SORTUP, FormFeature::SortAscending }, + { FMURL_FORM_SORT_DOWN, SID_FM_SORTDOWN, FormFeature::SortDescending }, + { FMURL_FORM_SORT, SID_FM_ORDERCRIT, FormFeature::InteractiveSort }, + { FMURL_FORM_AUTO_FILTER, SID_FM_AUTOFILTER, FormFeature::AutoFilter }, + { FMURL_FORM_FILTER, SID_FM_FILTERCRIT, FormFeature::InteractiveFilter }, + { FMURL_FORM_APPLY_FILTER, SID_FM_FORM_FILTERED, FormFeature::ToggleApplyFilter }, + { FMURL_FORM_REMOVE_FILTER, SID_FM_REMOVE_FILTER_SORT, FormFeature::RemoveFilterAndSort } + }; + for ( size_t i=0; i < SAL_N_ELEMENTS(aDescriptions); ++i ) + s_aFeatureDescriptions.push_back( aDescriptions[i] ); + } + }; + return s_aFeatureDescriptions; + } + } + + //-------------------------------------------------------------------- + namespace + { + //................................................................ + struct MatchFeatureDescriptionByURL : public ::std::unary_function< FeatureDescription, bool > + { + const ::rtl::OUString& m_rURL; + MatchFeatureDescriptionByURL( const ::rtl::OUString& _rURL ) :m_rURL( _rURL ) { } + + bool operator()( const FeatureDescription& _compare ) + { + return m_rURL == _compare.sURL; + } + }; + + //................................................................ + struct MatchFeatureDescriptionBySlotId : public ::std::unary_function< FeatureDescription, bool > + { + sal_Int32 m_nSlotId; + MatchFeatureDescriptionBySlotId( sal_Int32 _nSlotId ) :m_nSlotId( _nSlotId ) { } + + bool operator()( const FeatureDescription& _compare ) + { + return m_nSlotId == _compare.nSlotId; + } + }; + + //................................................................ + struct MatchFeatureDescriptionByFormFeature : public ::std::unary_function< FeatureDescription, bool > + { + sal_Int32 m_nFormFeature; + MatchFeatureDescriptionByFormFeature( sal_Int32 _nFormFeature ) :m_nFormFeature( _nFormFeature ) { } + + bool operator()( const FeatureDescription& _compare ) + { + return m_nFormFeature == _compare.nFormFeature; + } + }; + + //................................................................ + struct FormFeatureToSlotId : public ::std::unary_function< sal_Int16, sal_Int32 > + { + sal_Int32 operator()( sal_Int16 _FormFeature ) + { + return FeatureSlotTranslation::getSlotIdForFormFeature( _FormFeature ); + } + }; + } + + //-------------------------------------------------------------------- + sal_Int32 FeatureSlotTranslation::getControllerFeatureSlotIdForURL( const ::rtl::OUString& _rMainURL ) + { + const FeatureDescriptions& rDescriptions( getFeatureDescriptions() ); + FeatureDescriptions::const_iterator pos = ::std::find_if( rDescriptions.begin(), rDescriptions.end(), MatchFeatureDescriptionByURL( _rMainURL ) ); + return ( pos != rDescriptions.end() ) ? pos->nSlotId : -1; + } + + //-------------------------------------------------------------------- + ::rtl::OUString FeatureSlotTranslation::getControllerFeatureURLForSlotId( sal_Int32 _nSlotId ) + { + const FeatureDescriptions& rDescriptions( getFeatureDescriptions() ); + FeatureDescriptions::const_iterator pos = ::std::find_if( rDescriptions.begin(), rDescriptions.end(), MatchFeatureDescriptionBySlotId( _nSlotId ) ); + OSL_ENSURE( pos != rDescriptions.end(), "FeatureSlotTranslation::getControllerFeatureURLForSlotId: not found!" ); + return ( pos != rDescriptions.end() ) ? pos->sURL : ::rtl::OUString(); + } + + //-------------------------------------------------------------------- + sal_Bool FeatureSlotTranslation::isFeatureURL( const ::rtl::OUString& _rMainURL ) + { + return ( _rMainURL.indexOf( FMURL_FORMSLOTS_PREFIX ) == 0 ); + } + + //-------------------------------------------------------------------- + sal_Int16 FeatureSlotTranslation::getFormFeatureForSlotId( sal_Int32 _nSlotId ) + { + const FeatureDescriptions& rDescriptions( getFeatureDescriptions() ); + FeatureDescriptions::const_iterator pos = ::std::find_if( rDescriptions.begin(), rDescriptions.end(), MatchFeatureDescriptionBySlotId( _nSlotId ) ); + OSL_ENSURE( pos != rDescriptions.end(), "FeatureSlotTranslation::getFormFeatureForSlotId: not found!" ); + return ( pos != rDescriptions.end() ) ? pos->nFormFeature : -1; + } + + //-------------------------------------------------------------------- + sal_Int32 FeatureSlotTranslation::getSlotIdForFormFeature( sal_Int16 _nFormFeature ) + { + const FeatureDescriptions& rDescriptions( getFeatureDescriptions() ); + FeatureDescriptions::const_iterator pos = ::std::find_if( rDescriptions.begin(), rDescriptions.end(), MatchFeatureDescriptionByFormFeature( _nFormFeature ) ); + OSL_ENSURE( pos != rDescriptions.end(), "FeatureSlotTranslation::getSlotIdForFormFeature: not found!" ); + return ( pos != rDescriptions.end() ) ? pos->nSlotId : -1; + } + + //==================================================================== + //= ControllerFeatures + //==================================================================== + //-------------------------------------------------------------------- + ControllerFeatures::ControllerFeatures( const Reference< XMultiServiceFactory >& _rxORB, IControllerFeatureInvalidation* _pInvalidationCallback ) + :m_aContext( _rxORB ) + ,m_pInvalidationCallback( _pInvalidationCallback ) + ,m_pImpl( NULL ) + { + } + + //-------------------------------------------------------------------- + ControllerFeatures::ControllerFeatures( const Reference< XMultiServiceFactory >& _rxORB, + const Reference< XFormController >& _rxController, IControllerFeatureInvalidation* _pInvalidationCallback ) + :m_aContext( _rxORB ) + ,m_pInvalidationCallback( _pInvalidationCallback ) + ,m_pImpl( NULL ) + { + assign( _rxController ); + } + + //-------------------------------------------------------------------- + ControllerFeatures::ControllerFeatures( const Reference< XMultiServiceFactory >& _rxORB, + const Reference< XForm >& _rxForm, IControllerFeatureInvalidation* _pInvalidationCallback ) + :m_aContext( _rxORB ) + ,m_pInvalidationCallback( _pInvalidationCallback ) + ,m_pImpl( NULL ) + { + assign( _rxForm ); + } + + //-------------------------------------------------------------------- + void ControllerFeatures::assign( const Reference< XFormController >& _rxController ) + { + dispose(); + m_pImpl = new FormControllerHelper( m_aContext, _rxController, m_pInvalidationCallback ); + m_pImpl->acquire(); + } + + //-------------------------------------------------------------------- + void ControllerFeatures::assign( const Reference< XForm >& _rxForm ) + { + dispose(); + m_pImpl = new FormControllerHelper( m_aContext, _rxForm, m_pInvalidationCallback ); + m_pImpl->acquire(); + } + + //-------------------------------------------------------------------- + ControllerFeatures::~ControllerFeatures() + { + dispose(); + } + + //-------------------------------------------------------------------- + void ControllerFeatures::dispose() + { + if ( m_pImpl ) + { + m_pImpl->dispose(); + m_pImpl->release(); + m_pImpl = NULL; + } + } + + //==================================================================== + //= FormControllerHelper + //==================================================================== + //-------------------------------------------------------------------- + FormControllerHelper::FormControllerHelper( const ::comphelper::ComponentContext& _rContext, + const Reference< XFormController >& _rxController, IControllerFeatureInvalidation* _pInvalidationCallback ) + :m_aContext( _rContext ) + ,m_pInvalidationCallback( _pInvalidationCallback ) + { + osl_incrementInterlockedCount( &m_refCount ); + try + { + m_xFormOperations = FormOperations::createWithFormController( m_aContext.getUNOContext(), _rxController ); + if ( m_xFormOperations.is() ) + m_xFormOperations->setFeatureInvalidation( this ); + + // to prevent the controller from displaying any error messages which happen while we operate on it, + // we add ourself as XSQLErrorListener. By contract, a FormController displays errors if and only if + // no SQLErrorListeners are registered. + Reference< XSQLErrorBroadcaster > xErrorBroadcast( _rxController, UNO_QUERY_THROW ); + xErrorBroadcast->addSQLErrorListener( this ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + osl_decrementInterlockedCount( &m_refCount ); + } + + //-------------------------------------------------------------------- + FormControllerHelper::FormControllerHelper( const ::comphelper::ComponentContext& _rContext, + const Reference< XForm >& _rxForm, IControllerFeatureInvalidation* _pInvalidationCallback ) + :m_aContext( _rContext ) + ,m_pInvalidationCallback( _pInvalidationCallback ) + { + osl_incrementInterlockedCount( &m_refCount ); + try + { + m_xFormOperations = FormOperations::createWithForm( m_aContext.getUNOContext(), _rxForm ); + if ( m_xFormOperations.is() ) + m_xFormOperations->setFeatureInvalidation( this ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + osl_decrementInterlockedCount( &m_refCount ); + } + + //-------------------------------------------------------------------- + FormControllerHelper::~FormControllerHelper( ) + { + try + { + acquire(); + dispose(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + //-------------------------------------------------------------------- + void FormControllerHelper::dispose() + { + if ( m_xFormOperations.is() ) + m_xFormOperations->dispose(); + m_xFormOperations.clear(); + } + + //-------------------------------------------------------------------- + sal_Bool FormControllerHelper::isEnabled( sal_Int32 _nSlotId ) const + { + if ( !m_xFormOperations.is() ) + return sal_False; + return m_xFormOperations->isEnabled( FeatureSlotTranslation::getFormFeatureForSlotId( _nSlotId ) ); + } + + //-------------------------------------------------------------------- + Reference< XRowSet > FormControllerHelper::getCursor() const + { + Reference< XRowSet > xCursor; + if ( m_xFormOperations.is() ) + xCursor = m_xFormOperations->getCursor(); + return xCursor; + } + + //-------------------------------------------------------------------- + void FormControllerHelper::getState( sal_Int32 _nSlotId, FeatureState& _rState ) const + { + if ( m_xFormOperations.is() ) + _rState = m_xFormOperations->getState( FeatureSlotTranslation::getFormFeatureForSlotId( _nSlotId ) ); + } + + //-------------------------------------------------------------------- + sal_Bool FormControllerHelper::commitCurrentControl( ) const + { + return impl_operateForm_nothrow( COMMIT_CONTROL ); + } + + //-------------------------------------------------------------------- + sal_Bool FormControllerHelper::commitCurrentRecord() const + { + return impl_operateForm_nothrow( COMMIT_RECORD ); + } + + //-------------------------------------------------------------------- + bool FormControllerHelper::moveRight( ) const + { + return impl_operateForm_nothrow( FormFeature::MoveToNext ); + } + + //-------------------------------------------------------------------- + bool FormControllerHelper::moveLeft( ) const + { + return impl_operateForm_nothrow( FormFeature::MoveToPrevious ); + } + + //-------------------------------------------------------------------- + void FormControllerHelper::execute( sal_Int32 _nSlotId, const ::rtl::OUString& _rParamName, const Any& _rParamValue ) const + { + Sequence< NamedValue > aArguments(1); + aArguments[0].Name = _rParamName; + aArguments[0].Value = _rParamValue; + + impl_operateForm_nothrow( EXECUTE_ARGS, FeatureSlotTranslation::getFormFeatureForSlotId( _nSlotId ), aArguments ); + } + + //-------------------------------------------------------------------- + bool FormControllerHelper::impl_operateForm_nothrow( const FormOperation _eWhat, const sal_Int16 _nFeature, + const Sequence< NamedValue >& _rArguments ) const + { + if ( !m_xFormOperations.is() ) + return false; + + Any aError; + bool bSuccess = false; + const_cast< FormControllerHelper* >( this )->m_aOperationError.clear(); + try + { + switch ( _eWhat ) + { + case COMMIT_CONTROL: + bSuccess = m_xFormOperations->commitCurrentControl(); + break; + + case COMMIT_RECORD: + { + sal_Bool bDummy( sal_False ); + bSuccess = m_xFormOperations->commitCurrentRecord( bDummy ); + } + break; + + case EXECUTE: + m_xFormOperations->execute( _nFeature ); + bSuccess = true; + break; + + case EXECUTE_ARGS: + m_xFormOperations->executeWithArguments( _nFeature, _rArguments ); + bSuccess = true; + break; + } + } + catch ( const SQLException& ) + { + aError = ::cppu::getCaughtException(); + } + catch( const Exception& ) + { + SQLException aFallbackError; + aFallbackError.Message = ::comphelper::anyToString( ::cppu::getCaughtException() ); + aError <<= aFallbackError; + } + + if ( bSuccess ) + return true; + + // display the error. Prefer the one reported in errorOccurred over the one caught. + if ( m_aOperationError.hasValue() ) + displayException( m_aOperationError ); + else if ( aError.hasValue() ) + displayException( aError ); + else + OSL_ENSURE( false, "FormControllerHelper::impl_operateForm_nothrow: no success, but no error?" ); + + return false; + } + + //-------------------------------------------------------------------- + void FormControllerHelper::execute( sal_Int32 _nSlotId ) const + { + impl_operateForm_nothrow( EXECUTE, FeatureSlotTranslation::getFormFeatureForSlotId( _nSlotId ), + Sequence< NamedValue >() ); + } + + //-------------------------------------------------------------------- + void SAL_CALL FormControllerHelper::invalidateFeatures( const Sequence< ::sal_Int16 >& _Features ) throw (RuntimeException) + { + if ( !m_pInvalidationCallback ) + // nobody's interested in ... + return; + + ::std::vector< sal_Int32 > aFeatures( _Features.getLength() ); + ::std::transform( + _Features.getConstArray(), + _Features.getConstArray() + _Features.getLength(), + aFeatures.begin(), + FormFeatureToSlotId() + ); + + m_pInvalidationCallback->invalidateFeatures( aFeatures ); + } + + //-------------------------------------------------------------------- + void SAL_CALL FormControllerHelper::invalidateAllFeatures() throw (RuntimeException) + { + if ( !m_pInvalidationCallback ) + // nobody's interested in ... + return; + + // actually, it's a little bit more than the supported features, + // but on the medium term, we are to support everything listed + // here + ::std::vector< sal_Int32 > aSupportedFeatures; + sal_Int32 pSupportedFeatures[] = + { + SID_FM_RECORD_FIRST, + SID_FM_RECORD_NEXT, + SID_FM_RECORD_PREV, + SID_FM_RECORD_LAST, + SID_FM_RECORD_NEW, + SID_FM_RECORD_DELETE, + SID_FM_RECORD_ABSOLUTE, + SID_FM_RECORD_TOTAL, + SID_FM_RECORD_SAVE, + SID_FM_RECORD_UNDO, + SID_FM_REMOVE_FILTER_SORT, + SID_FM_SORTUP, + SID_FM_SORTDOWN, + SID_FM_ORDERCRIT, + SID_FM_AUTOFILTER, + SID_FM_FILTERCRIT, + SID_FM_FORM_FILTERED, + SID_FM_REFRESH, + SID_FM_REFRESH_FORM_CONTROL, + SID_FM_SEARCH, + SID_FM_FILTER_START, + SID_FM_VIEW_AS_GRID + }; + sal_Int32 nFeatureCount = SAL_N_ELEMENTS( pSupportedFeatures ); + aSupportedFeatures.resize( nFeatureCount ); + ::std::copy( pSupportedFeatures, pSupportedFeatures + nFeatureCount, aSupportedFeatures.begin() ); + + m_pInvalidationCallback->invalidateFeatures( aSupportedFeatures ); + } + + //-------------------------------------------------------------------- + void SAL_CALL FormControllerHelper::errorOccured( const SQLErrorEvent& _Event ) throw (RuntimeException) + { + OSL_ENSURE( !m_aOperationError.hasValue(), "FormControllerHelper::errorOccurred: two errors during one operation?" ); + m_aOperationError = _Event.Reason; + } + + //-------------------------------------------------------------------- + void SAL_CALL FormControllerHelper::disposing( const EventObject& /*_Source*/ ) throw (RuntimeException) + { + // not interested in + } + + //-------------------------------------------------------------------- + sal_Bool FormControllerHelper::isInsertionRow() const + { + sal_Bool bIs = sal_False; + if ( m_xFormOperations.is() ) + bIs = m_xFormOperations->isInsertionRow(); + return bIs; + } + + //-------------------------------------------------------------------- + sal_Bool FormControllerHelper::isModifiedRow() const + { + sal_Bool bIs = sal_False; + if ( m_xFormOperations.is() ) + bIs = m_xFormOperations->isModifiedRow(); + return bIs; + } + //-------------------------------------------------------------------- + bool FormControllerHelper::canDoFormFilter() const + { + if ( !m_xFormOperations.is() ) + return false; + + bool bCanDo = false; + try + { + Reference< XPropertySet > xCursorProperties( m_xFormOperations->getCursor(), UNO_QUERY_THROW ); + + bool bEscapeProcessing( false ); + OSL_VERIFY( xCursorProperties->getPropertyValue( FM_PROP_ESCAPE_PROCESSING ) >>= bEscapeProcessing ); + + ::rtl::OUString sActiveCommand; + OSL_VERIFY( xCursorProperties->getPropertyValue( FM_PROP_ACTIVECOMMAND ) >>= sActiveCommand ); + + bool bInsertOnlyForm( false ); + OSL_VERIFY( xCursorProperties->getPropertyValue( FM_PROP_INSERTONLY ) >>= bInsertOnlyForm ); + + bCanDo = bEscapeProcessing && ( sActiveCommand.getLength() > 0 ) && !bInsertOnlyForm; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return bCanDo; + } + +//........................................................................ +} // namespace svx +//........................................................................ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/formdispatchinterceptor.cxx b/svx/source/form/formdispatchinterceptor.cxx new file mode 100644 index 000000000000..7eff1ac6bc8b --- /dev/null +++ b/svx/source/form/formdispatchinterceptor.cxx @@ -0,0 +1,217 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * +************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include "formdispatchinterceptor.hxx" + +/** === begin UNO includes === **/ +/** === end UNO includes === **/ + +#include <tools/debug.hxx> + +//........................................................................ +namespace svxform +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::makeAny; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Type; + using ::com::sun::star::frame::XDispatchProviderInterception; + using ::com::sun::star::frame::XDispatchProviderInterceptor; + using ::com::sun::star::lang::XComponent; + using ::com::sun::star::util::URL; + using ::com::sun::star::frame::XDispatch; + using ::com::sun::star::frame::DispatchDescriptor; + using ::com::sun::star::frame::XDispatchProvider; + using ::com::sun::star::lang::EventObject; + /** === end UNO using === **/ + + //======================================================================== + //= DispatchInterceptionMultiplexer + //======================================================================== + + DBG_NAME(DispatchInterceptionMultiplexer) + //------------------------------------------------------------------------ + DispatchInterceptionMultiplexer::DispatchInterceptionMultiplexer( + const Reference< XDispatchProviderInterception >& _rxToIntercept, DispatchInterceptor* _pMaster ) + :DispatchInterceptionMultiplexer_BASE(_pMaster && _pMaster->getInterceptorMutex() ? *_pMaster->getInterceptorMutex() : m_aFallback) + ,m_aFallback() + ,m_pMutex( _pMaster && _pMaster->getInterceptorMutex() ? _pMaster->getInterceptorMutex() : &m_aFallback ) + ,m_xIntercepted(_rxToIntercept) + ,m_bListening(sal_False) + ,m_pMaster(_pMaster) + { + DBG_CTOR(DispatchInterceptionMultiplexer,NULL); + + ::osl::MutexGuard aGuard( *m_pMutex ); + ::comphelper::increment(m_refCount); + if (_rxToIntercept.is()) + { + _rxToIntercept->registerDispatchProviderInterceptor((XDispatchProviderInterceptor*)this); + // this should make us the top-level dispatch-provider for the component, via a call to our + // setDispatchProvider we should have got an fallback for requests we (i.e. our master) cannot fullfill + Reference< XComponent> xInterceptedComponent(_rxToIntercept, UNO_QUERY); + if (xInterceptedComponent.is()) + { + xInterceptedComponent->addEventListener(this); + m_bListening = sal_True; + } + } + ::comphelper::decrement(m_refCount); + } + + //------------------------------------------------------------------------ + DispatchInterceptionMultiplexer::~DispatchInterceptionMultiplexer() + { + if (!rBHelper.bDisposed) + dispose(); + + DBG_DTOR(DispatchInterceptionMultiplexer,NULL); + } + + //------------------------------------------------------------------------------ + Reference< XDispatch > SAL_CALL DispatchInterceptionMultiplexer::queryDispatch( const URL& aURL, const ::rtl::OUString& aTargetFrameName, sal_Int32 nSearchFlags ) throw(RuntimeException) + { + ::osl::MutexGuard aGuard( *m_pMutex ); + Reference< XDispatch> xResult; + // ask our 'real' interceptor + if (m_pMaster) + xResult = m_pMaster->interceptedQueryDispatch( aURL, aTargetFrameName, nSearchFlags); + + // ask our slave provider + if (!xResult.is() && m_xSlaveDispatcher.is()) + xResult = m_xSlaveDispatcher->queryDispatch(aURL, aTargetFrameName, nSearchFlags); + + return xResult; + } + + //------------------------------------------------------------------------------ + Sequence< Reference< XDispatch > > SAL_CALL + DispatchInterceptionMultiplexer::queryDispatches( const Sequence< DispatchDescriptor >& aDescripts ) throw(RuntimeException) + { + ::osl::MutexGuard aGuard( *m_pMutex ); + Sequence< Reference< XDispatch> > aReturn(aDescripts.getLength()); + Reference< XDispatch>* pReturn = aReturn.getArray(); + const DispatchDescriptor* pDescripts = aDescripts.getConstArray(); + for (sal_Int16 i=0; i<aDescripts.getLength(); ++i, ++pReturn, ++pDescripts) + { + *pReturn = queryDispatch(pDescripts->FeatureURL, pDescripts->FrameName, pDescripts->SearchFlags); + } + return aReturn; + } + + //------------------------------------------------------------------------------ + Reference< XDispatchProvider > SAL_CALL DispatchInterceptionMultiplexer::getSlaveDispatchProvider( ) throw(RuntimeException) + { + ::osl::MutexGuard aGuard( *m_pMutex ); + return m_xSlaveDispatcher; + } + + //------------------------------------------------------------------------------ + void SAL_CALL DispatchInterceptionMultiplexer::setSlaveDispatchProvider(const Reference< XDispatchProvider>& xNewDispatchProvider) throw( RuntimeException ) + { + ::osl::MutexGuard aGuard( *m_pMutex ); + m_xSlaveDispatcher = xNewDispatchProvider; + } + + //------------------------------------------------------------------------------ + Reference< XDispatchProvider> SAL_CALL DispatchInterceptionMultiplexer::getMasterDispatchProvider(void) throw( RuntimeException ) + { + ::osl::MutexGuard aGuard( *m_pMutex ); + return m_xMasterDispatcher; + } + + //------------------------------------------------------------------------------ + void SAL_CALL DispatchInterceptionMultiplexer::setMasterDispatchProvider(const Reference< XDispatchProvider>& xNewSupplier) throw( RuntimeException ) + { + ::osl::MutexGuard aGuard( *m_pMutex ); + m_xMasterDispatcher = xNewSupplier; + } + + //------------------------------------------------------------------------------ + void SAL_CALL DispatchInterceptionMultiplexer::disposing(const EventObject& Source) throw( RuntimeException ) + { + if (m_bListening) + { + Reference< XDispatchProviderInterception > xIntercepted(m_xIntercepted.get(), UNO_QUERY); + if (Source.Source == xIntercepted) + ImplDetach(); + } + } + + //------------------------------------------------------------------------------ + void DispatchInterceptionMultiplexer::ImplDetach() + { + ::osl::MutexGuard aGuard( *m_pMutex ); + OSL_ENSURE(m_bListening, "DispatchInterceptionMultiplexer::ImplDetach: invalid call!"); + + // deregister ourself from the interception component + Reference< XDispatchProviderInterception > xIntercepted(m_xIntercepted.get(), UNO_QUERY); + if (xIntercepted.is()) + xIntercepted->releaseDispatchProviderInterceptor(static_cast<XDispatchProviderInterceptor*>(this)); + + // m_xIntercepted = Reference< XDispatchProviderInterception >(); + // Don't reset m_xIntercepted: It may be needed by our owner to check for which object we were + // responsible. As we hold the object with a weak reference only, this should be no problem. + // 88936 - 23.07.2001 - frank.schoenheit@sun.com + m_pMaster = NULL; + m_pMutex = &m_aFallback; + m_bListening = sal_False; + } + + //------------------------------------------------------------------------------ + void DispatchInterceptionMultiplexer::disposing() + { + // remove ourself as event listener from the interception component + if (m_bListening) + { + Reference< XComponent> xInterceptedComponent(m_xIntercepted.get(), UNO_QUERY); + if (xInterceptedComponent.is()) + xInterceptedComponent->removeEventListener(static_cast<XEventListener*>(this)); + + // detach from the interception component + ImplDetach(); + } + } + +//........................................................................ +} // namespace svxform +//........................................................................ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/formfeaturedispatcher.cxx b/svx/source/form/formfeaturedispatcher.cxx new file mode 100644 index 000000000000..b7277ce6dd6c --- /dev/null +++ b/svx/source/form/formfeaturedispatcher.cxx @@ -0,0 +1,244 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include "formfeaturedispatcher.hxx" + +#include <comphelper/namedvaluecollection.hxx> +#include <tools/diagnose_ex.h> + +//........................................................................ +namespace svx +{ +//........................................................................ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::form::runtime; + + //==================================================================== + //= OSingleFeatureDispatcher + //==================================================================== + //-------------------------------------------------------------------- + OSingleFeatureDispatcher::OSingleFeatureDispatcher( const URL& _rFeatureURL, const sal_Int16 _nFormFeature, + const Reference< XFormOperations >& _rxFormOperations, ::osl::Mutex& _rMutex ) + :m_rMutex( _rMutex ) + ,m_aStatusListeners( _rMutex ) + ,m_xFormOperations( _rxFormOperations ) + ,m_aFeatureURL( _rFeatureURL ) + ,m_nFormFeature( _nFormFeature ) + ,m_bLastKnownEnabled( sal_False ) + ,m_bDisposed( sal_False ) + { + } + + //-------------------------------------------------------------------- + void OSingleFeatureDispatcher::dispose() + { + { + ::osl::MutexGuard aGuard( m_rMutex ); + if ( m_bDisposed ) + return; + } + + EventObject aDisposeEvent( *this ); + m_aStatusListeners.disposeAndClear( aDisposeEvent ); + + { + ::osl::MutexGuard aGuard( m_rMutex ); + m_bDisposed = sal_True; + } + } + + //-------------------------------------------------------------------- + void OSingleFeatureDispatcher::getUnoState( FeatureStateEvent& /* [out] */ _rState ) const + { + _rState.Source = *const_cast< OSingleFeatureDispatcher* >( this ); + + FeatureState aState( m_xFormOperations->getState( m_nFormFeature ) ); + + _rState.FeatureURL = m_aFeatureURL; + _rState.IsEnabled = aState.Enabled; + _rState.Requery = sal_False; + _rState.State = aState.State; + } + + //-------------------------------------------------------------------- + void OSingleFeatureDispatcher::updateAllListeners() + { + ::osl::ClearableMutexGuard aGuard( m_rMutex ); + + FeatureStateEvent aUnoState; + getUnoState( aUnoState ); + + if ( ( m_aLastKnownState == aUnoState.State ) && ( m_bLastKnownEnabled == aUnoState.IsEnabled ) ) + return; + + m_aLastKnownState = aUnoState.State; + m_bLastKnownEnabled = aUnoState.IsEnabled; + + notifyStatus( NULL, aGuard ); + } + + //-------------------------------------------------------------------- + void OSingleFeatureDispatcher::notifyStatus( const Reference< XStatusListener >& _rxListener, ::osl::ClearableMutexGuard& _rFreeForNotification ) + { + FeatureStateEvent aUnoState; + getUnoState( aUnoState ); + + if ( _rxListener.is() ) + { + try + { + _rFreeForNotification.clear(); + _rxListener->statusChanged( aUnoState ); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "OSingleFeatureDispatcher::notifyStatus: caught an exception!" ); + } + } + else + { + ::cppu::OInterfaceIteratorHelper aIter( m_aStatusListeners ); + _rFreeForNotification.clear(); + + while ( aIter.hasMoreElements() ) + { + try + { + static_cast< XStatusListener* >( aIter.next() )->statusChanged( aUnoState ); + } + catch( const DisposedException& ) + { + OSL_ENSURE( sal_False, "OSingleFeatureDispatcher::notifyStatus: caught a DisposedException - removing the listener!" ); + aIter.remove( ); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "OSingleFeatureDispatcher::notifyStatus: caught a generic exception while notifying a single listener!" ); + } + } + } + } + + //-------------------------------------------------------------------- + void SAL_CALL OSingleFeatureDispatcher::dispatch( const URL& _rURL, const Sequence< PropertyValue >& _rArguments ) throw (RuntimeException) + { + ::osl::ClearableMutexGuard aGuard( m_rMutex ); + checkAlive(); + + OSL_ENSURE( _rURL.Complete == m_aFeatureURL.Complete, "OSingleFeatureDispatcher::dispatch: not responsible for this URL!" ); + (void)_rURL; + + if ( !m_xFormOperations->isEnabled( m_nFormFeature ) ) + return; + + // release our mutex before executing the command + sal_Int16 nFormFeature( m_nFormFeature ); + Reference< XFormOperations > xFormOperations( m_xFormOperations ); + aGuard.clear(); + + try + { + if ( !_rArguments.getLength() ) + { + xFormOperations->execute( nFormFeature ); + } + else + { // at the moment we only support one parameter + ::comphelper::NamedValueCollection aArgs( _rArguments ); + xFormOperations->executeWithArguments( nFormFeature, aArgs.getNamedValues() ); + } + } + catch( const RuntimeException& ) + { + throw; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + //-------------------------------------------------------------------- + void SAL_CALL OSingleFeatureDispatcher::addStatusListener( const Reference< XStatusListener >& _rxControl, const URL& _rURL ) throw (RuntimeException) + { + (void)_rURL; + OSL_ENSURE( _rURL.Complete == m_aFeatureURL.Complete, "OSingleFeatureDispatcher::addStatusListener: unexpected URL!" ); + OSL_ENSURE( _rxControl.is(), "OSingleFeatureDispatcher::addStatusListener: senseless call!" ); + if ( !_rxControl.is() ) + return; + + ::osl::ClearableMutexGuard aGuard( m_rMutex ); + if ( m_bDisposed ) + { + EventObject aDisposeEvent( *this ); + aGuard.clear(); + _rxControl->disposing( aDisposeEvent ); + return; + } + + m_aStatusListeners.addInterface( _rxControl ); + + // initially update the status + notifyStatus( _rxControl, aGuard ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OSingleFeatureDispatcher::removeStatusListener( const Reference< XStatusListener >& _rxControl, const URL& _rURL ) throw (RuntimeException) + { + (void)_rURL; + OSL_ENSURE( _rURL.Complete == m_aFeatureURL.Complete, "OSingleFeatureDispatcher::removeStatusListener: unexpected URL!" ); + OSL_ENSURE( _rxControl.is(), "OSingleFeatureDispatcher::removeStatusListener: senseless call!" ); + if ( !_rxControl.is() ) + return; + + ::osl::MutexGuard aGuard( m_rMutex ); + checkAlive(); + + m_aStatusListeners.removeInterface( _rxControl ); + } + + //-------------------------------------------------------------------- + void OSingleFeatureDispatcher::checkAlive() const SAL_THROW((DisposedException)) + { + if ( m_bDisposed ) + throw DisposedException( ::rtl::OUString(), *const_cast< OSingleFeatureDispatcher* >( this ) ); + } + +//........................................................................ +} // namespace svx +//........................................................................ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/formshell.src b/svx/source/form/formshell.src new file mode 100644 index 000000000000..5a7e25e14f13 --- /dev/null +++ b/svx/source/form/formshell.src @@ -0,0 +1,227 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "fmresids.hrc" +#include <svx/svxids.hrc> +#include <svx/dialogs.hrc> +#include <sfx2/sfxsids.hrc> +#include "globlmn.hrc" +#include "helpid.hrc" + +Menu RID_FM_TEXTATTRIBUTE_MENU +{ + ItemList = + { + MenuItem + { + ITEM_FORMAT_ATTR_CHAR_FONT + }; + MenuItem + { + ITEM_FORMAT_ATTR_CHAR_FONTHEIGHT + }; + MenuItem + { + Identifier = MENU_FM_TEXTATTRIBITES_STYLE; + HelpID = MENU_FM_TEXTATTRIBITES_STYLE; + Text [ en-US ] = "St~yle"; + SubMenu = Menu + { + ItemList = + { + MenuItem + { + ITEM_FORMAT_ATTR_CHAR_WEIGHT + }; + MenuItem + { + ITEM_FORMAT_ATTR_CHAR_POSTURE + }; + MenuItem + { + ITEM_FORMAT_ATTR_CHAR_OVERLINE + }; + MenuItem + { + ITEM_FORMAT_ATTR_CHAR_UNDERLINE + }; + MenuItem + { + ITEM_FORMAT_ATTR_CHAR_STRIKEOUT + }; + MenuItem + { + ITEM_FORMAT_ATTR_CHAR_SHADOWED + }; + MenuItem + { + ITEM_FORMAT_ATTR_CHAR_CONTOUR + }; + MenuItem { Separator = TRUE; }; + MenuItem + { + ITEM_FORMAT_SET_SUPER_SCRIPT + }; + MenuItem + { + ITEM_FORMAT_SET_SUB_SCRIPT + }; + }; + }; + }; + MenuItem + { + Identifier = MENU_FM_TEXTATTRIBITES_ALIGNMENT; + HelpID = MENU_FM_TEXTATTRIBITES_ALIGNMENT; + Text [ en-US ] = "~Alignment"; + RadioCheck = TRUE; + SubMenu = Menu + { + ItemList = + { + MenuItem + { + RadioCheck = TRUE; + ITEM_FORMAT_ATTR_PARA_ADJUST_LEFT + }; + MenuItem + { + RadioCheck = TRUE; + ITEM_FORMAT_ATTR_PARA_ADJUST_RIGHT + }; + MenuItem + { + RadioCheck = TRUE; + ITEM_FORMAT_ATTR_PARA_ADJUST_CENTER + }; + MenuItem + { + ITEM_FORMAT_ATTR_PARA_ADJUST_BLOCK + RadioCheck = TRUE; + }; + }; + }; + }; + MenuItem + { + Identifier = MENU_FM_TEXTATTRIBITES_SPACING; + HelpID = MENU_FM_TEXTATTRIBITES_SPACING; + Text [ en-US ] = "~Line Spacing"; + _MenuItemFlags = MIB_RADIOCHECK; + SubMenu = Menu + { + ItemList = + { + MenuItem + { + RadioCheck = TRUE; + ITEM_FORMAT_PARA_LINESPACE_10 + }; + MenuItem + { + RadioCheck = TRUE; + ITEM_FORMAT_PARA_LINESPACE_15 + }; + MenuItem + { + RadioCheck = TRUE; + ITEM_FORMAT_PARA_LINESPACE_20 + }; + }; + }; + }; + }; +}; + +TabDialog RID_SVXDLG_TEXTCONTROL_CHARATTR +{ + OutputSize = TRUE; + SVLook = TRUE; + Moveable = TRUE; + + Text [ en-US ] = "Character"; + + TabControl 1 + { + OutputSize = TRUE; + PageList = + { + PageItem + { + Identifier = RID_SVXPAGE_CHAR_NAME; + Text [ en-US ] = "Font"; + }; + PageItem + { + Identifier = RID_SVXPAGE_CHAR_EFFECTS; + Text [ en-US ] = "Font Effects"; + }; + PageItem + { + Identifier = RID_SVXPAGE_CHAR_POSITION; + Text [ en-US ] = "Position"; + }; + }; + }; +}; + +TabDialog RID_SVXDLG_TEXTCONTROL_PARAATTR +{ + OutputSize = TRUE; + SVLook = TRUE; + Moveable = TRUE; + + Text [ en-US ] = "Paragraph"; + + TabControl 1 + { + OutputSize = TRUE; + PageList = + { + PageItem + { + Identifier = RID_SVXPAGE_STD_PARAGRAPH; + Text [ en-US ] = "Indents & Spacing"; + }; + PageItem + { + Identifier = RID_SVXPAGE_ALIGN_PARAGRAPH; + Text [ en-US ] = "Alignment"; + }; + PageItem + { + Identifier = RID_SVXPAGE_PARA_ASIAN; + Text [ en-US ] = "Asian Typography"; + }; + PageItem + { + Identifier = RID_SVXPAGE_TABULATOR; + Text [ en-US ] = "Tabs"; + }; + }; + }; +}; diff --git a/svx/source/form/formtoolbars.cxx b/svx/source/form/formtoolbars.cxx new file mode 100644 index 000000000000..063e3e01005c --- /dev/null +++ b/svx/source/form/formtoolbars.cxx @@ -0,0 +1,117 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include "formtoolbars.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/beans/XPropertySet.hpp> +/** === end UNO includes === **/ + +#include <svx/svxids.hrc> + +//........................................................................ +namespace svxform +{ +//........................................................................ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::frame; + + //==================================================================== + //= FormToolboxes + //==================================================================== + //-------------------------------------------------------------------- + FormToolboxes::FormToolboxes( const Reference< XFrame >& _rxFrame ) + { + // the layout manager + Reference< XPropertySet > xFrameProps( _rxFrame, UNO_QUERY ); + if ( xFrameProps.is() ) + xFrameProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LayoutManager" ) ) ) >>= m_xLayouter; + } + + //-------------------------------------------------------------------- + void FormToolboxes::toggleToolbox( USHORT _nSlotId ) const + { + try + { + Reference< XLayoutManager > xManager( m_xLayouter ); + OSL_ENSURE( xManager. is(), "FormToolboxes::toggleToolbox: couldn't obtain the layout manager!" ); + if ( xManager. is() ) + { + ::rtl::OUString sToolboxResource( getToolboxResourceName( _nSlotId ) ); + if ( xManager->isElementVisible( sToolboxResource ) ) + { + xManager->hideElement( sToolboxResource ); + xManager->destroyElement( sToolboxResource ); + } + else + { + xManager->createElement( sToolboxResource ); + xManager->showElement( sToolboxResource ); + } + } + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FormToolboxes::toggleToolbox: caught an exception!" ); + } + } + + //-------------------------------------------------------------------- + bool FormToolboxes::isToolboxVisible( USHORT _nSlotId ) const + { + return m_xLayouter.is() && m_xLayouter->isElementVisible( + getToolboxResourceName( _nSlotId ) ); + } + + //-------------------------------------------------------------------- + ::rtl::OUString FormToolboxes::getToolboxResourceName( USHORT _nSlotId ) const + { + OSL_ENSURE( ( _nSlotId == SID_FM_MORE_CONTROLS ) || ( _nSlotId == SID_FM_FORM_DESIGN_TOOLS ) || ( _nSlotId == SID_FM_CONFIG ), + "FormToolboxes::getToolboxResourceName: unsupported slot!" ); + + const sal_Char* pToolBarName = "formcontrols"; + if ( _nSlotId == SID_FM_MORE_CONTROLS ) + pToolBarName = "moreformcontrols"; + else if ( _nSlotId == SID_FM_FORM_DESIGN_TOOLS ) + pToolBarName = "formdesign"; + + ::rtl::OUString aToolBarResStr( RTL_CONSTASCII_USTRINGPARAM( "private:resource/toolbar/" )); + aToolBarResStr += ::rtl::OUString::createFromAscii( pToolBarName ); + return aToolBarResStr; + } + +//........................................................................ +} // namespace svxform +//........................................................................ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/legacyformcontroller.cxx b/svx/source/form/legacyformcontroller.cxx new file mode 100644 index 000000000000..2224ce7caa2f --- /dev/null +++ b/svx/source/form/legacyformcontroller.cxx @@ -0,0 +1,228 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * +************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include "fmservs.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/form/XFormController.hpp> +#include <com/sun/star/form/runtime/XFormController.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +/** === end UNO includes === **/ + +#include <cppuhelper/implbase2.hxx> + +//........................................................................ +namespace svxform +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::makeAny; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Type; + using ::com::sun::star::lang::XMultiServiceFactory; + using ::com::sun::star::awt::XControl; + using ::com::sun::star::awt::XTabControllerModel; + using ::com::sun::star::awt::XControlContainer; + using ::com::sun::star::lang::XServiceInfo; + /** === end UNO using === **/ + + using namespace ::com::sun::star; + + //==================================================================== + //= LegacyFormController + //==================================================================== + typedef ::cppu::WeakImplHelper2 < form::XFormController + , XServiceInfo + > LegacyFormController_Base; + /** is an implementation of the legacy form controller service, namely css.form.FormController, supporting the + css.form.XFormController interface. + + This legacy API is superseded by css.form.runtime.(X)FormController, and though we migrated all OOo-internal + usage of this old API, their might be clients external to OOo still using it (though this is rather unlikely). + */ + class LegacyFormController : public LegacyFormController_Base + { + public: + static Reference< XInterface > Create( const Reference< XMultiServiceFactory >& _rxFactory ) + { + return *( new LegacyFormController( _rxFactory ) ); + } + + protected: + LegacyFormController( const Reference< XMultiServiceFactory >& _rxFactory ) + :m_xDelegator( _rxFactory->createInstance( FM_FORM_CONTROLLER ), UNO_QUERY_THROW ) + { + } + + // form::XFormController + virtual Reference< XControl > SAL_CALL getCurrentControl( ) throw (RuntimeException); + virtual void SAL_CALL addActivateListener( const Reference< form::XFormControllerListener >& l ) throw (RuntimeException); + virtual void SAL_CALL removeActivateListener( const Reference< form::XFormControllerListener >& l ) throw (RuntimeException); + + // awt::XTabController + virtual void SAL_CALL setModel( const Reference< XTabControllerModel >& Model ) throw (RuntimeException); + virtual Reference< XTabControllerModel > SAL_CALL getModel( ) throw (RuntimeException); + virtual void SAL_CALL setContainer( const Reference< XControlContainer >& Container ) throw (RuntimeException); + virtual Reference< XControlContainer > SAL_CALL getContainer( ) throw (RuntimeException); + virtual Sequence< Reference< XControl > > SAL_CALL getControls( ) throw (RuntimeException); + virtual void SAL_CALL autoTabOrder( ) throw (RuntimeException); + virtual void SAL_CALL activateTabOrder( ) throw (RuntimeException); + virtual void SAL_CALL activateFirst( ) throw (RuntimeException); + virtual void SAL_CALL activateLast( ) throw (RuntimeException); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName( ) throw (RuntimeException); + virtual ::sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (RuntimeException); + virtual Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) throw (RuntimeException); + + private: + const Reference< form::runtime::XFormController > m_xDelegator; + }; + + //-------------------------------------------------------------------- + Reference< XControl > SAL_CALL LegacyFormController::getCurrentControl( ) throw (RuntimeException) + { + return m_xDelegator->getCurrentControl(); + } + + //-------------------------------------------------------------------- + void SAL_CALL LegacyFormController::addActivateListener( const Reference< form::XFormControllerListener >& _listener ) throw (RuntimeException) + { + m_xDelegator->addActivateListener( _listener ); + } + + //-------------------------------------------------------------------- + void SAL_CALL LegacyFormController::removeActivateListener( const Reference< form::XFormControllerListener >& _listener ) throw (RuntimeException) + { + m_xDelegator->removeActivateListener( _listener ); + } + + //-------------------------------------------------------------------- + void SAL_CALL LegacyFormController::setModel( const Reference< XTabControllerModel >& _model ) throw (RuntimeException) + { + m_xDelegator->setModel( _model ); + } + + //-------------------------------------------------------------------- + Reference< XTabControllerModel > SAL_CALL LegacyFormController::getModel( ) throw (RuntimeException) + { + return m_xDelegator->getModel(); + } + + //-------------------------------------------------------------------- + void SAL_CALL LegacyFormController::setContainer( const Reference< XControlContainer >& _container ) throw (RuntimeException) + { + m_xDelegator->setContainer( _container ); + } + + //-------------------------------------------------------------------- + Reference< XControlContainer > SAL_CALL LegacyFormController::getContainer( ) throw (RuntimeException) + { + return m_xDelegator->getContainer(); + } + + //-------------------------------------------------------------------- + Sequence< Reference< XControl > > SAL_CALL LegacyFormController::getControls( ) throw (RuntimeException) + { + return m_xDelegator->getControls(); + } + + //-------------------------------------------------------------------- + void SAL_CALL LegacyFormController::autoTabOrder( ) throw (RuntimeException) + { + m_xDelegator->autoTabOrder(); + } + + //-------------------------------------------------------------------- + void SAL_CALL LegacyFormController::activateTabOrder( ) throw (RuntimeException) + { + m_xDelegator->activateTabOrder(); + } + + //-------------------------------------------------------------------- + void SAL_CALL LegacyFormController::activateFirst( ) throw (RuntimeException) + { + m_xDelegator->activateFirst(); + } + + //-------------------------------------------------------------------- + void SAL_CALL LegacyFormController::activateLast( ) throw (RuntimeException) + { + m_xDelegator->activateLast(); + } + + //-------------------------------------------------------------------- + ::rtl::OUString SAL_CALL LegacyFormController::getImplementationName( ) throw (RuntimeException) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.comp.svx.LegacyFormController" ) ); + } + + //-------------------------------------------------------------------- + ::sal_Bool SAL_CALL LegacyFormController::supportsService( const ::rtl::OUString& _serviceName ) throw (RuntimeException) + { + Sequence< ::rtl::OUString > aServices( getSupportedServiceNames() ); + const ::rtl::OUString* pServices = aServices.getConstArray(); + for ( sal_Int32 i = 0; i < aServices.getLength(); ++i, ++pServices ) + if( pServices->equals( _serviceName ) ) + return sal_True; + return sal_False; + } + + //-------------------------------------------------------------------- + Sequence< ::rtl::OUString > SAL_CALL LegacyFormController::getSupportedServiceNames( ) throw (RuntimeException) + { + Sequence< ::rtl::OUString > aServices(2); + aServices.getArray()[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.form.FormController" ) ); + aServices.getArray()[1] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.awt.control.TabController") ); + return aServices; + } + +//........................................................................ +} // namespace svxform +//........................................................................ + +//------------------------------------------------------------------ +::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL + LegacyFormController_NewInstance_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & _rxORB ) +{ + return ::svxform::LegacyFormController::Create( _rxORB ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/makefile.mk b/svx/source/form/makefile.mk new file mode 100644 index 000000000000..44bcd53d234f --- /dev/null +++ b/svx/source/form/makefile.mk @@ -0,0 +1,123 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=svx +TARGET=form +LIBTARGET=NO + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files -------------------------------------------------------- + +.IF "$(ENABLE_VBA)"=="YES" + CDEFS+=-DENABLE_VBA +.ENDIF + +.IF "$(ENABLE_VBA)"=="YES" + CDEFS+=-DENABLE_VBA +.ENDIF + +SRS1NAME=form +SRC1FILES= \ + fmexpl.src \ + filtnav.src \ + fmstring.src \ + formshell.src \ + datanavi.src + +LIB1TARGET= $(SLB)$/$(TARGET)-core.lib +LIB1OBJFILES= \ + $(SLO)$/formtoolbars.obj \ + $(SLO)$/fmdocumentclassification.obj \ + $(SLO)$/fmcontrolbordermanager.obj \ + $(SLO)$/fmcontrollayout.obj \ + $(SLO)$/fmtextcontroldialogs.obj \ + $(SLO)$/fmtextcontrolfeature.obj \ + $(SLO)$/fmtextcontrolshell.obj \ + $(SLO)$/ParseContext.obj \ + $(SLO)$/typeconversionclient.obj \ + $(SLO)$/dbtoolsclient.obj \ + $(SLO)$/sqlparserclient.obj \ + $(SLO)$/dataaccessdescriptor.obj \ + $(SLO)$/fmpage.obj \ + $(SLO)$/fmundo.obj \ + $(SLO)$/fmmodel.obj \ + $(SLO)$/navigatortree.obj \ + $(SLO)$/navigatortreemodel.obj \ + $(SLO)$/fmexpl.obj \ + $(SLO)$/formcontroller.obj \ + $(SLO)$/fmpgeimp.obj \ + $(SLO)$/fmvwimp.obj \ + $(SLO)$/fmdpage.obj \ + $(SLO)$/fmitems.obj \ + $(SLO)$/fmobj.obj \ + $(SLO)$/fmdmod.obj \ + $(SLO)$/fmservs.obj \ + $(SLO)$/typemap.obj \ + $(SLO)$/fmexch.obj \ + $(SLO)$/fmtools.obj \ + $(SLO)$/fmshimp.obj \ + $(SLO)$/fmshell.obj \ + $(SLO)$/fmview.obj \ + $(SLO)$/sdbdatacolumn.obj \ + $(SLO)$/formcontrolling.obj \ + $(SLO)$/formfeaturedispatcher.obj \ + $(SLO)$/formdispatchinterceptor.obj \ + $(SLO)$/datanavi.obj \ + $(SLO)$/xfm_addcondition.obj \ + $(SLO)$/datalistener.obj \ + $(SLO)$/fmscriptingenv.obj \ + $(SLO)$/stringlistresource.obj \ + $(SLO)$/delayedevent.obj \ + $(SLO)$/formcontrolfactory.obj \ + $(SLO)$/legacyformcontroller.obj + +LIB2TARGET= $(SLB)$/$(TARGET).lib +LIB2OBJFILES= \ + $(SLO)$/dbcharsethelper.obj \ + $(SLO)$/fmPropBrw.obj \ + $(SLO)$/tbxform.obj \ + $(SLO)$/fmobjfac.obj \ + $(SLO)$/fmsrccfg.obj \ + $(SLO)$/tabwin.obj \ + $(SLO)$/filtnav.obj \ + $(SLO)$/fmsrcimp.obj \ + $(SLO)$/databaselocationinput.obj + +SLOFILES = $(LIB1OBJFILES) $(LIB2OBJFILES) + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk + diff --git a/svx/source/form/navigatortree.cxx b/svx/source/form/navigatortree.cxx new file mode 100644 index 000000000000..df01af4bfa0d --- /dev/null +++ b/svx/source/form/navigatortree.cxx @@ -0,0 +1,2301 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include <svx/dialmgr.hxx> +#include <svx/fmshell.hxx> +#include <svx/fmmodel.hxx> +#include <svx/fmpage.hxx> +#include <svx/svdpagv.hxx> +#include "svditer.hxx" + +#include "fmhelp.hrc" +#include "fmexpl.hrc" +#include "fmexpl.hxx" +#include "fmresids.hrc" +#include "fmshimp.hxx" +#include "fmservs.hxx" +#include "fmundo.hxx" +#include "fmpgeimp.hxx" +#include "fmitems.hxx" +#include "fmobj.hxx" +#include "fmprop.hrc" +#include <vcl/wrkwin.hxx> +#include <sfx2/viewsh.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/viewfrm.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/property.hxx> +#include <com/sun/star/form/FormComponentType.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/script/XEventAttacherManager.hpp> +#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp> +#include <com/sun/star/datatransfer/XTransferable.hpp> +#include <sdrpaintwindow.hxx> + +#include <svx/svxdlg.hxx> +#include <svx/dialogs.hrc> +#include <rtl/logfile.hxx> +//............................................................................ +namespace svxform +{ +//............................................................................ + + #define DROP_ACTION_TIMER_INITIAL_TICKS 10 + // solange dauert es, bis das Scrollen anspringt + #define DROP_ACTION_TIMER_SCROLL_TICKS 3 + // in diesen Intervallen wird jeweils eine Zeile gescrollt + #define DROP_ACTION_TIMER_TICK_BASE 10 + // das ist die Basis, mit der beide Angaben multipliziert werden (in ms) + + #define EXPLORER_SYNC_DELAY 200 + // dieser Betrag an Millisekunden wird gewartet, ehe der Explorer nach einem Select oder Deselect die ::com::sun::star::sdbcx::View synchronisiert + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::form; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::script; + using namespace ::com::sun::star::datatransfer; + using namespace ::com::sun::star::datatransfer::clipboard; + using namespace ::com::sun::star::sdb; + + //======================================================================== + // helper + //======================================================================== + + typedef ::std::map< Reference< XInterface >, SdrObject*, ::comphelper::OInterfaceCompare< XInterface > > + MapModelToShape; + typedef MapModelToShape::value_type ModelShapePair; + + //------------------------------------------------------------------------ + void collectShapeModelMapping( SdrPage* _pPage, MapModelToShape& _rMapping ) + { + OSL_ENSURE( _pPage, "collectShapeModelMapping: invalid arg!" ); + + _rMapping.clear(); + + SdrObjListIter aIter( *_pPage ); + while ( aIter.IsMore() ) + { + SdrObject* pSdrObject = aIter.Next(); + FmFormObj* pFormObject = FmFormObj::GetFormObject( pSdrObject ); + if ( !pFormObject ) + continue; + + Reference< XInterface > xNormalizedModel( pFormObject->GetUnoControlModel(), UNO_QUERY ); + // note that this is normalized (i.e. queried for XInterface explicitly) + +#ifdef DBG_UTIL + ::std::pair< MapModelToShape::iterator, bool > aPos = +#endif + _rMapping.insert( ModelShapePair( xNormalizedModel, pSdrObject ) ); + DBG_ASSERT( aPos.second, "collectShapeModelMapping: model was already existent!" ); + // if this asserts, this would mean we have 2 shapes pointing to the same model + } + } + + //------------------------------------------------------------------------ + sal_Bool isModelShapeMarked( FmEntryData* _pEntry, const MapModelToShape& _rModelMap, SdrMarkView* _pView ) + { + DBG_ASSERT( _pEntry && _pView, "isModelShapeMarked: invalid arguments!" ); + if ( !_pEntry || !_pView ) + return sal_False; + + DBG_ASSERT( _pEntry->GetElement().get() == Reference< XInterface >( _pEntry->GetElement(), UNO_QUERY ).get(), + "isModelShapeMarked: element of the FmEntryData is not normalized!" ); + // normalization of the XInterface is a prerequisite for properly finding it in the map + + sal_Bool bIsMarked = sal_False; + + MapModelToShape::const_iterator aPos = _rModelMap.find( _pEntry->GetElement() ); + if ( _rModelMap.end() != aPos ) + { // there is a shape for this model .... + bIsMarked = _pView->IsObjMarked( aPos->second ); + if ( !bIsMarked ) + { + // IsObjMarked does not step down grouped objects, so the sal_False we + // have is not really reliable (while a sal_True would have been) + // Okay, travel the mark list, and see if there is a group marked, and our shape + // is a part of this group + sal_uInt32 nMarked = _pView->GetMarkedObjectList().GetMarkCount(); + for ( sal_uInt32 i = 0; (i<nMarked ) && !bIsMarked; ++i ) + { + SdrMark* pMark = _pView->GetMarkedObjectList().GetMark( i ); + SdrObject* pObj = pMark ? pMark->GetMarkedSdrObj() : NULL; + if ( pObj && pObj->IsGroupObject() ) + { // the i-th marked shape is a group shape + SdrObjListIter aIter( *pObj ); + while ( aIter.IsMore() ) + { + if ( aIter.Next() == aPos->second ) + { + bIsMarked = sal_True; + break; + } + } + } + } + } + } + + return bIsMarked; + } + + //======================================================================== + // class NavigatorTree + //======================================================================== + + //------------------------------------------------------------------------ + NavigatorTree::NavigatorTree( const Reference< XMultiServiceFactory >& _xORB, + Window* pParent ) + :SvTreeListBox( pParent, WB_HASBUTTONS|WB_HASLINES|WB_BORDER|WB_HSCROLL ) // #100258# OJ WB_HSCROLL added + ,m_aControlExchange(this) + ,m_xORB(_xORB) + ,m_pNavModel( NULL ) + ,m_pRootEntry(NULL) + ,m_pEditEntry(NULL) + ,nEditEvent(0) + ,m_sdiState(SDI_DIRTY) + ,m_aTimerTriggered(-1,-1) + ,m_aDropActionType( DA_SCROLLUP ) + ,m_nSelectLock(0) + ,m_nFormsSelected(0) + ,m_nControlsSelected(0) + ,m_nHiddenControls(0) + ,m_aTimerCounter( DROP_ACTION_TIMER_INITIAL_TICKS ) + ,m_bDragDataDirty(sal_False) + ,m_bPrevSelectionMixed(sal_False) + ,m_bMarkingObjects(sal_False) + ,m_bRootSelected(sal_False) + ,m_bInitialUpdate(sal_True) + ,m_bKeyboardCut( sal_False ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::NavigatorTree" ); + SetHelpId( HID_FORM_NAVIGATOR ); + + m_aNavigatorImages = ImageList( SVX_RES( RID_SVXIMGLIST_FMEXPL ) ); + + SetNodeBitmaps( + m_aNavigatorImages.GetImage( RID_SVXIMG_COLLAPSEDNODE ), + m_aNavigatorImages.GetImage( RID_SVXIMG_EXPANDEDNODE ) + ); + + SetDragDropMode(0xFFFF); + EnableInplaceEditing( sal_True ); + SetSelectionMode(MULTIPLE_SELECTION); + + m_pNavModel = new NavigatorTreeModel( m_aNavigatorImages ); + Clear(); + + StartListening( *m_pNavModel ); + + m_aDropActionTimer.SetTimeoutHdl(LINK(this, NavigatorTree, OnDropActionTimer)); + + m_aSynchronizeTimer.SetTimeoutHdl(LINK(this, NavigatorTree, OnSynchronizeTimer)); + SetSelectHdl(LINK(this, NavigatorTree, OnEntrySelDesel)); + SetDeselectHdl(LINK(this, NavigatorTree, OnEntrySelDesel)); + } + + //------------------------------------------------------------------------ + NavigatorTree::~NavigatorTree() + { + if( nEditEvent ) + Application::RemoveUserEvent( nEditEvent ); + + if (m_aSynchronizeTimer.IsActive()) + m_aSynchronizeTimer.Stop(); + + DBG_ASSERT(GetNavModel() != NULL, "NavigatorTree::~NavigatorTree : unerwartet : kein ExplorerModel"); + EndListening( *m_pNavModel ); + Clear(); + delete m_pNavModel; + } + + //------------------------------------------------------------------------ + void NavigatorTree::Clear() + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::Clear" ); + m_pNavModel->Clear(); + } + + //------------------------------------------------------------------------ + void NavigatorTree::UpdateContent( FmFormShell* pFormShell ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::UpdateContent" ); + if (m_bInitialUpdate) + { + GrabFocus(); + m_bInitialUpdate = sal_False; + } + + FmFormShell* pOldShell = GetNavModel()->GetFormShell(); + FmFormPage* pOldPage = GetNavModel()->GetFormPage(); + FmFormPage* pNewPage = pFormShell ? pFormShell->GetCurPage() : NULL; + + if ((pOldShell != pFormShell) || (pOldPage != pNewPage)) + { + // neue Shell, waehrend ich gerade editiere ? + if (IsEditingActive()) + CancelTextEditing(); + + m_bDragDataDirty = sal_True; // sicherheitshalber, auch wenn ich gar nicht dragge + } + GetNavModel()->UpdateContent( pFormShell ); + + // wenn es eine Form gibt, die Root expandieren + if (m_pRootEntry && !IsExpanded(m_pRootEntry)) + Expand(m_pRootEntry); + // wenn es GENAU eine Form gibt, auch diese expandieren + if (m_pRootEntry) + { + SvLBoxEntry* pFirst = FirstChild(m_pRootEntry); + if (pFirst && !NextSibling(pFirst)) + Expand(pFirst); + } + } + + //------------------------------------------------------------------------------ + sal_Bool NavigatorTree::implAllowExchange( sal_Int8 _nAction, sal_Bool* _pHasNonHidden ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::implAllowExchange" ); + SvLBoxEntry* pCurEntry = GetCurEntry(); + if (!pCurEntry) + return sal_False; + + // die Informationen fuer das AcceptDrop und ExecuteDrop + CollectSelectionData(SDI_ALL); + if (!m_arrCurrentSelection.Count()) + // nothing to do + return sal_False; + + // testen, ob es sich vielleicht ausschliesslich um hidden controls handelt (dann koennte ich pCtrlExch noch ein + // zusaetzliches Format geben) + sal_Bool bHasNonHidden = sal_False; + for (sal_Int32 i=0; i<m_arrCurrentSelection.Count(); i++) + { + FmEntryData* pCurrent = static_cast< FmEntryData* >( m_arrCurrentSelection[(sal_uInt16)i]->GetUserData() ); + if ( IsHiddenControl( pCurrent ) ) + continue; + bHasNonHidden = sal_True; + break; + } + + if ( bHasNonHidden && ( 0 == ( _nAction & DND_ACTION_MOVE ) ) ) + // non-hidden controls need to be moved + return sal_False; + + if ( _pHasNonHidden ) + *_pHasNonHidden = bHasNonHidden; + + return sal_True; + } + + //------------------------------------------------------------------------------ + sal_Bool NavigatorTree::implPrepareExchange( sal_Int8 _nAction ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::implPrepareExchange" ); + sal_Int32 i; + + EndSelection(); + + sal_Bool bHasNonHidden = sal_False; + if ( !implAllowExchange( _nAction, &bHasNonHidden ) ) + return sal_False; + + m_aControlExchange.prepareDrag(); + m_aControlExchange->setFocusEntry( GetCurEntry() ); + + for ( i = 0; i < m_arrCurrentSelection.Count(); ++i ) + m_aControlExchange->addSelectedEntry(m_arrCurrentSelection[(sal_uInt16)i]); + + m_aControlExchange->setFormsRoot( GetNavModel()->GetFormPage()->GetForms() ); + m_aControlExchange->buildPathFormat( this, m_pRootEntry ); + + if (!bHasNonHidden) + { + // eine entsprechende Sequenz aufbauen + Sequence< Reference< XInterface > > seqIFaces(m_arrCurrentSelection.Count()); + Reference< XInterface >* pArray = seqIFaces.getArray(); + for (i=0; i<m_arrCurrentSelection.Count(); ++i, ++pArray) + *pArray = static_cast< FmEntryData* >( m_arrCurrentSelection[(sal_uInt16)i]->GetUserData() )->GetElement(); + + // und das neue Format + m_aControlExchange->addHiddenControlsFormat(seqIFaces); + } + + m_bDragDataDirty = sal_False; + return sal_True; + } + + //------------------------------------------------------------------------------ + void NavigatorTree::StartDrag( sal_Int8 /*nAction*/, const ::Point& /*rPosPixel*/ ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::StartDrag" ); + EndSelection(); + + if ( !implPrepareExchange( DND_ACTION_COPYMOVE ) ) + // nothing to do or something went wrong + return; + + // jetzt haben wir alle in der aktuelle Situation moeglichen Formate eingesammelt, es kann also losgehen ... + m_aControlExchange.startDrag( DND_ACTION_COPYMOVE ); + } + + //------------------------------------------------------------------------------ + void NavigatorTree::Command( const CommandEvent& rEvt ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::Command" ); + sal_Bool bHandled = sal_False; + switch( rEvt.GetCommand() ) + { + case COMMAND_CONTEXTMENU: + { + // die Stelle, an der geklickt wurde + ::Point ptWhere; + if (rEvt.IsMouseEvent()) + { + ptWhere = rEvt.GetMousePosPixel(); + SvLBoxEntry* ptClickedOn = GetEntry(ptWhere); + if (ptClickedOn == NULL) + break; + if ( !IsSelected(ptClickedOn) ) + { + SelectAll(sal_False); + Select(ptClickedOn, sal_True); + SetCurEntry(ptClickedOn); + } + } + else + { + if (m_arrCurrentSelection.Count() == 0) // kann nur bei Kontextmenue ueber Tastatur passieren + break; + + SvLBoxEntry* pCurrent = GetCurEntry(); + if (!pCurrent) + break; + ptWhere = GetEntryPosition(pCurrent); + } + + // meine Selektionsdaten auf den aktuellen Stand + CollectSelectionData(SDI_ALL); + + // wenn mindestens ein Nicht-Root-Eintrag selektiert ist und die Root auch, dann nehme ich letztere aus der Selektion + // fix wieder raus + if ( (m_arrCurrentSelection.Count() > 1) && m_bRootSelected ) + { + Select( m_pRootEntry, sal_False ); + SetCursor( m_arrCurrentSelection.GetObject(0), sal_True); + } + sal_Bool bSingleSelection = (m_arrCurrentSelection.Count() == 1); + + + DBG_ASSERT( (m_arrCurrentSelection.Count() > 0) || m_bRootSelected, "keine Eintraege selektiert" ); + // solte nicht passieren, da ich oben bei der IsSelected-Abfrage auf jeden Fall einen selektiert haette, + // wenn das vorher nicht der Fall gewesen waere + + + // das Menue zusammenbasteln + FmFormShell* pFormShell = GetNavModel()->GetFormShell(); + FmFormModel* pFormModel = pFormShell ? pFormShell->GetFormModel() : NULL; + if( pFormShell && pFormModel ) + { + PopupMenu aContextMenu(SVX_RES(RID_FMEXPLORER_POPUPMENU)); + PopupMenu* pSubMenuNew = aContextMenu.GetPopupMenu( SID_FM_NEW ); + + // das 'Neu'-Untermenue gibt es nur, wenn genau die Root oder genau ein Formular selektiert sind + aContextMenu.EnableItem( SID_FM_NEW, bSingleSelection && (m_nFormsSelected || m_bRootSelected) ); + + // 'Neu'\'Formular' unter genau den selben Bedingungen + pSubMenuNew->EnableItem( SID_FM_NEW_FORM, bSingleSelection && (m_nFormsSelected || m_bRootSelected) ); + pSubMenuNew->SetItemImage(SID_FM_NEW_FORM, m_aNavigatorImages.GetImage(RID_SVXIMG_FORM)); + pSubMenuNew->SetItemImage(SID_FM_NEW_HIDDEN, m_aNavigatorImages.GetImage(RID_SVXIMG_HIDDEN)); + + // 'Neu'\'verstecktes...', wenn genau ein Formular selektiert ist + pSubMenuNew->EnableItem( SID_FM_NEW_HIDDEN, bSingleSelection && m_nFormsSelected ); + + // 'Delete': everything which is not root can be removed + aContextMenu.EnableItem( SID_FM_DELETE, !m_bRootSelected ); + + // 'Cut', 'Copy' and 'Paste' + aContextMenu.EnableItem( SID_CUT, !m_bRootSelected && implAllowExchange( DND_ACTION_MOVE ) ); + aContextMenu.EnableItem( SID_COPY, !m_bRootSelected && implAllowExchange( DND_ACTION_COPY ) ); + aContextMenu.EnableItem( SID_PASTE, implAcceptPaste( ) ); + + // der TabDialog, wenn es genau ein Formular ist ... + aContextMenu.EnableItem( SID_FM_TAB_DIALOG, bSingleSelection && m_nFormsSelected ); + + // in XML forms, we don't allow for the properties of a form + // #i36484# / 2004-11-04 /- fs@openoffice.org + if ( pFormShell->GetImpl()->isEnhancedForm() && !m_nControlsSelected ) + aContextMenu.RemoveItem( aContextMenu.GetItemPos( SID_FM_SHOW_PROPERTY_BROWSER ) ); + + // if the property browser is already open, we don't allow for the properties, too + if( pFormShell->GetImpl()->IsPropBrwOpen() ) + aContextMenu.RemoveItem( aContextMenu.GetItemPos( SID_FM_SHOW_PROPERTY_BROWSER ) ); + // and finally, if there's a mixed selection of forms and controls, disable the entry, too + else + aContextMenu.EnableItem( SID_FM_SHOW_PROPERTY_BROWSER, + (m_nControlsSelected && !m_nFormsSelected) || (!m_nControlsSelected && m_nFormsSelected) ); + + // Umbenennen gdw wenn ein Element und nicht die Root + aContextMenu.EnableItem( SID_FM_RENAME_OBJECT, bSingleSelection && !m_bRootSelected ); + + // der Reandonly-Eintrag ist nur auf der Root erlaubt + aContextMenu.EnableItem( SID_FM_OPEN_READONLY, m_bRootSelected ); + // the same for automatic control focus + aContextMenu.EnableItem( SID_FM_AUTOCONTROLFOCUS, m_bRootSelected ); + + // die ConvertTo-Slots sind enabled, wenn genau ein Control selektiert ist, der + // dem Control entsprechende Slot ist disabled + if (!m_bRootSelected && !m_nFormsSelected && (m_nControlsSelected == 1)) + { + aContextMenu.SetPopupMenu( SID_FM_CHANGECONTROLTYPE, FmXFormShell::GetConversionMenu() ); +#if OSL_DEBUG_LEVEL > 0 + FmControlData* pCurrent = (FmControlData*)(m_arrCurrentSelection[0]->GetUserData()); + OSL_ENSURE( pFormShell->GetImpl()->isSolelySelected( pCurrent->GetFormComponent() ), + "NavigatorTree::Command: inconsistency between the navigator selection, and the selection as the shell knows it!" ); +#endif + + pFormShell->GetImpl()->checkControlConversionSlotsForCurrentSelection( *aContextMenu.GetPopupMenu( SID_FM_CHANGECONTROLTYPE ) ); + } + else + aContextMenu.EnableItem( SID_FM_CHANGECONTROLTYPE, sal_False ); + + // jetzt alles, was disabled wurde, wech + aContextMenu.RemoveDisabledEntries(sal_True, sal_True); + ////////////////////////////////////////////////////////// + // OpenReadOnly setzen + + aContextMenu.CheckItem( SID_FM_OPEN_READONLY, pFormModel->GetOpenInDesignMode() ); + aContextMenu.CheckItem( SID_FM_AUTOCONTROLFOCUS, pFormModel->GetAutoControlFocus() ); + + sal_uInt16 nSlotId = aContextMenu.Execute( this, ptWhere ); + switch( nSlotId ) + { + case SID_FM_NEW_FORM: + { + XubString aStr(SVX_RES(RID_STR_FORM)); + XubString aUndoStr(SVX_RES(RID_STR_UNDO_CONTAINER_INSERT)); + aUndoStr.SearchAndReplace('#', aStr); + + pFormModel->BegUndo(aUndoStr); + // der Slot war nur verfuegbar, wenn es genau einen selektierten Eintrag gibt und dieser die Root + // oder ein Formular ist + NewForm( m_arrCurrentSelection.GetObject(0) ); + pFormModel->EndUndo(); + + } break; + case SID_FM_NEW_HIDDEN: + { + XubString aStr(SVX_RES(RID_STR_CONTROL)); + XubString aUndoStr(SVX_RES(RID_STR_UNDO_CONTAINER_INSERT)); + aUndoStr.SearchAndReplace('#', aStr); + + pFormModel->BegUndo(aUndoStr); + // dieser Slot war guletig bei (genau) einem selektierten Formular + rtl::OUString fControlName = FM_COMPONENT_HIDDEN; + NewControl( fControlName, m_arrCurrentSelection.GetObject(0) ); + pFormModel->EndUndo(); + + } break; + + case SID_CUT: + doCut(); + break; + + case SID_COPY: + doCopy(); + break; + + case SID_PASTE: + doPaste(); + break; + + case SID_FM_DELETE: + { + DeleteSelection(); + } + break; + case SID_FM_TAB_DIALOG: + { + // dieser Slot galt bei genau einem selektierten Formular + SvLBoxEntry* pSelectedForm = m_arrCurrentSelection.GetObject(0); + DBG_ASSERT( IsFormEntry(pSelectedForm), "NavigatorTree::Command: Dieser Eintrag muss ein FormEntry sein." ); + + FmFormData* pFormData = (FmFormData*)pSelectedForm->GetUserData(); + Reference< XForm > xForm( pFormData->GetFormIface()); + + Reference< XTabControllerModel > xTabController(xForm, UNO_QUERY); + if( !xTabController.is() ) + break; + GetNavModel()->GetFormShell()->GetImpl()->ExecuteTabOrderDialog( xTabController ); + } + break; + + case SID_FM_SHOW_PROPERTY_BROWSER: + { + ShowSelectionProperties(sal_True); + } + break; + case SID_FM_RENAME_OBJECT: + { + // das war bei genau einem Nicht-Root-Eintrag erlaubt + EditEntry( m_arrCurrentSelection.GetObject(0) ); + } + break; + case SID_FM_OPEN_READONLY: + { + pFormModel->SetOpenInDesignMode( !pFormModel->GetOpenInDesignMode() ); + pFormShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(SID_FM_OPEN_READONLY); + } + break; + case SID_FM_AUTOCONTROLFOCUS: + { + pFormModel->SetAutoControlFocus( !pFormModel->GetAutoControlFocus() ); + pFormShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(SID_FM_AUTOCONTROLFOCUS); + } + break; + default: + if (pFormShell->GetImpl()->isControlConversionSlot(nSlotId)) + { + FmControlData* pCurrent = (FmControlData*)(m_arrCurrentSelection[0]->GetUserData()); + if ( pFormShell->GetImpl()->executeControlConversionSlot( pCurrent->GetFormComponent(), nSlotId ) ) + ShowSelectionProperties(); + } + } + } + bHandled = sal_True; + } break; + } + + if (!bHandled) + SvTreeListBox::Command( rEvt ); + } + + //------------------------------------------------------------------------ + sal_Bool NavigatorTree::IsDeleteAllowed() + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::IsDeleteAllowed" ); + ////////////////////////////////////////////////////////////////////// + // Haben wir eine Form... + SvLBoxEntry* pCurEntry = GetCurEntry(); + sal_uInt32 nCurEntryPos = GetModel()->GetAbsPos( pCurEntry ); + + if( nCurEntryPos==0 ) // Root kann nicht geloescht werden + return sal_False; + else + return IsFormEntry(pCurEntry) || IsFormComponentEntry(pCurEntry); + } + + //------------------------------------------------------------------------ + SvLBoxEntry* NavigatorTree::FindEntry( FmEntryData* pEntryData ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::FindEntry" ); + if( !pEntryData ) return NULL; + SvLBoxEntry* pCurEntry = First(); + FmEntryData* pCurEntryData; + while( pCurEntry ) + { + pCurEntryData = (FmEntryData*)pCurEntry->GetUserData(); + if( pCurEntryData && pCurEntryData->IsEqualWithoutChilds(pEntryData) ) + return pCurEntry; + + pCurEntry = Next( pCurEntry ); + } + + return NULL; + } + + //------------------------------------------------------------------------ + void NavigatorTree::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::Notify" ); + if( rHint.ISA(FmNavRemovedHint) ) + { + FmNavRemovedHint* pRemovedHint = (FmNavRemovedHint*)&rHint; + FmEntryData* pEntryData = pRemovedHint->GetEntryData(); + Remove( pEntryData ); + } + + else if( rHint.ISA(FmNavInsertedHint) ) + { + FmNavInsertedHint* pInsertedHint = (FmNavInsertedHint*)&rHint; + FmEntryData* pEntryData = pInsertedHint->GetEntryData(); + sal_uInt32 nRelPos = pInsertedHint->GetRelPos(); + Insert( pEntryData, nRelPos ); + } + + else if( rHint.ISA(FmNavModelReplacedHint) ) + { + FmEntryData* pData = ((FmNavModelReplacedHint*)&rHint)->GetEntryData(); + SvLBoxEntry* pEntry = FindEntry( pData ); + if (pEntry) + { // das Image neu setzen + SetCollapsedEntryBmp( pEntry, pData->GetNormalImage() ); + SetExpandedEntryBmp( pEntry, pData->GetNormalImage() ); + } + } + + else if( rHint.ISA(FmNavNameChangedHint) ) + { + FmNavNameChangedHint* pNameChangedHint = (FmNavNameChangedHint*)&rHint; + SvLBoxEntry* pEntry = FindEntry( pNameChangedHint->GetEntryData() ); + SetEntryText( pEntry, pNameChangedHint->GetNewName() ); + } + + else if( rHint.ISA(FmNavClearedHint) ) + { + SvTreeListBox::Clear(); + + ////////////////////////////////////////////////////////////////////// + // Default-Eintrag "Formulare" + Image aRootImage( m_aNavigatorImages.GetImage( RID_SVXIMG_FORMS ) ); + m_pRootEntry = InsertEntry( SVX_RES(RID_STR_FORMS), aRootImage, aRootImage, + NULL, sal_False, 0, NULL ); + } + else if (!m_bMarkingObjects && rHint.ISA(FmNavRequestSelectHint)) + { // wenn m_bMarkingObjects sal_True ist, markiere ich gerade selber Objekte, und da der ganze Mechanismus dahinter synchron ist, + // ist das genau der Hint, der durch mein Markieren ausgeloest wird, also kann ich ihn ignorieren + FmNavRequestSelectHint* pershHint = (FmNavRequestSelectHint*)&rHint; + FmEntryDataArray& arredToSelect = pershHint->GetItems(); + SynchronizeSelection(arredToSelect); + + if (pershHint->IsMixedSelection()) + // in diesem Fall habe ich alles deselektiert, obwohl die View u.U. eine gemischte Markierung hatte + // ich muss also im naechsten Select den Navigator an die View anpassen + m_bPrevSelectionMixed = sal_True; + } + } + + //------------------------------------------------------------------------ + SvLBoxEntry* NavigatorTree::Insert( FmEntryData* pEntryData, ULONG nRelPos ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::Insert" ); + ////////////////////////////////////////////////////////////////////// + // Aktuellen Eintrag einfuegen + SvLBoxEntry* pParentEntry = FindEntry( pEntryData->GetParent() ); + SvLBoxEntry* pNewEntry; + + if( !pParentEntry ) + pNewEntry = InsertEntry( pEntryData->GetText(), + pEntryData->GetNormalImage(), pEntryData->GetNormalImage(), + m_pRootEntry, sal_False, nRelPos, pEntryData ); + + else + pNewEntry = InsertEntry( pEntryData->GetText(), + pEntryData->GetNormalImage(), pEntryData->GetNormalImage(), + pParentEntry, sal_False, nRelPos, pEntryData ); + + ////////////////////////////////////////////////////////////////////// + // Wenn Root-Eintrag Root expandieren + if( !pParentEntry ) + Expand( m_pRootEntry ); + + ////////////////////////////////////////////////////////////////////// + // Childs einfuegen + FmEntryDataList* pChildList = pEntryData->GetChildList(); + size_t nChildCount = pChildList->size(); + FmEntryData* pChildData; + for( size_t i = 0; i < nChildCount; i++ ) + { + pChildData = pChildList->at( i ); + Insert( pChildData, LIST_APPEND ); + } + + return pNewEntry; + } + + //------------------------------------------------------------------------ + void NavigatorTree::Remove( FmEntryData* pEntryData ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::Remove" ); + if( !pEntryData ) + return; + + // der Entry zu den Daten + SvLBoxEntry* pEntry = FindEntry( pEntryData ); + if (!pEntry) + return; + + // Eintrag aus TreeListBox entfernen + // ich darf das Select, das ich ausloese, nicht behandeln : + // Select aendert die MarkList der View, wenn das gerade auch jemand anders macht und dabei ein Remove + // triggert, haben wir mit ziemlicher Sicherheit ein Problem - Paradebeispiel war das Gruppieren von Controls mit + // offenem Navigator ...) + LockSelectionHandling(); + + // ein kleines Problem : ich merke mir meine selektierten Daten, wenn mir jetzt jemand einen selektierten Eintrag + // unter dem Hintern wegschiesst, werde ich inkonsistent ... was schlecht waere + Select(pEntry, sal_False); + + // beim eigentlichen Entfernen kann die Selection geaendert werden, da ich aber das SelectionHandling abgeschaltet + // habe, muss ich mich hinterher darum kuemmern + ULONG nExpectedSelectionCount = GetSelectionCount(); + + if( pEntry ) + GetModel()->Remove( pEntry ); + + if (nExpectedSelectionCount != GetSelectionCount()) + SynchronizeSelection(); + + // und standardmaessig behandle ich das Select natuerlich + UnlockSelectionHandling(); + } + + //------------------------------------------------------------------------ + sal_Bool NavigatorTree::IsFormEntry( SvLBoxEntry* pEntry ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::IsFormEntry" ); + FmEntryData* pEntryData = (FmEntryData*)pEntry->GetUserData(); + return !pEntryData || pEntryData->ISA(FmFormData); + } + + //------------------------------------------------------------------------ + sal_Bool NavigatorTree::IsFormComponentEntry( SvLBoxEntry* pEntry ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::IsFormComponentEntry" ); + FmEntryData* pEntryData = (FmEntryData*)pEntry->GetUserData(); + return pEntryData && pEntryData->ISA(FmControlData); + } + + //------------------------------------------------------------------------ + sal_Bool NavigatorTree::implAcceptPaste( ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::implAcceptPaste" ); + SvLBoxEntry* pFirstSelected = FirstSelected(); + if ( !pFirstSelected || NextSelected( pFirstSelected ) ) + // no selected entry, or at least two selected entries + return sal_False; + + // get the clipboard + TransferableDataHelper aClipboardContent( TransferableDataHelper::CreateFromSystemClipboard( this ) ); + + sal_Int8 nAction = m_aControlExchange.isClipboardOwner() && doingKeyboardCut( ) ? DND_ACTION_MOVE : DND_ACTION_COPY; + return ( nAction == implAcceptDataTransfer( aClipboardContent.GetDataFlavorExVector(), nAction, pFirstSelected, sal_False ) ); + } + + //------------------------------------------------------------------------ + sal_Int8 NavigatorTree::implAcceptDataTransfer( const DataFlavorExVector& _rFlavors, sal_Int8 _nAction, const ::Point& _rDropPos, sal_Bool _bDnD ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::implAcceptDataTransfer" ); + return implAcceptDataTransfer( _rFlavors, _nAction, GetEntry( _rDropPos ), _bDnD ); + } + + //------------------------------------------------------------------------ + sal_Int8 NavigatorTree::implAcceptDataTransfer( const DataFlavorExVector& _rFlavors, sal_Int8 _nAction, SvLBoxEntry* _pTargetEntry, sal_Bool _bDnD ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::implAcceptDataTransfer" ); + // no target -> no drop + if (!_pTargetEntry) + return DND_ACTION_NONE; + + // format check + sal_Bool bHasDefControlFormat = OControlExchange::hasFieldExchangeFormat( _rFlavors ); + sal_Bool bHasControlPathFormat = OControlExchange::hasControlPathFormat( _rFlavors ); + sal_Bool bHasHiddenControlsFormat = OControlExchange::hasHiddenControlModelsFormat( _rFlavors ); + if (!bHasDefControlFormat && !bHasControlPathFormat && !bHasHiddenControlsFormat) + return DND_ACTION_NONE; + + sal_Bool bSelfSource = _bDnD ? m_aControlExchange.isDragSource() : m_aControlExchange.isClipboardOwner(); + + if ( bHasHiddenControlsFormat ) + { // bHasHiddenControlsFormat means that only hidden controls are part of the data + + // hidden controls can be copied to a form only + if ( !_pTargetEntry || ( _pTargetEntry == m_pRootEntry ) || !IsFormEntry( _pTargetEntry ) ) + return DND_ACTION_NONE; + + return bSelfSource ? ( DND_ACTION_COPYMOVE & _nAction ) : DND_ACTION_COPY; + } + + if ( !bSelfSource ) + { + // DnD or CnP crossing navigator boundaries + // The main problem here is that the current API does not allow us to sneak into the content which + // is to be inserted. So we have to allow it for the moment, but maybe reject later on (in the real drop). + + // TODO: this smart behaviour later on ... at the moment, we disallow data transfer crossing navigator + // boundaries. + + return DND_ACTION_NONE; + } + + DBG_ASSERT( _bDnD ? m_aControlExchange.isDragSource() : m_aControlExchange.isClipboardOwner(), + "NavigatorTree::implAcceptDataTransfer: here only with source=dest!" ); + // somebody changed the logic of this method ... + + // from here on, I can work with m_aControlExchange instead of _rData! + + sal_Bool bForeignCollection = m_aControlExchange->getFormsRoot().get() != GetNavModel()->GetFormPage()->GetForms().get(); + if ( bForeignCollection ) + { + // crossing shell/page boundaries, we can exchange hidden controls only + // But if we survived the checks above, we do not have hidden controls. + // -> no data transfer + DBG_ASSERT( !bHasHiddenControlsFormat, "NavigatorTree::implAcceptDataTransfer: still hidden controls format!" ); + // somebody changed the logic of this method ... + + return DND_ACTION_COPY; + } + + if (DND_ACTION_MOVE != _nAction) // 'normal' controls within a shell are moved only (never copied) + return DND_ACTION_NONE; + + if ( m_bDragDataDirty || !bHasDefControlFormat ) + { + if (!bHasControlPathFormat) + // ich befinde mich zwar in der Shell/Page, aus der die Controls stammen, habe aber kein Format, das den stattgefundenen + // Shell-Wechsel ueberlebt hat (SVX_FM_CONTROLS_AS_PATH) + return DND_ACTION_NONE; + + // da die Shell waehrend des Draggens umgeschaltet wude, muss ich die Liste des ExchangeObjektes wieder neu aufbauen + // (dort stehen SvLBoxEntries drin, und die sind bei der Umschaltung floeten gegangen) + m_aControlExchange->buildListFromPath(this, m_pRootEntry); + m_bDragDataDirty = sal_False; + } + + // die Liste der gedroppten Eintraege aus dem DragServer + const ListBoxEntrySet& aDropped = m_aControlExchange->selected(); + DBG_ASSERT(aDropped.size() >= 1, "NavigatorTree::implAcceptDataTransfer: keine Eintraege !"); + + sal_Bool bDropTargetIsComponent = IsFormComponentEntry( _pTargetEntry ); + //SvLBoxEntry* pDropTargetParent = GetParent( _pTargetEntry ); + + // conditions to disallow the drop + // 0) the root entry is part of the list (can't DnD the root!) + // 1) one of the draged entries is to be dropped onto it's own parent + // 2) - " - is to be dropped onto itself + // 3) - " - is a Form and to be dropped onto one of it's descendants + // 4) one of the entries is a control and to be dropped onto the root + // 5) a control or form will be dropped onto a control which is _not_ a sibling (dropping onto a sibling + // means moving the control) + + // collect the ancestors of the drop targte (speeds up 3) + SvLBoxEntrySortedArray arrDropAnchestors; + SvLBoxEntry* pLoop = _pTargetEntry; + while (pLoop) + { + arrDropAnchestors.Insert(pLoop); + pLoop = GetParent(pLoop); + } + + for ( ListBoxEntrySet::const_iterator dropped = aDropped.begin(); + dropped != aDropped.end(); + ++dropped + ) + { + SvLBoxEntry* pCurrent = *dropped; + SvLBoxEntry* pCurrentParent = GetParent(pCurrent); + + // test for 0) + if (pCurrent == m_pRootEntry) + return DND_ACTION_NONE; + + // test for 1) + if ( _pTargetEntry == pCurrentParent ) + return DND_ACTION_NONE; + + // test for 2) + if (pCurrent == _pTargetEntry) + return DND_ACTION_NONE; + + // test for 5) + // if ( bDropTargetIsComponent && (pDropTargetParent != pCurrentParent) ) + if ( bDropTargetIsComponent ) // TODO : die obige Zeile wieder rein, dann muss aber ExecuteDrop das Vertauschen auch beherrschen + return DND_ACTION_NONE; + + // test for 3) + if ( IsFormEntry(pCurrent) ) + { + sal_uInt16 nPosition; + if ( arrDropAnchestors.Seek_Entry(pCurrent, &nPosition) ) + return DND_ACTION_NONE; + } else if ( IsFormComponentEntry(pCurrent) ) + { + // test for 4) + if (_pTargetEntry == m_pRootEntry) + return DND_ACTION_NONE; + } + } + + return DND_ACTION_MOVE; + } + + //------------------------------------------------------------------------ + sal_Int8 NavigatorTree::AcceptDrop( const AcceptDropEvent& rEvt ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::AcceptDrop" ); + ::Point aDropPos = rEvt.maPosPixel; + + // kuemmern wir uns erst mal um moeglich DropActions (Scrollen und Aufklappen) + if (rEvt.mbLeaving) + { + if (m_aDropActionTimer.IsActive()) + m_aDropActionTimer.Stop(); + } else + { + sal_Bool bNeedTrigger = sal_False; + // auf dem ersten Eintrag ? + if ((aDropPos.Y() >= 0) && (aDropPos.Y() < GetEntryHeight())) + { + m_aDropActionType = DA_SCROLLUP; + bNeedTrigger = sal_True; + } else + // auf dem letzten (bzw. in dem Bereich, den ein Eintrag einnehmen wuerde, wenn er unten genau buendig + // abschliessen wuerde) ? + if ((aDropPos.Y() < GetSizePixel().Height()) && (aDropPos.Y() >= GetSizePixel().Height() - GetEntryHeight())) + { + m_aDropActionType = DA_SCROLLDOWN; + bNeedTrigger = sal_True; + } else + { // auf einem Entry mit Childs, der nicht aufgeklappt ist ? + SvLBoxEntry* pDropppedOn = GetEntry(aDropPos); + if (pDropppedOn && (GetChildCount(pDropppedOn) > 0) && !IsExpanded(pDropppedOn)) + { + // -> aufklappen + m_aDropActionType = DA_EXPANDNODE; + bNeedTrigger = sal_True; + } + } + + if (bNeedTrigger && (m_aTimerTriggered != aDropPos)) + { + // neu anfangen zu zaehlen + m_aTimerCounter = DROP_ACTION_TIMER_INITIAL_TICKS; + // die Pos merken, da ich auch AcceptDrops bekomme, wenn sich die Maus gar nicht bewegt hat + m_aTimerTriggered = aDropPos; + // und den Timer los + if (!m_aDropActionTimer.IsActive()) // gibt es den Timer schon ? + { + m_aDropActionTimer.SetTimeout(DROP_ACTION_TIMER_TICK_BASE); + m_aDropActionTimer.Start(); + } + } else if (!bNeedTrigger) + m_aDropActionTimer.Stop(); + } + + return implAcceptDataTransfer( GetDataFlavorExVector(), rEvt.mnAction, aDropPos, sal_True ); + } + + //------------------------------------------------------------------------ + sal_Int8 NavigatorTree::implExecuteDataTransfer( const OControlTransferData& _rData, sal_Int8 _nAction, const ::Point& _rDropPos, sal_Bool _bDnD ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::implExecuteDataTransfer" ); + return implExecuteDataTransfer( _rData, _nAction, GetEntry( _rDropPos ), _bDnD ); + } + + //------------------------------------------------------------------------ + sal_Int8 NavigatorTree::implExecuteDataTransfer( const OControlTransferData& _rData, sal_Int8 _nAction, SvLBoxEntry* _pTargetEntry, sal_Bool _bDnD ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::implExecuteDataTransfer" ); + const DataFlavorExVector& rDataFlavors = _rData.GetDataFlavorExVector(); + + if ( DND_ACTION_NONE == implAcceptDataTransfer( rDataFlavors, _nAction, _pTargetEntry, _bDnD ) ) + // under some platforms, it may happen that ExecuteDrop is called though AcceptDrop returned DND_ACTION_NONE + return DND_ACTION_NONE; + + // ware schlecht, wenn nach dem Droppen noch gescrollt wird ... + if (m_aDropActionTimer.IsActive()) + m_aDropActionTimer.Stop(); + + if (!_pTargetEntry) + // no target -> no drop + return DND_ACTION_NONE; + + // format checks +#ifdef DBG_UTIL + sal_Bool bHasHiddenControlsFormat = OControlExchange::hasHiddenControlModelsFormat( rDataFlavors ); + sal_Bool bForeignCollection = _rData.getFormsRoot().get() != GetNavModel()->GetFormPage()->GetForms().get(); + DBG_ASSERT(!bForeignCollection || bHasHiddenControlsFormat, "NavigatorTree::implExecuteDataTransfer: invalid format (AcceptDrop shouldn't have let this pass) !"); + DBG_ASSERT(bForeignCollection || !m_bDragDataDirty, "NavigatorTree::implExecuteDataTransfer: invalid state (shell changed since last exchange resync) !"); + // das sollte in AcceptDrop erledigt worden sein : dort wird in _rData die Liste der Controls aufgebaut und m_bDragDataDirty + // zurueckgesetzt +#endif + + if ( DND_ACTION_COPY == _nAction ) + { // bHasHiddenControlsFormat means that only hidden controls are part of the data + DBG_ASSERT( bHasHiddenControlsFormat, "NavigatorTree::implExecuteDataTransfer: copy allowed for hidden controls only!" ); + DBG_ASSERT( _pTargetEntry && ( _pTargetEntry != m_pRootEntry ) && IsFormEntry( _pTargetEntry ), + "NavigatorTree::implExecuteDataTransfer: should not be here!" ); + // implAcceptDataTransfer should have caught both cases + + DBG_ASSERT(bHasHiddenControlsFormat, "NavigatorTree::implExecuteDataTransfer: only copying of hidden controls is supported !"); + // das sollte das AcceptDrop abgefangen haben + + // da ich gleich die Zielobjekte alle selektieren will (und nur die) + SelectAll(sal_False); + + Sequence< Reference< XInterface > > aControls = _rData.hiddenControls(); + sal_Int32 nCount = aControls.getLength(); + const Reference< XInterface >* pControls = aControls.getConstArray(); + + FmFormShell* pFormShell = GetNavModel()->GetFormShell(); + FmFormModel* pFormModel = pFormShell ? pFormShell->GetFormModel() : NULL; + + // innerhalb eines Undo ... + if (pFormModel) + { + XubString aStr(SVX_RES(RID_STR_CONTROL)); + XubString aUndoStr(SVX_RES(RID_STR_UNDO_CONTAINER_INSERT)); + aUndoStr.SearchAndReplace('#', aStr); + pFormModel->BegUndo(aUndoStr); + } + + // die Conrtols kopieren + for (sal_Int32 i=0; i<nCount; ++i) + { + // neues Control anlegen + rtl::OUString fControlName = FM_COMPONENT_HIDDEN; + FmControlData* pNewControlData = NewControl( fControlName, _pTargetEntry, sal_False); + Reference< XPropertySet > xNewPropSet( pNewControlData->GetPropertySet() ); + + // und die Properties des alten in das neue kopieren + Reference< XPropertySet > xCurrent(pControls[i], UNO_QUERY); +#if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL + // nur mal eben sehen, ob das Ding tatsaechlich ein hidden control ist + sal_Int16 nClassId = ::comphelper::getINT16(xCurrent->getPropertyValue(FM_PROP_CLASSID)); + OSL_ENSURE(nClassId == FormComponentType::HIDDENCONTROL, "NavigatorTree::implExecuteDataTransfer: invalid control in drop list !"); + // wenn das SVX_FM_HIDDEN_CONTROLS-Format vorhanden ist, dann sollten wirklich nur hidden controls in der Sequenz + // stecken +#endif // (OSL_DEBUG_LEVEL > 1) || DBG_UTIL + Reference< XPropertySetInfo > xPropInfo( xCurrent->getPropertySetInfo()); + Sequence< Property> seqAllCurrentProps = xPropInfo->getProperties(); + Property* pAllCurrentProps = seqAllCurrentProps.getArray(); + for (sal_Int32 j=0; j<seqAllCurrentProps.getLength(); ++j) + { + ::rtl::OUString sCurrentProp = pAllCurrentProps[j].Name; + if (((pAllCurrentProps[j].Attributes & PropertyAttribute::READONLY) == 0) && (sCurrentProp != FM_PROP_NAME)) + { // (read-only attribs werden natuerlich nicht gesetzt, dito der Name, den hat das NewControl schon eindeutig + // festgelegt) + xNewPropSet->setPropertyValue(sCurrentProp, xCurrent->getPropertyValue(sCurrentProp)); + } + } + + SvLBoxEntry* pToSelect = FindEntry(pNewControlData); + Select(pToSelect, sal_True); + if (i == 0) + SetCurEntry(pToSelect); + } + + if (pFormModel) + pFormModel->EndUndo(); + + return _nAction; + } + + if ( !OControlExchange::hasFieldExchangeFormat( _rData.GetDataFlavorExVector() ) ) + { + // can't do anything without the internal format here ... usually happens when doing DnD or CnP + // over navigator boundaries + return DND_ACTION_NONE; + } + + // some data for the target + sal_Bool bDropTargetIsForm = IsFormEntry(_pTargetEntry); + FmFormData* pTargetData = bDropTargetIsForm ? (FmFormData*)_pTargetEntry->GetUserData() : NULL; + + DBG_ASSERT( DND_ACTION_COPY != _nAction, "NavigatorTree::implExecuteDataTransfer: somebody changed the logics!" ); + + // die Liste der gedraggten Eintraege + ListBoxEntrySet aDropped = _rData.selected(); + DBG_ASSERT(aDropped.size() >= 1, "NavigatorTree::implExecuteDataTransfer: no entries!"); + + // die Shell und das Model + FmFormShell* pFormShell = GetNavModel()->GetFormShell(); + FmFormModel* pFormModel = pFormShell ? pFormShell->GetFormModel() : NULL; + if (!pFormModel) + return DND_ACTION_NONE; + + // fuer's Undo + const bool bUndo = pFormModel->IsUndoEnabled(); + + if( bUndo ) + { + XubString strUndoDescription(SVX_RES(RID_STR_UNDO_CONTAINER_REPLACE)); + pFormModel->BegUndo(strUndoDescription); + } + + // ich nehme vor dem Einfuegen eines Eintrages seine Selection raus, damit die Markierung dabei nicht flackert + // -> das Handeln des Select locken + LockSelectionHandling(); + + // jetzt durch alle gedroppten Eintraege ... + for ( ListBoxEntrySet::const_iterator dropped = aDropped.begin(); + dropped != aDropped.end(); + ++dropped + ) + { + // ein paar Daten zum aktuellen Element + SvLBoxEntry* pCurrent = *dropped; + DBG_ASSERT(pCurrent != NULL, "NavigatorTree::implExecuteDataTransfer: ungueltiger Eintrag"); + DBG_ASSERT(GetParent(pCurrent) != NULL, "NavigatorTree::implExecuteDataTransfer: ungueltiger Eintrag"); + // die Root darf nicht gedraggt werden + + FmEntryData* pCurrentUserData = (FmEntryData*)pCurrent->GetUserData(); + + Reference< XChild > xCurrentChild(pCurrentUserData->GetChildIFace(), UNO_QUERY); + Reference< XIndexContainer > xContainer(xCurrentChild->getParent(), UNO_QUERY); + + FmFormData* pCurrentParentUserData = (FmFormData*)pCurrentUserData->GetParent(); + DBG_ASSERT(pCurrentParentUserData == NULL || pCurrentParentUserData->ISA(FmFormData), "NavigatorTree::implExecuteDataTransfer: ungueltiges Parent"); + + // beim Vater austragen + if (pCurrentParentUserData) + pCurrentParentUserData->GetChildList()->remove( pCurrentUserData ); + else + GetNavModel()->GetRootList()->remove( pCurrentUserData ); + + // aus dem Container entfernen + sal_Int32 nIndex = getElementPos(Reference< XIndexAccess > (xContainer, UNO_QUERY), xCurrentChild); + GetNavModel()->m_pPropChangeList->Lock(); + // die Undo-Action fuer das Rausnehmen + if ( bUndo && GetNavModel()->m_pPropChangeList->CanUndo()) + { + pFormModel->AddUndo(new FmUndoContainerAction(*pFormModel, FmUndoContainerAction::Removed, + xContainer, xCurrentChild, nIndex)); + } + else if( !GetNavModel()->m_pPropChangeList->CanUndo() ) + { + FmUndoContainerAction::DisposeElement( xCurrentChild ); + } + + // Events mitkopieren + Reference< XEventAttacherManager > xManager(xContainer, UNO_QUERY); + Sequence< ScriptEventDescriptor > aEvts; + + if (xManager.is() && nIndex >= 0) + aEvts = xManager->getScriptEvents(nIndex); + xContainer->removeByIndex(nIndex); + + // die Selection raus + Select(pCurrent, sal_False); + // und weg + Remove(pCurrentUserData); + + // die Stelle innerhalb des DropParents, an der ich die gedroppten Eintraege einfuegen muss + if (pTargetData) + xContainer = Reference< XIndexContainer > (pTargetData->GetElement(), UNO_QUERY); + else + xContainer = Reference< XIndexContainer > (GetNavModel()->GetForms(), UNO_QUERY); + + // immer ganz hinten einfuegen + nIndex = xContainer->getCount(); + + // UndoAction fuer das Einfuegen + if ( bUndo && GetNavModel()->m_pPropChangeList->CanUndo()) + pFormModel->AddUndo(new FmUndoContainerAction(*pFormModel, FmUndoContainerAction::Inserted, + xContainer, xCurrentChild, nIndex)); + + // einfuegen im neuen Container + if (pTargetData) + { + // es wird in eine Form eingefuegt, dann brauche ich eine FormComponent + xContainer->insertByIndex( nIndex, + makeAny( Reference< XFormComponent >( xCurrentChild, UNO_QUERY ) ) ); + } + else + { + xContainer->insertByIndex( nIndex, + makeAny( Reference< XForm >( xCurrentChild, UNO_QUERY ) ) ); + } + + if (aEvts.getLength()) + { + xManager = Reference< XEventAttacherManager > (xContainer, UNO_QUERY); + if (xManager.is()) + xManager->registerScriptEvents(nIndex, aEvts); + } + + GetNavModel()->m_pPropChangeList->UnLock(); + + // zuerst dem Eintrag das neue Parent + pCurrentUserData->SetParent(pTargetData); + + // dann dem Parent das neue Child + if (pTargetData) + pTargetData->GetChildList()->insert( pCurrentUserData, nIndex ); + else + GetNavModel()->GetRootList()->insert( pCurrentUserData, nIndex ); + + // dann bei mir selber bekanntgeben und neu selektieren + SvLBoxEntry* pNew = Insert( pCurrentUserData, nIndex ); + if ( ( aDropped.begin() == dropped ) && pNew ) + { + SvLBoxEntry* pParent = GetParent( pNew ); + if ( pParent ) + Expand( pParent ); + } + } + + UnlockSelectionHandling(); + + if( bUndo ) + pFormModel->EndUndo(); + + // During the move, the markings of the underlying view did not change (because the view is not affected by the logical + // hierarchy of the form/control models. But my selection changed - which means I have to adjust it according to the + // view marks, again. + SynchronizeSelection(); + + // in addition, with the move of controls such things as "the current form" may have changed - force the shell + // to update itself accordingly + if( pFormShell && pFormShell->GetImpl() && pFormShell->GetFormView() ) + pFormShell->GetImpl()->DetermineSelection( pFormShell->GetFormView()->GetMarkedObjectList() ); + + if ( m_aControlExchange.isClipboardOwner() && ( DND_ACTION_MOVE == _nAction ) ) + m_aControlExchange->clear(); + + return _nAction; + } + + //------------------------------------------------------------------------ + sal_Int8 NavigatorTree::ExecuteDrop( const ExecuteDropEvent& rEvt ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::ExecuteDrop" ); + sal_Int8 nResult( DND_ACTION_NONE ); + + if ( m_aControlExchange.isDragSource() ) + nResult = implExecuteDataTransfer( *m_aControlExchange, rEvt.mnAction, rEvt.maPosPixel, sal_True ); + else + { + OControlTransferData aDroppedData( rEvt.maDropEvent.Transferable ); + nResult = implExecuteDataTransfer( aDroppedData, rEvt.mnAction, rEvt.maPosPixel, sal_True ); + } + + return nResult; + } + + //------------------------------------------------------------------------ + void NavigatorTree::doPaste() + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::doPaste" ); + try + { + if ( m_aControlExchange.isClipboardOwner() ) + { + implExecuteDataTransfer( *m_aControlExchange, doingKeyboardCut( ) ? DND_ACTION_MOVE : DND_ACTION_COPY, FirstSelected(), sal_False ); + } + else + { + // the clipboard content + Reference< XClipboard > xClipboard( GetClipboard() ); + Reference< XTransferable > xTransferable; + if ( xClipboard.is() ) + xTransferable = xClipboard->getContents(); + + OControlTransferData aClipboardContent( xTransferable ); + implExecuteDataTransfer( aClipboardContent, DND_ACTION_COPY, FirstSelected(), sal_False ); + } + } + catch( const Exception& ) + { + DBG_ERROR( "NavigatorTree::doPaste: caught an exception!" ); + } + } + + //------------------------------------------------------------------------ + void NavigatorTree::doCopy() + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::doCopy" ); + if ( implPrepareExchange( DND_ACTION_COPY ) ) + { + m_aControlExchange.setClipboardListener( LINK( this, NavigatorTree, OnClipboardAction ) ); + m_aControlExchange.copyToClipboard( ); + } + } + + //------------------------------------------------------------------------ + void NavigatorTree::ModelHasRemoved( SvListEntry* _pEntry ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::ModelHasRemoved" ); + SvLBoxEntry* pTypedEntry = static_cast< SvLBoxEntry* >( _pEntry ); + if ( doingKeyboardCut() ) + m_aCutEntries.erase( pTypedEntry ); + + if ( m_aControlExchange.isDataExchangeActive() ) + { + if ( 0 == m_aControlExchange->onEntryRemoved( pTypedEntry ) ) + { + // last of the entries which we put into the clipboard has been deleted from the tree. + // Give up the clipboard ownership. + m_aControlExchange.clear(); + } + } + } + + //------------------------------------------------------------------------ + void NavigatorTree::doCut() + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::doCut" ); + if ( implPrepareExchange( DND_ACTION_MOVE ) ) + { + m_aControlExchange.setClipboardListener( LINK( this, NavigatorTree, OnClipboardAction ) ); + m_aControlExchange.copyToClipboard( ); + m_bKeyboardCut = sal_True; + + // mark all the entries we just "cut" into the clipboard as "nearly moved" + for ( sal_Int32 i=0; i<m_arrCurrentSelection.Count(); ++i ) + { + SvLBoxEntry* pEntry = m_arrCurrentSelection[ (sal_uInt16)i ]; + if ( pEntry ) + { + m_aCutEntries.insert( pEntry ); + pEntry->SetFlags( pEntry->GetFlags() | SV_ENTRYFLAG_SEMITRANSPARENT ); + InvalidateEntry( pEntry ); + } + } + } + } + + //------------------------------------------------------------------------ + void NavigatorTree::KeyInput(const ::KeyEvent& rKEvt) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::KeyInput" ); + const KeyCode& rCode = rKEvt.GetKeyCode(); + + // delete? + if (rKEvt.GetKeyCode().GetCode() == KEY_DELETE && !rKEvt.GetKeyCode().GetModifier()) + { + DeleteSelection(); + return; + } + + // copy'n'paste? + switch ( rCode.GetFunction() ) + { + case KEYFUNC_CUT: + doCut(); + break; + + case KEYFUNC_PASTE: + if ( implAcceptPaste() ) + doPaste(); + break; + + case KEYFUNC_COPY: + doCopy(); + break; + + default: + break; + } + + SvTreeListBox::KeyInput(rKEvt); + } + + //------------------------------------------------------------------------ + sal_Bool NavigatorTree::EditingEntry( SvLBoxEntry* pEntry, Selection& rSelection ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::EditingEntry" ); + if (!SvTreeListBox::EditingEntry( pEntry, rSelection )) + return sal_False; + + return (pEntry && (pEntry->GetUserData() != NULL)); + // die Wurzel, die ich nicht umbenennen darf, hat als UserData NULL + } + + //------------------------------------------------------------------------ + void NavigatorTree::NewForm( SvLBoxEntry* pParentEntry ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::NewForm" ); + ////////////////////////////////////////////////////////////////////// + // ParentFormData holen + if( !IsFormEntry(pParentEntry) ) + return; + + FmFormData* pParentFormData = (FmFormData*)pParentEntry->GetUserData(); + + ////////////////////////////////////////////////////////////////////// + // Neue Form erzeugen + Reference< XForm > xNewForm(m_xORB->createInstance(FM_SUN_COMPONENT_FORM), UNO_QUERY); + if (!xNewForm.is()) + return; + + FmFormData* pNewFormData = new FmFormData( xNewForm, m_aNavigatorImages, pParentFormData ); + + ////////////////////////////////////////////////////////////////////// + // Namen setzen + ::rtl::OUString aName = GenerateName(pNewFormData); + pNewFormData->SetText(aName); + + Reference< XPropertySet > xPropertySet(xNewForm, UNO_QUERY); + if (!xPropertySet.is()) + return; + try + { + xPropertySet->setPropertyValue( FM_PROP_NAME, makeAny(aName) ); + // a form should always have the command type table as default + xPropertySet->setPropertyValue( FM_PROP_COMMANDTYPE, makeAny(sal_Int32(CommandType::TABLE))); + } + catch ( const Exception& ) + { + DBG_ERROR("NavigatorTree::NewForm : could not set esssential properties !"); + } + + + ////////////////////////////////////////////////////////////////////// + // Form einfuegen + GetNavModel()->Insert( pNewFormData, LIST_APPEND, sal_True ); + + ////////////////////////////////////////////////////////////////////// + // Neue Form als aktive Form setzen + FmFormShell* pFormShell = GetNavModel()->GetFormShell(); + if( pFormShell ) + { + InterfaceBag aSelection; + aSelection.insert( Reference< XInterface >( xNewForm, UNO_QUERY ) ); + pFormShell->GetImpl()->setCurrentSelection( aSelection ); + + pFormShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(SID_FM_PROPERTIES,sal_True,sal_True); + } + GetNavModel()->SetModified(); + + ////////////////////////////////////////////////////////////////////// + // In EditMode schalten + SvLBoxEntry* pNewEntry = FindEntry( pNewFormData ); + EditEntry( pNewEntry ); + } + + //------------------------------------------------------------------------ + FmControlData* NavigatorTree::NewControl( const ::rtl::OUString& rServiceName, SvLBoxEntry* pParentEntry, sal_Bool bEditName ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::NewControl" ); + ////////////////////////////////////////////////////////////////////// + // ParentForm holen + if (!GetNavModel()->GetFormShell()) + return NULL; + if (!IsFormEntry(pParentEntry)) + return NULL; + + FmFormData* pParentFormData = (FmFormData*)pParentEntry->GetUserData();; + Reference< XForm > xParentForm( pParentFormData->GetFormIface()); + + ////////////////////////////////////////////////////////////////////// + // Neue Component erzeugen + Reference< XFormComponent > xNewComponent(::comphelper::getProcessServiceFactory()->createInstance(rServiceName), UNO_QUERY); + if (!xNewComponent.is()) + return NULL; + + FmControlData* pNewFormControlData = new FmControlData( xNewComponent, m_aNavigatorImages, pParentFormData ); + + ////////////////////////////////////////////////////////////////////// + // Namen setzen + FmFormView* pFormView = GetNavModel()->GetFormShell()->GetFormView(); + SdrPageView* pPageView = pFormView->GetSdrPageView(); + FmFormPage* pPage = (FmFormPage*)pPageView->GetPage(); + + ::rtl::OUString sName = pPage->GetImpl().setUniqueName( xNewComponent, xParentForm ); + + pNewFormControlData->SetText( sName ); + + ////////////////////////////////////////////////////////////////////// + // FormComponent einfuegen + GetNavModel()->Insert( pNewFormControlData, LIST_APPEND, sal_True ); + GetNavModel()->SetModified(); + + if (bEditName) + { + ////////////////////////////////////////////////////////////////////// + // In EditMode schalten + SvLBoxEntry* pNewEntry = FindEntry( pNewFormControlData ); + Select( pNewEntry, sal_True ); + EditEntry( pNewEntry ); + } + + return pNewFormControlData; + } + + //------------------------------------------------------------------------ + ::rtl::OUString NavigatorTree::GenerateName( FmEntryData* pEntryData ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::GenerateName" ); + const sal_uInt16 nMaxCount = 99; + ::rtl::OUString aNewName; + + ////////////////////////////////////////////////////////////////////// + // BasisNamen erzeugen + UniString aBaseName; + if( pEntryData->ISA(FmFormData) ) + aBaseName = SVX_RES( RID_STR_STDFORMNAME ); + + else if( pEntryData->ISA(FmControlData) ) + aBaseName = SVX_RES( RID_STR_CONTROL ); + + ////////////////////////////////////////////////////////////////////// + // Neuen Namen erstellen + FmFormData* pFormParentData = (FmFormData*)pEntryData->GetParent(); + + for( sal_Int32 i=0; i<nMaxCount; i++ ) + { + aNewName = aBaseName; + if( i>0 ) + { + aNewName += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" ")); + aNewName += ::rtl::OUString::valueOf(i).getStr(); + } + + if( GetNavModel()->FindData(aNewName, pFormParentData,sal_False) == NULL ) + break; + } + + return aNewName; + } + + //------------------------------------------------------------------------ + sal_Bool NavigatorTree::EditedEntry( SvLBoxEntry* pEntry, const XubString& rNewText ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::EditedEntry" ); + if (EditingCanceled()) + return sal_True; + + GrabFocus(); + FmEntryData* pEntryData = (FmEntryData*)pEntry->GetUserData(); + sal_Bool bRes = GetNavModel()->Rename( pEntryData, rNewText); + if( !bRes ) + { + m_pEditEntry = pEntry; + nEditEvent = Application::PostUserEvent( LINK(this, NavigatorTree, OnEdit) ); + } else + SetCursor(pEntry, sal_True); + + return bRes; + } + + //------------------------------------------------------------------------ + IMPL_LINK( NavigatorTree, OnEdit, void*, EMPTYARG ) + { + nEditEvent = 0; + EditEntry( m_pEditEntry ); + m_pEditEntry = NULL; + + return 0L; + } + + //------------------------------------------------------------------------ + IMPL_LINK( NavigatorTree, OnDropActionTimer, void*, EMPTYARG ) + { + if (--m_aTimerCounter > 0) + return 0L; + + switch ( m_aDropActionType ) + { + case DA_EXPANDNODE: + { + SvLBoxEntry* pToExpand = GetEntry(m_aTimerTriggered); + if (pToExpand && (GetChildCount(pToExpand) > 0) && !IsExpanded(pToExpand)) + // tja, eigentlich muesste ich noch testen, ob die Node nicht schon expandiert ist, aber ich + // habe dazu weder in den Basisklassen noch im Model eine Methode gefunden ... + // aber ich denke, die BK sollte es auch so vertragen + Expand(pToExpand); + + // nach dem Expand habe ich im Gegensatz zum Scrollen natuerlich nix mehr zu tun + m_aDropActionTimer.Stop(); + } + break; + + case DA_SCROLLUP : + ScrollOutputArea( 1 ); + m_aTimerCounter = DROP_ACTION_TIMER_SCROLL_TICKS; + break; + + case DA_SCROLLDOWN : + ScrollOutputArea( -1 ); + m_aTimerCounter = DROP_ACTION_TIMER_SCROLL_TICKS; + break; + + } + + return 0L; + } + + //------------------------------------------------------------------------ + IMPL_LINK(NavigatorTree, OnEntrySelDesel, NavigatorTree*, /*pThis*/) + { + m_sdiState = SDI_DIRTY; + + if (IsSelectionHandlingLocked()) + return 0L; + + if (m_aSynchronizeTimer.IsActive()) + m_aSynchronizeTimer.Stop(); + + m_aSynchronizeTimer.SetTimeout(EXPLORER_SYNC_DELAY); + m_aSynchronizeTimer.Start(); + + return 0L; + } + + //------------------------------------------------------------------------ + IMPL_LINK(NavigatorTree, OnSynchronizeTimer, void*, EMPTYARG) + { + SynchronizeMarkList(); + return 0L; + } + + + //------------------------------------------------------------------------ + IMPL_LINK( NavigatorTree, OnClipboardAction, void*, EMPTYARG ) + { + if ( !m_aControlExchange.isClipboardOwner() ) + { + if ( doingKeyboardCut() ) + { + for ( ListBoxEntrySet::const_iterator i = m_aCutEntries.begin(); + i != m_aCutEntries.end(); + ++i + ) + { + SvLBoxEntry* pEntry = *i; + if ( !pEntry ) + continue; + + pEntry->SetFlags( pEntry->GetFlags() & ~SV_ENTRYFLAG_SEMITRANSPARENT ); + InvalidateEntry( pEntry ); + } + ListBoxEntrySet aEmpty; + m_aCutEntries.swap( aEmpty ); + + m_bKeyboardCut = sal_False; + } + } + return 0L; + } + + //------------------------------------------------------------------------ + void NavigatorTree::ShowSelectionProperties(sal_Bool bForce) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::ShowSelectionProperties" ); + // zuerst brauche ich die FormShell + FmFormShell* pFormShell = GetNavModel()->GetFormShell(); + if (!pFormShell) + // keine Shell -> ich koennte kein curObject setzen -> raus + return; + + CollectSelectionData(SDI_ALL); + DBG_ASSERT( m_nFormsSelected + m_nControlsSelected + (m_bRootSelected ? 1 : 0) == m_arrCurrentSelection.Count(), + "NavigatorTree::ShowSelectionProperties : selection meta data invalid !"); + + + InterfaceBag aSelection; + sal_Bool bSetSelectionAsMarkList = sal_False; + + if (m_bRootSelected) + ; // no properties for the root, neither for single nor for multi selection + else if ( m_nFormsSelected + m_nControlsSelected == 0 ) // none of the two should be less 0 + ; // no selection -> no properties + else if ( m_nFormsSelected * m_nControlsSelected != 0 ) + ; // mixed selection -> no properties + else + { // either only forms, or only controls are selected + if (m_arrCurrentSelection.Count() == 1) + { + if (m_nFormsSelected > 0) + { // es ist genau eine Form selektiert + FmFormData* pFormData = (FmFormData*)m_arrCurrentSelection.GetObject(0)->GetUserData(); + aSelection.insert( Reference< XInterface >( pFormData->GetFormIface(), UNO_QUERY ) ); + } + else + { // es ist genau ein Control selektiert (egal ob hidden oder normal) + FmEntryData* pEntryData = (FmEntryData*)m_arrCurrentSelection.GetObject(0)->GetUserData(); + + aSelection.insert( Reference< XInterface >( pEntryData->GetElement(), UNO_QUERY ) ); + } + } + else + { // wir haben eine MultiSelection, also muessen wir ein MultiSet dafuer aufbauen + if (m_nFormsSelected > 0) + { // ... nur Forms + // erstmal die PropertySet-Interfaces der Forms einsammeln + for ( sal_Int32 i = 0; i < m_nFormsSelected; ++i ) + { + FmFormData* pFormData = (FmFormData*)m_arrCurrentSelection.GetObject((USHORT)i)->GetUserData(); + aSelection.insert( pFormData->GetPropertySet().get() ); + } + } + else + { // ... nur Controls + if (m_nHiddenControls == m_nControlsSelected) + { // ein MultiSet fuer die Properties der hidden controls + for ( sal_Int32 i = 0; i < m_nHiddenControls; ++i ) + { + FmEntryData* pEntryData = (FmEntryData*)m_arrCurrentSelection.GetObject((USHORT)i)->GetUserData(); + aSelection.insert( pEntryData->GetPropertySet().get() ); + } + } + else if (m_nHiddenControls == 0) + { // nur normale Controls + bSetSelectionAsMarkList = sal_True; + } + } + } + + } + + // und dann meine Form und mein SelObject + if ( bSetSelectionAsMarkList ) + pFormShell->GetImpl()->setCurrentSelectionFromMark( pFormShell->GetFormView()->GetMarkedObjectList() ); + else + pFormShell->GetImpl()->setCurrentSelection( aSelection ); + + if ( pFormShell->GetImpl()->IsPropBrwOpen() || bForce ) + { + // und jetzt kann ich das Ganze dem PropertyBrowser uebergeben + pFormShell->GetViewShell()->GetViewFrame()->GetDispatcher()->Execute( SID_FM_SHOW_PROPERTY_BROWSER, SFX_CALLMODE_ASYNCHRON ); + } + } + + //------------------------------------------------------------------------ + void NavigatorTree::DeleteSelection() + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::DeleteSelection" ); + // die Root darf ich natuerlich nicht mitloeschen + sal_Bool bRootSelected = IsSelected(m_pRootEntry); + ULONG nSelectedEntries = GetSelectionCount(); + if (bRootSelected && (nSelectedEntries > 1)) // die Root plus andere Elemente ? + Select(m_pRootEntry, sal_False); // ja -> die Root raus + + if ((nSelectedEntries == 0) || bRootSelected) // immer noch die Root ? + return; // -> sie ist das einzige selektierte -> raus + + DBG_ASSERT(!m_bPrevSelectionMixed, "NavigatorTree::DeleteSelection() : loeschen nicht erlaubt wenn Markierung und Selektion nciht konsistent"); + + // ich brauche unten das FormModel ... + FmFormShell* pFormShell = GetNavModel()->GetFormShell(); + if (!pFormShell) + return; + FmFormModel* pFormModel = pFormShell ? pFormShell->GetFormModel() : NULL; + if (!pFormModel) + return; + + // jetzt muss ich noch die DeleteList etwas absichern : wenn man ein Formular und ein abhaengiges + // Element loescht - und zwar in dieser Reihenfolge - dann ist der SvLBoxEntryPtr des abhaengigen Elementes + // natuerlich schon ungueltig, wenn es geloescht werden soll ... diesen GPF, den es dann mit Sicherheit gibt, + // gilt es zu verhindern, also die 'normalisierte' Liste + CollectSelectionData( SDI_NORMALIZED ); + + // see below for why we need this mapping from models to shapes + FmFormView* pFormView = pFormShell->GetFormView(); + SdrPageView* pPageView = pFormView ? pFormView->GetSdrPageView() : NULL; + SdrPage* pPage = pPageView ? pPageView->GetPage() : NULL; + DBG_ASSERT( pPage, "NavigatorTree::DeleteSelection: invalid form page!" ); + + MapModelToShape aModelShapes; + if ( pPage ) + collectShapeModelMapping( pPage, aModelShapes ); + + // problem: we have to use ExplorerModel::Remove, since only this one properly deletes Form objects. + // But, the controls themself must be deleted via DeleteMarked (else, the Writer has some problems + // somewhere). In case I'd first delete the structure, then the controls, the UNDO would not work + // (since UNDO then would mean to first restore the controls, then the structure, means their parent + // form). The other way round, the EntryDatas would be invalid, if I'd first delete the controls and + // then go on to the strucure. This means I have to delete the forms *after* the normal controls, so + // that during UNDO, they're restored in the proper order. + pFormShell->GetImpl()->EnableTrackProperties(sal_False); + USHORT i; + for (i = m_arrCurrentSelection.Count(); i>0; --i) + { + FmEntryData* pCurrent = (FmEntryData*)(m_arrCurrentSelection.GetObject(i - 1)->GetUserData()); + + // eine Form ? + sal_Bool bIsForm = pCurrent->ISA(FmFormData); + + // da ich das Loeschen im folgenden der View ueberlasse und dabei auf deren MarkList aufbaue, im Normalfall aber bei + // einem makierten Formular nur die direkt, nicht die indirekt abhaengigen Controls markiert werden, muss ich das hier + // noch nachholen + if (bIsForm) + MarkViewObj((FmFormData*)pCurrent, sal_True, sal_True); // das zweite sal_True heisst "deep" + + // ein hidden control ? + sal_Bool bIsHidden = IsHiddenControl(pCurrent); + + // Forms und hidden Controls muss ich behalten, alles andere nicht + if (!bIsForm && !bIsHidden) + { + // well, no form and no hidden control -> we can remove it from m_arrCurrentSelection, as it will + // be deleted automatically. This is because for every model (except forms and hidden control models) + // there exist a shape, which is marked _if_and_only_if_ the model is selected in our tree. + if ( aModelShapes.find( pCurrent->GetElement() ) != aModelShapes.end() ) + { + // if there's a shape for the current entry, then either it is marked or it is in a + // hidden layer (#i28502#), or something like this. + // In the first case, it will be deleted below, in the second case, we currently don't + // delete it, as there's no real (working!) API for this, neither in UNO nor in non-UNO. + m_arrCurrentSelection.Remove( i - 1, 1 ); + } + // In case there is no shape for the current entry, we keep the entry in m_arrCurrentSelection, + // since then we can definately remove it. + // #103597# + } + } + pFormShell->GetImpl()->EnableTrackProperties(sal_True); + + // let the view delete the marked controls + pFormShell->GetFormView()->DeleteMarked(); + + // start UNDO at this point. Unfortunately, this results in 2 UNDO actions, since DeleteMarked is + // creating an own one. However, if we'd move it before DeleteMarked, Writer does not really like + // this ... :( + // 2004-07-05 - #i31038# - fs@openoffice.org + { + // --------------- + // initialize UNDO + String aUndoStr; + if ( m_arrCurrentSelection.Count() == 1 ) + { + aUndoStr = SVX_RES(RID_STR_UNDO_CONTAINER_REMOVE); + if (m_nFormsSelected) + aUndoStr.SearchAndReplaceAscii( "#", SVX_RES( RID_STR_FORM ) ); + else + // it must be a control (else the root would be selected, but it cannot be deleted) + aUndoStr.SearchAndReplaceAscii( "#", SVX_RES( RID_STR_CONTROL ) ); + } + else + { + aUndoStr = SVX_RES(RID_STR_UNDO_CONTAINER_REMOVE_MULTIPLE); + aUndoStr.SearchAndReplaceAscii( "#", String::CreateFromInt32( m_arrCurrentSelection.Count() ) ); + } + pFormModel->BegUndo(aUndoStr); + } + + // remove remaining structure + for (i=0; i<m_arrCurrentSelection.Count(); ++i) + { + FmEntryData* pCurrent = (FmEntryData*)(m_arrCurrentSelection.GetObject(i)->GetUserData()); + + // if the entry still has children, we skipped deletion of one of those children. + // This may for instance be because the shape is in a hidden layer, where we're unable + // to remove it + if ( pCurrent->GetChildList()->size() ) + continue; + + // noch ein kleines Problem, bevor ich das ganz loesche : wenn es eine Form ist und die Shell diese als CurrentObject + // kennt, dann muss ich ihr das natuerlich ausreden + if (pCurrent->ISA(FmFormData)) + { + Reference< XForm > xCurrentForm( static_cast< FmFormData* >( pCurrent )->GetFormIface() ); + if ( pFormShell->GetImpl()->getCurrentForm() == xCurrentForm ) // die Shell kennt die zu loeschende Form ? + pFormShell->GetImpl()->forgetCurrentForm(); // -> wegnehmen ... + } + GetNavModel()->Remove(pCurrent, sal_True); + } + pFormModel->EndUndo(); + } + + //------------------------------------------------------------------------ + void NavigatorTree::CollectSelectionData(SELDATA_ITEMS sdiHow) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::CollectSelectionData" ); + DBG_ASSERT(sdiHow != SDI_DIRTY, "NavigatorTree::CollectSelectionData : ever thought about your parameter ? DIRTY ?"); + if (sdiHow == m_sdiState) + return; + + m_arrCurrentSelection.Remove((sal_uInt16)0, m_arrCurrentSelection.Count()); + m_nFormsSelected = m_nControlsSelected = m_nHiddenControls = 0; + m_bRootSelected = sal_False; + + SvLBoxEntry* pSelectionLoop = FirstSelected(); + while (pSelectionLoop) + { + // erst mal die Zaehlung der verschiedenen Elemente + if (pSelectionLoop == m_pRootEntry) + m_bRootSelected = sal_True; + else + { + if (IsFormEntry(pSelectionLoop)) + ++m_nFormsSelected; + else + { + ++m_nControlsSelected; + if (IsHiddenControl((FmEntryData*)(pSelectionLoop->GetUserData()))) + ++m_nHiddenControls; + } + } + + if (sdiHow == SDI_NORMALIZED) + { + // alles, was schon einen selektierten Vorfahr hat, nicht mitnehmen + if (pSelectionLoop == m_pRootEntry) + m_arrCurrentSelection.Insert(pSelectionLoop); + else + { + SvLBoxEntry* pParentLoop = GetParent(pSelectionLoop); + while (pParentLoop) + { + // eigentlich muesste ich testen, ob das Parent in der m_arrCurrentSelection steht ... + // Aber wenn es selektiert ist, dann steht es in m_arrCurrentSelection, oder wenigstens einer seiner Vorfahren, + // wenn der auch schon selektiert war. In beiden Faellen reicht also die Abfrage IsSelected + if (IsSelected(pParentLoop)) + break; + else + { + if (m_pRootEntry == pParentLoop) + { + // bis (exclusive) zur Root gab es kein selektiertes Parent -> der Eintrag gehoert in die normalisierte Liste + m_arrCurrentSelection.Insert(pSelectionLoop); + break; + } + else + pParentLoop = GetParent(pParentLoop); + } + } + } + } + else if (sdiHow == SDI_NORMALIZED_FORMARK) + { + SvLBoxEntry* pParent = GetParent(pSelectionLoop); + if (!pParent || !IsSelected(pParent) || IsFormEntry(pSelectionLoop)) + m_arrCurrentSelection.Insert(pSelectionLoop); + } + else + m_arrCurrentSelection.Insert(pSelectionLoop); + + + pSelectionLoop = NextSelected(pSelectionLoop); + } + + m_sdiState = sdiHow; + } + + //------------------------------------------------------------------------ + void NavigatorTree::SynchronizeSelection(FmEntryDataArray& arredToSelect) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::SynchronizeSelection" ); + LockSelectionHandling(); + if (arredToSelect.Count() == 0) + { + SelectAll(sal_False); + } + else + { + // erst mal gleiche ich meine aktuelle Selektion mit der geforderten SelectList ab + SvLBoxEntry* pSelection = FirstSelected(); + while (pSelection) + { + FmEntryData* pCurrent = (FmEntryData*)pSelection->GetUserData(); + if (pCurrent != NULL) + { + sal_uInt16 nPosition; + if ( arredToSelect.Seek_Entry(pCurrent, &nPosition) ) + { // der Entry ist schon selektiert, steht aber auch in der SelectList -> er kann aus letzterer + // raus + arredToSelect.Remove(nPosition, 1); + } else + { // der Entry ist selektiert, aber steht nicht in der SelectList -> Selektion rausnehmen + Select(pSelection, sal_False); + // und sichtbar machen (kann ja sein, dass das die einzige Modifikation ist, die ich hier in dem + // ganzen Handler mache, dann sollte das zu sehen sein) + MakeVisible(pSelection); + } + } + else + Select(pSelection, sal_False); + + pSelection = NextSelected(pSelection); + } + + // jetzt habe ich in der SelectList genau die Eintraege, die noch selektiert werden muessen + // zwei Moeglichkeiten : 1) ich gehe durch die SelectList, besorge mir zu jedem Eintrag meinen SvLBoxEntry + // und selektiere diesen (waere irgendwie intuitiver ;)) 2) ich gehe durch alle meine SvLBoxEntries und selektiere + // genau die, die ich in der SelectList finde + // 1) braucht O(k*n) (k=Laenge der SelectList, n=Anzahl meiner Entries), plus den Fakt, dass FindEntry nicht den + // Pointer auf die UserDaten vergleicht, sondern ein aufwendigeres IsEqualWithoutChilds durchfuehrt + // 2) braucht O(n*log k), dupliziert aber etwas Code (naemlich den aus FindEntry) + // da das hier eine relativ oft aufgerufenen Stelle sein koennte (bei jeder Aenderung in der Markierung in der View !), + // nehme ich doch lieber letzteres + SvLBoxEntry* pLoop = First(); + while( pLoop ) + { + FmEntryData* pCurEntryData = (FmEntryData*)pLoop->GetUserData(); + sal_uInt16 nPosition; + if ( arredToSelect.Seek_Entry(pCurEntryData, &nPosition) ) + { + Select(pLoop, sal_True); + MakeVisible(pLoop); + SetCursor(pLoop, sal_True); + } + + pLoop = Next( pLoop ); + } + } + UnlockSelectionHandling(); + } + + //------------------------------------------------------------------------ + void NavigatorTree::SynchronizeSelection() + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::SynchronizeSelection" ); + // Shell und View + FmFormShell* pFormShell = GetNavModel()->GetFormShell(); + if(!pFormShell) return; + + FmFormView* pFormView = pFormShell->GetFormView(); + if (!pFormView) return; + + GetNavModel()->BroadcastMarkedObjects(pFormView->GetMarkedObjectList()); + } + + //------------------------------------------------------------------------ + void NavigatorTree::SynchronizeMarkList() + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::SynchronizeMarkList" ); + // die Shell werde ich brauchen ... + FmFormShell* pFormShell = GetNavModel()->GetFormShell(); + if (!pFormShell) return; + + CollectSelectionData(SDI_NORMALIZED_FORMARK); + + // Die View soll jetzt kein Notify bei einer Aenderung der MarkList rauslassen + pFormShell->GetImpl()->EnableTrackProperties(sal_False); + + UnmarkAllViewObj(); + + for (sal_uInt32 i=0; i<m_arrCurrentSelection.Count(); ++i) + { + SvLBoxEntry* pSelectionLoop = m_arrCurrentSelection.GetObject((USHORT)i); + // Bei Formselektion alle Controls dieser Form markieren + if (IsFormEntry(pSelectionLoop) && (pSelectionLoop != m_pRootEntry)) + MarkViewObj((FmFormData*)pSelectionLoop->GetUserData(), sal_True, sal_False); + + // Bei Controlselektion Control-SdrObjects markieren + else if (IsFormComponentEntry(pSelectionLoop)) + { + FmControlData* pControlData = (FmControlData*)pSelectionLoop->GetUserData(); + if (pControlData) + { + ///////////////////////////////////////////////////////////////// + // Beim HiddenControl kann kein Object selektiert werden + Reference< XFormComponent > xFormComponent( pControlData->GetFormComponent()); + if (!xFormComponent.is()) + continue; + Reference< XPropertySet > xSet(xFormComponent, UNO_QUERY); + if (!xSet.is()) + continue; + + sal_uInt16 nClassId = ::comphelper::getINT16(xSet->getPropertyValue(FM_PROP_CLASSID)); + if (nClassId != FormComponentType::HIDDENCONTROL) + MarkViewObj(pControlData, sal_True, sal_True); + } + } + } + + // wenn der PropertyBrowser offen ist, muss ich den entsprechend meiner Selektion anpassen + // (NICHT entsprechend der MarkList der View : wenn ich ein Formular selektiert habe, sind in der + // View alle zugehoerigen Controls markiert, trotzdem moechte ich natuerlich die Formular-Eigenschaften + // sehen) + ShowSelectionProperties(sal_False); + + // Flag an View wieder zuruecksetzen + pFormShell->GetImpl()->EnableTrackProperties(sal_True); + + // wenn jetzt genau eine Form selektiert ist, sollte die Shell das als CurrentForm mitbekommen + // (wenn SelectionHandling nicht locked ist, kuemmert sich die View eigentlich in MarkListHasChanged drum, + // aber der Mechanismus greift zum Beispiel nicht, wenn die Form leer ist) + if ((m_arrCurrentSelection.Count() == 1) && (m_nFormsSelected == 1)) + { + FmFormData* pSingleSelectionData = PTR_CAST( FmFormData, static_cast< FmEntryData* >( FirstSelected()->GetUserData() ) ); + DBG_ASSERT( pSingleSelectionData, "NavigatorTree::SynchronizeMarkList: invalid selected form!" ); + if ( pSingleSelectionData ) + { + InterfaceBag aSelection; + aSelection.insert( Reference< XInterface >( pSingleSelectionData->GetFormIface(), UNO_QUERY ) ); + pFormShell->GetImpl()->setCurrentSelection( aSelection ); + } + } + } + + //------------------------------------------------------------------------ + sal_Bool NavigatorTree::IsHiddenControl(FmEntryData* pEntryData) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::IsHiddenControl" ); + if (pEntryData == NULL) return sal_False; + + Reference< XPropertySet > xProperties( pEntryData->GetPropertySet() ); + if (::comphelper::hasProperty(FM_PROP_CLASSID, xProperties)) + { + Any aClassID = xProperties->getPropertyValue( FM_PROP_CLASSID ); + return (::comphelper::getINT16(aClassID) == FormComponentType::HIDDENCONTROL); + } + return sal_False; + } + + //------------------------------------------------------------------------ + sal_Bool NavigatorTree::Select( SvLBoxEntry* pEntry, sal_Bool bSelect ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::Select" ); + if (bSelect == IsSelected(pEntry)) // das passiert manchmal, ich glaube, die Basisklasse geht zu sehr auf Nummer sicher ;) + return sal_True; + + return SvTreeListBox::Select(pEntry, bSelect ); + } + + //------------------------------------------------------------------------ + void NavigatorTree::UnmarkAllViewObj() + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::UnmarkAllViewObj" ); + FmFormShell* pFormShell = GetNavModel()->GetFormShell(); + if( !pFormShell ) + return; + FmFormView* pFormView = pFormShell->GetFormView(); + pFormView->UnMarkAll(); + } + //------------------------------------------------------------------------ + void NavigatorTree::MarkViewObj(FmFormData* pFormData, sal_Bool bMark, sal_Bool bDeep ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::MarkViewObjects" ); + FmFormShell* pFormShell = GetNavModel()->GetFormShell(); + if( !pFormShell ) + return; + + // first collect all sdrobjects + ::std::set< Reference< XFormComponent > > aObjects; + CollectObjects(pFormData,bDeep,aObjects); + + ////////////////////////////////////////////////////////////////////// + // In der Page das entsprechende SdrObj finden und selektieren + FmFormView* pFormView = pFormShell->GetFormView(); + SdrPageView* pPageView = pFormView->GetSdrPageView(); + SdrPage* pPage = pPageView->GetPage(); + //FmFormPage* pFormPage = dynamic_cast< FmFormPage* >( pPage ); + + SdrObjListIter aIter( *pPage ); + while ( aIter.IsMore() ) + { + SdrObject* pSdrObject = aIter.Next(); + FmFormObj* pFormObject = FmFormObj::GetFormObject( pSdrObject ); + if ( !pFormObject ) + continue; + + Reference< XFormComponent > xControlModel( pFormObject->GetUnoControlModel(),UNO_QUERY ); + if ( xControlModel.is() && aObjects.find(xControlModel) != aObjects.end() && bMark != pFormView->IsObjMarked( pSdrObject ) ) + { + // unfortunately, the writer doesn't like marking an already-marked object, again, so reset the mark first + pFormView->MarkObj( pSdrObject, pPageView, !bMark, sal_False ); + } + } // while ( aIter.IsMore() ) + if ( bMark ) + { + // make the mark visible + ::Rectangle aMarkRect( pFormView->GetAllMarkedRect()); + for ( sal_uInt32 i = 0; i < pFormView->PaintWindowCount(); ++i ) + { + SdrPaintWindow* pPaintWindow = pFormView->GetPaintWindow( i ); + OutputDevice& rOutDev = pPaintWindow->GetOutputDevice(); + if ( ( OUTDEV_WINDOW == rOutDev.GetOutDevType() ) && !aMarkRect.IsEmpty() ) + { + pFormView->MakeVisible( aMarkRect, (Window&)rOutDev ); + } + } // for ( sal_uInt32 i = 0; i < pFormView->PaintWindowCount(); ++i ) + } + } + //------------------------------------------------------------------------ + void NavigatorTree::CollectObjects(FmFormData* pFormData, sal_Bool bDeep, ::std::set< Reference< XFormComponent > >& _rObjects) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::MarkViewObjects" ); + FmEntryDataList* pChildList = pFormData->GetChildList(); + FmEntryData* pEntryData; + FmControlData* pControlData; + for( size_t i = 0; i < pChildList->size(); ++i ) + { + pEntryData = pChildList->at( i ); + if( pEntryData->ISA(FmControlData) ) + { + pControlData = (FmControlData*)pEntryData; + _rObjects.insert(pControlData->GetFormComponent()); + } // if( pEntryData->ISA(FmControlData) ) + else if (bDeep && (pEntryData->ISA(FmFormData))) + CollectObjects((FmFormData*)pEntryData,bDeep,_rObjects); + } // for( sal_uInt32 i=0; i<pChildList->Count(); i++ ) + } + //------------------------------------------------------------------------ + void NavigatorTree::MarkViewObj( FmControlData* pControlData, sal_Bool bMarkHandles, sal_Bool bMark) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTree::MarkViewObj" ); + if( !pControlData ) + return; + FmFormShell* pFormShell = GetNavModel()->GetFormShell(); + if( !pFormShell ) + return; + + ////////////////////////////////////////////////////////////////////// + // In der Page das entsprechende SdrObj finden und selektieren + FmFormView* pFormView = pFormShell->GetFormView(); + Reference< XFormComponent > xFormComponent( pControlData->GetFormComponent()); + SdrPageView* pPageView = pFormView->GetSdrPageView(); + SdrPage* pPage = pPageView->GetPage(); + + bool bPaint = false; + SdrObjListIter aIter( *pPage ); + while ( aIter.IsMore() ) + { + SdrObject* pSdrObject = aIter.Next(); + FmFormObj* pFormObject = FmFormObj::GetFormObject( pSdrObject ); + if ( !pFormObject ) + continue; + + Reference< XInterface > xControlModel( pFormObject->GetUnoControlModel() ); + if ( xControlModel != xFormComponent ) + continue; + + // mark the object + if ( bMark != pFormView->IsObjMarked( pSdrObject ) ) + // unfortunately, the writer doesn't like marking an already-marked object, again, so reset the mark first + pFormView->MarkObj( pSdrObject, pPageView, !bMark, sal_False ); + + if ( !bMarkHandles || !bMark ) + continue; + + bPaint = true; + + } // while ( aIter.IsMore() ) + if ( bPaint ) + { + // make the mark visible + ::Rectangle aMarkRect( pFormView->GetAllMarkedRect()); + for ( sal_uInt32 i = 0; i < pFormView->PaintWindowCount(); ++i ) + { + SdrPaintWindow* pPaintWindow = pFormView->GetPaintWindow( i ); + OutputDevice& rOutDev = pPaintWindow->GetOutputDevice(); + if ( OUTDEV_WINDOW == rOutDev.GetOutDevType() ) + { + pFormView->MakeVisible( aMarkRect, (Window&)rOutDev ); + } + } // for ( sal_uInt32 i = 0; i < pFormView->PaintWindowCount(); ++i ) + } + } + +//............................................................................ +} // namespace svxform +//............................................................................ + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/navigatortreemodel.cxx b/svx/source/form/navigatortreemodel.cxx new file mode 100644 index 000000000000..b792200956d8 --- /dev/null +++ b/svx/source/form/navigatortreemodel.cxx @@ -0,0 +1,1120 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include <svx/dialmgr.hxx> +#include <svx/fmshell.hxx> +#include <svx/fmmodel.hxx> +#include <svx/fmpage.hxx> +#include <svx/fmglob.hxx> +#include "svditer.hxx" +#include <svx/svdogrp.hxx> +#include <svx/svdpagv.hxx> + +#include "fmprop.hrc" + +#include "fmundo.hxx" +#include "fmhelp.hrc" +#include "fmexpl.hrc" +#include "fmexpl.hxx" +#include "fmresids.hrc" +#include "fmshimp.hxx" +#include "fmobj.hxx" +#include <sfx2/objsh.hxx> +#include <tools/diagnose_ex.h> +#include <rtl/logfile.hxx> +#include <com/sun/star/container/XContainer.hpp> + +//............................................................................ +namespace svxform +{ +//............................................................................ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::form; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::script; + using namespace ::com::sun::star::sdb; + + //======================================================================== + // class OFormComponentObserver + //======================================================================== + //------------------------------------------------------------------------ + OFormComponentObserver::OFormComponentObserver(NavigatorTreeModel* _pModel) + :m_pNavModel(_pModel) + ,m_nLocks(0) + ,m_bCanUndo(sal_True) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "OFormComponentObserver::OFormComponentObserver" ); + } + + // XPropertyChangeListener + //------------------------------------------------------------------------ + void SAL_CALL OFormComponentObserver::disposing(const EventObject& Source) throw( RuntimeException ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "OFormComponentObserver::disposing" ); + Remove( Source.Source ); + } + + //------------------------------------------------------------------------ + void SAL_CALL OFormComponentObserver::propertyChange(const PropertyChangeEvent& evt) throw(RuntimeException) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "OFormComponentObserver::propertyChange" ); + if( !m_pNavModel ) return; + if( evt.PropertyName != FM_PROP_NAME ) return; + + Reference< XFormComponent > xFormComponent(evt.Source, UNO_QUERY); + Reference< XForm > xForm(evt.Source, UNO_QUERY); + + FmEntryData* pEntryData( NULL ); + if( xForm.is() ) + pEntryData = m_pNavModel->FindData( xForm, m_pNavModel->GetRootList() ); + else if( xFormComponent.is() ) + pEntryData = m_pNavModel->FindData( xFormComponent, m_pNavModel->GetRootList() ); + + if( pEntryData ) + { + ::rtl::OUString aNewName = ::comphelper::getString(evt.NewValue); + pEntryData->SetText( aNewName ); + FmNavNameChangedHint aNameChangedHint( pEntryData, aNewName ); + m_pNavModel->Broadcast( aNameChangedHint ); + } + } + + // XContainerListener + //------------------------------------------------------------------------------ + void SAL_CALL OFormComponentObserver::elementInserted(const ContainerEvent& evt) throw(RuntimeException) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "OFormComponentObserver::elementInserted" ); + if (IsLocked() || !m_pNavModel) + return; + + // keine Undoaction einfuegen + m_bCanUndo = sal_False; + + Reference< XInterface > xTemp; + evt.Element >>= xTemp; + Insert(xTemp, ::comphelper::getINT32(evt.Accessor)); + + m_bCanUndo = sal_True; + } + + //------------------------------------------------------------------------------ + void OFormComponentObserver::Insert(const Reference< XInterface > & xIface, sal_Int32 nIndex) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "OFormComponentObserver::Insert" ); + Reference< XForm > xForm(xIface, UNO_QUERY); + if (xForm.is()) + { + m_pNavModel->InsertForm(xForm, sal_uInt32(nIndex)); + Reference< XIndexContainer > xContainer(xForm, UNO_QUERY); + Reference< XInterface > xTemp; + for (sal_Int32 i = 0; i < xContainer->getCount(); i++) + { + xContainer->getByIndex(i) >>= xTemp; + Insert(xTemp, i); + } + } + else + { + Reference< XFormComponent > xFormComp(xIface, UNO_QUERY); + if (xFormComp.is()) + m_pNavModel->InsertFormComponent(xFormComp, sal_uInt32(nIndex)); + } + } + + //------------------------------------------------------------------------------ + void SAL_CALL OFormComponentObserver::elementReplaced(const ContainerEvent& evt) throw(RuntimeException) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "OFormComponentObserver::elementReplaced" ); + if (IsLocked() || !m_pNavModel) + return; + + m_bCanUndo = sal_False; + + // EntryData loeschen + Reference< XFormComponent > xReplaced; + evt.ReplacedElement >>= xReplaced; + FmEntryData* pEntryData = m_pNavModel->FindData(xReplaced, m_pNavModel->GetRootList(), sal_True); + if (pEntryData) + { + if (pEntryData->ISA(FmControlData)) + { + Reference< XFormComponent > xComp; + evt.Element >>= xComp; + DBG_ASSERT(xComp.is(), "OFormComponentObserver::elementReplaced : invalid argument !"); + // an einer FmControlData sollte eine XFormComponent haengen + m_pNavModel->ReplaceFormComponent(xReplaced, xComp); + } + else if (pEntryData->ISA(FmFormData)) + { + DBG_ERROR("replacing forms not implemented yet !"); + } + } + + m_bCanUndo = sal_True; + } + + //------------------------------------------------------------------------------ + void OFormComponentObserver::Remove( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxElement ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "OFormComponentObserver::Remove" ); + if (IsLocked() || !m_pNavModel) + return; + + m_bCanUndo = sal_False; + + ////////////////////////////////////////////////////////// + // EntryData loeschen + FmEntryData* pEntryData = m_pNavModel->FindData( _rxElement, m_pNavModel->GetRootList(), sal_True ); + if (pEntryData) + m_pNavModel->Remove(pEntryData); + + m_bCanUndo = sal_True; + } + + //------------------------------------------------------------------------------ + void SAL_CALL OFormComponentObserver::elementRemoved(const ContainerEvent& evt) throw(RuntimeException) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "OFormComponentObserver::elementRemoved" ); + Reference< XInterface > xElement; + evt.Element >>= xElement; + Remove( xElement ); + } + + //======================================================================== + // class NavigatorTreeModel + //======================================================================== + + //------------------------------------------------------------------------ + NavigatorTreeModel::NavigatorTreeModel( const ImageList& _rNormalImages ) + :m_pFormShell(NULL) + ,m_pFormPage(NULL) + ,m_pFormModel(NULL) + ,m_aNormalImages( _rNormalImages ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::NavigatorTreeModel" ); + m_pPropChangeList = new OFormComponentObserver(this); + m_pPropChangeList->acquire(); + m_pRootList = new FmEntryDataList(); + } + + //------------------------------------------------------------------------ + NavigatorTreeModel::~NavigatorTreeModel() + { + ////////////////////////////////////////////////////////////////////// + // Als Listener abmelden + if( m_pFormShell) + { + FmFormModel* pFormModel = m_pFormShell->GetFormModel(); + if( pFormModel && IsListening(*pFormModel)) + EndListening( *pFormModel ); + + if (IsListening(*m_pFormShell)) + EndListening(*m_pFormShell); + } + + Clear(); + delete m_pRootList; + m_pPropChangeList->ReleaseModel(); + m_pPropChangeList->release(); + } + + + //------------------------------------------------------------------------ + void NavigatorTreeModel::SetModified( sal_Bool bMod ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::SetModified" ); + if( !m_pFormShell ) return; + SfxObjectShell* pObjShell = m_pFormShell->GetFormModel()->GetObjectShell(); + if( !pObjShell ) return; + pObjShell->SetModified( bMod ); + } + + //------------------------------------------------------------------------ + void NavigatorTreeModel::Clear() + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::Clear" ); + Reference< XNameContainer > xForms( GetForms()); + Reference< XContainer > xContainer(xForms, UNO_QUERY); + if (xContainer.is()) + xContainer->removeContainerListener((XContainerListener*)m_pPropChangeList); + + ////////////////////////////////////////////////////////////////////// + // RootList loeschen + GetRootList()->clear(); + + ////////////////////////////////////////////////////////////////////// + // UI benachrichtigen + FmNavClearedHint aClearedHint; + Broadcast( aClearedHint ); + } + + //------------------------------------------------------------------------ + Reference< XNameContainer > NavigatorTreeModel::GetForms() const + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::GetForms" ); + if( !m_pFormShell || !m_pFormShell->GetCurPage()) + return NULL; + else + return m_pFormShell->GetCurPage()->GetForms(); + } + + //------------------------------------------------------------------------ + void NavigatorTreeModel::Insert(FmEntryData* pEntry, ULONG nRelPos, sal_Bool bAlterModel) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::Insert" ); + if (IsListening(*m_pFormModel)) + EndListening(*m_pFormModel); + + m_pPropChangeList->Lock(); + FmFormData* pFolder = (FmFormData*) pEntry->GetParent(); + Reference< XChild > xElement( pEntry->GetChildIFace() ); + if (bAlterModel) + { + XubString aStr; + if (pEntry->ISA(FmFormData)) + aStr = SVX_RES(RID_STR_FORM); + else + aStr = SVX_RES(RID_STR_CONTROL); + + Reference< XIndexContainer > xContainer; + if (pFolder) + xContainer = Reference< XIndexContainer > (pFolder->GetFormIface(), UNO_QUERY); + else + xContainer = Reference< XIndexContainer > (GetForms(), UNO_QUERY); + + bool bUndo = m_pFormModel->IsUndoEnabled(); + + if( bUndo ) + { + XubString aUndoStr(SVX_RES(RID_STR_UNDO_CONTAINER_INSERT)); + aUndoStr.SearchAndReplace('#', aStr); + m_pFormModel->BegUndo(aUndoStr); + } + + if (nRelPos >= (sal_uInt32)xContainer->getCount()) + nRelPos = (sal_uInt32)xContainer->getCount(); + + // UndoAction + if ( bUndo && m_pPropChangeList->CanUndo()) + { + m_pFormModel->AddUndo(new FmUndoContainerAction(*m_pFormModel, + FmUndoContainerAction::Inserted, + xContainer, + xElement, + nRelPos)); + } + + // das Element muss den Typ haben, den der Container erwartet + if (xContainer->getElementType() == + ::getCppuType((const Reference< XForm>*)0)) + + { + Reference< XForm > xElementAsForm(xElement, UNO_QUERY); + xContainer->insertByIndex(nRelPos, makeAny(xElementAsForm)); + } + else if (xContainer->getElementType() == + ::getCppuType((const Reference< XFormComponent>*)0)) + + { + Reference< XFormComponent > xElementAsComponent(xElement, UNO_QUERY); + xContainer->insertByIndex(nRelPos, makeAny(xElementAsComponent)); + } + else + { + DBG_ERROR("NavigatorTreeModel::Insert : the parent container needs an elementtype I don't know !"); + } + + if( bUndo ) + m_pFormModel->EndUndo(); + } + + ////////////////////////////////////////////////////////////////////// + // Als PropertyChangeListener anmelden + Reference< XPropertySet > xSet(xElement, UNO_QUERY); + if( xSet.is() ) + xSet->addPropertyChangeListener( FM_PROP_NAME, m_pPropChangeList ); + + ////////////////////////////////////////////////////////////////////// + // Daten aus Model entfernen + if (pEntry->ISA(FmFormData)) + { + Reference< XContainer > xContainer(xElement, UNO_QUERY); + if (xContainer.is()) + xContainer->addContainerListener((XContainerListener*)m_pPropChangeList); + } + + if (pFolder) + pFolder->GetChildList()->insert( pEntry, nRelPos ); + else + GetRootList()->insert( pEntry, nRelPos ); + + ////////////////////////////////////////////////////////////////////// + // UI benachrichtigen + FmNavInsertedHint aInsertedHint( pEntry, nRelPos ); + Broadcast( aInsertedHint ); + + m_pPropChangeList->UnLock(); + if (IsListening(*m_pFormModel)) + StartListening(*m_pFormModel); + } + + //------------------------------------------------------------------------ + void NavigatorTreeModel::Remove(FmEntryData* pEntry, sal_Bool bAlterModel) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::Remove" ); + ////////////////////////////////////////////////////////////////////// + // Form und Parent holen + if (!pEntry || !m_pFormModel) + return; + + if (IsListening(*m_pFormModel)) + EndListening(*m_pFormModel); + + const bool bUndo = m_pFormModel->IsUndoEnabled(); + + m_pPropChangeList->Lock(); + FmFormData* pFolder = (FmFormData*) pEntry->GetParent(); + Reference< XChild > xElement ( pEntry->GetChildIFace() ); + if (bAlterModel) + { + XubString aStr; + if (pEntry->ISA(FmFormData)) + aStr = SVX_RES(RID_STR_FORM); + else + aStr = SVX_RES(RID_STR_CONTROL); + + if( bUndo ) + { + XubString aUndoStr(SVX_RES(RID_STR_UNDO_CONTAINER_REMOVE)); + aUndoStr.SearchAndReplace('#', aStr); + m_pFormModel->BegUndo(aUndoStr); + } + } + + // jetzt die eigentliche Entfernung der Daten aus dem Model + if (pEntry->ISA(FmFormData)) + RemoveForm((FmFormData*)pEntry); + else + RemoveFormComponent((FmControlData*)pEntry); + + + if (bAlterModel) + { + Reference< XIndexContainer > xContainer(xElement->getParent(), UNO_QUERY); + // aus dem Container entfernen + sal_Int32 nContainerIndex = getElementPos(xContainer.get(), xElement); + // UndoAction + if (nContainerIndex >= 0) + { + if ( bUndo && m_pPropChangeList->CanUndo()) + { + m_pFormModel->AddUndo(new FmUndoContainerAction(*m_pFormModel, + FmUndoContainerAction::Removed, + xContainer, + xElement, nContainerIndex )); + } + else if( !m_pPropChangeList->CanUndo() ) + { + FmUndoContainerAction::DisposeElement( xElement ); + } + + xContainer->removeByIndex(nContainerIndex ); + } + + if( bUndo ) + m_pFormModel->EndUndo(); + } + + // beim Vater austragen + if (pFolder) + pFolder->GetChildList()->remove( pEntry ); + else + { + GetRootList()->remove( pEntry ); + ////////////////////////////////////////////////////////////////////// + // Wenn keine Form mehr in der Root, an der Shell CurForm zuruecksetzen + if ( !GetRootList()->size() ) + m_pFormShell->GetImpl()->forgetCurrentForm(); + } + + ////////////////////////////////////////////////////////////////////// + // UI benachrichtigen + FmNavRemovedHint aRemovedHint( pEntry ); + Broadcast( aRemovedHint ); + + // Eintrag loeschen + delete pEntry; + + m_pPropChangeList->UnLock(); + StartListening(*m_pFormModel); + } + + //------------------------------------------------------------------------ + void NavigatorTreeModel::RemoveForm(FmFormData* pFormData) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::RemoveForm" ); + ////////////////////////////////////////////////////////////////////// + // Form und Parent holen + if (!pFormData || !m_pFormModel) + return; + + FmEntryDataList* pChildList = pFormData->GetChildList(); + for ( size_t i = pChildList->size(); i > 0; ) + { + FmEntryData* pEntryData = pChildList->at( --i ); + + ////////////////////////////////////////////////////////////////////// + // Child ist Form -> rekursiver Aufruf + if( pEntryData->ISA(FmFormData) ) + RemoveForm( (FmFormData*)pEntryData); + else if( pEntryData->ISA(FmControlData) ) + RemoveFormComponent((FmControlData*) pEntryData); + } + + ////////////////////////////////////////////////////////////////////// + // Als PropertyChangeListener abmelden + Reference< XPropertySet > xSet( pFormData->GetPropertySet() ); + if ( xSet.is() ) + xSet->removePropertyChangeListener( FM_PROP_NAME, m_pPropChangeList ); + + Reference< XContainer > xContainer( pFormData->GetContainer() ); + if (xContainer.is()) + xContainer->removeContainerListener((XContainerListener*)m_pPropChangeList); + } + + //------------------------------------------------------------------------ + void NavigatorTreeModel::RemoveFormComponent(FmControlData* pControlData) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::RemoveFormComponent" ); + ////////////////////////////////////////////////////////////////////// + // Control und Parent holen + if (!pControlData) + return; + + ////////////////////////////////////////////////////////////////////// + // Als PropertyChangeListener abmelden + Reference< XPropertySet > xSet( pControlData->GetPropertySet() ); + if (xSet.is()) + xSet->removePropertyChangeListener( FM_PROP_NAME, m_pPropChangeList); + } + + //------------------------------------------------------------------------ + void NavigatorTreeModel::ClearBranch( FmFormData* pParentData ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::ClearBranch" ); + ////////////////////////////////////////////////////////////////////// + // Alle Eintraege dieses Zweiges loeschen + FmEntryDataList* pChildList = pParentData->GetChildList(); + + for( size_t i = pChildList->size(); i > 0; ) + { + FmEntryData* pChildData = pChildList->at( --i ); + if( pChildData->ISA(FmFormData) ) + ClearBranch( (FmFormData*)pChildData ); + + pChildList->remove( pChildData ); + } + } + + //------------------------------------------------------------------------ + void NavigatorTreeModel::FillBranch( FmFormData* pFormData ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::FillBranch" ); + ////////////////////////////////////////////////////////////// + // Forms aus der Root einfuegen + if( pFormData == NULL ) + { + Reference< XIndexContainer > xForms(GetForms(), UNO_QUERY); + if (!xForms.is()) + return; + + Reference< XForm > xSubForm; + FmFormData* pSubFormData; + for (sal_Int32 i=0; i<xForms->getCount(); ++i) + { + DBG_ASSERT( xForms->getByIndex(i).getValueType() == ::getCppuType((const Reference< XForm>*)NULL), + "NavigatorTreeModel::FillBranch : the root container should supply only elements of type XForm"); + + xForms->getByIndex(i) >>= xSubForm; + pSubFormData = new FmFormData( xSubForm, m_aNormalImages, pFormData ); + Insert( pSubFormData, LIST_APPEND ); + + ////////////////////////////////////////////////////////////// + // Neuer Branch, wenn SubForm wiederum Subforms enthaelt + FillBranch( pSubFormData ); + } + } + + ////////////////////////////////////////////////////////////// + // Componenten einfuegen + else + { + Reference< XIndexContainer > xComponents( GetFormComponents(pFormData)); + if( !xComponents.is() ) return; + + ::rtl::OUString aControlName; + Reference< XInterface > xInterface; + Reference< XPropertySet > xSet; + FmControlData* pNewControlData; + FmFormData* pSubFormData; + + Reference< XFormComponent > xCurrentComponent; + for (sal_Int32 j=0; j<xComponents->getCount(); ++j) + { + xComponents->getByIndex(j) >>= xCurrentComponent; + Reference< XForm > xSubForm(xCurrentComponent, UNO_QUERY); + + if (xSubForm.is()) + { // die aktuelle Component ist eine Form + pSubFormData = new FmFormData(xSubForm, m_aNormalImages, pFormData); + Insert(pSubFormData, LIST_APPEND); + + ////////////////////////////////////////////////////////////// + // Neuer Branch, wenn SubForm wiederum Subforms enthaelt + FillBranch(pSubFormData); + } + else + { + pNewControlData = new FmControlData(xCurrentComponent, m_aNormalImages, pFormData); + Insert(pNewControlData, LIST_APPEND); + } + } + } + } + + //------------------------------------------------------------------------ + void NavigatorTreeModel::InsertForm(const Reference< XForm > & xForm, sal_uInt32 nRelPos) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::InsertForm" ); + FmFormData* pFormData = (FmFormData*)FindData( xForm, GetRootList() ); + if (pFormData) + return; + + ////////////////////////////////////////////////////////// + // ParentData setzen + Reference< XInterface > xIFace( xForm->getParent()); + Reference< XForm > xParentForm(xIFace, UNO_QUERY); + FmFormData* pParentData = NULL; + if (xParentForm.is()) + pParentData = (FmFormData*)FindData( xParentForm, GetRootList() ); + + pFormData = new FmFormData( xForm, m_aNormalImages, pParentData ); + Insert( pFormData, nRelPos ); + } + + //------------------------------------------------------------------------ + void NavigatorTreeModel::InsertFormComponent(const Reference< XFormComponent > & xComp, sal_uInt32 nRelPos) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::InsertFormComponent" ); + ////////////////////////////////////////////////////////// + // ParentData setzen + Reference< XInterface > xIFace( xComp->getParent()); + Reference< XForm > xForm(xIFace, UNO_QUERY); + if (!xForm.is()) + return; + + FmFormData* pParentData = (FmFormData*)FindData( xForm, GetRootList() ); + if( !pParentData ) + { + pParentData = new FmFormData( xForm, m_aNormalImages, NULL ); + Insert( pParentData, LIST_APPEND ); + } + + if (!FindData(xComp, pParentData->GetChildList(),sal_False)) + { + ////////////////////////////////////////////////////////// + // Neue EntryData setzen + FmEntryData* pNewEntryData = new FmControlData( xComp, m_aNormalImages, pParentData ); + + ////////////////////////////////////////////////////////// + // Neue EntryData einfuegen + Insert( pNewEntryData, nRelPos ); + } + } + + //------------------------------------------------------------------------ + void NavigatorTreeModel::ReplaceFormComponent( + const Reference< XFormComponent > & xOld, + const Reference< XFormComponent > & xNew + ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::ReplaceFormComponent" ); + FmEntryData* pData = FindData(xOld, GetRootList(), sal_True); + DBG_ASSERT(pData && pData->ISA(FmControlData), "NavigatorTreeModel::ReplaceFormComponent : invalid argument !"); + ((FmControlData*)pData)->ModelReplaced( xNew, m_aNormalImages ); + + FmNavModelReplacedHint aReplacedHint( pData ); + Broadcast( aReplacedHint ); + } + + //------------------------------------------------------------------------ + FmEntryData* NavigatorTreeModel::FindData(const Reference< XInterface > & xElement, FmEntryDataList* pDataList, sal_Bool bRecurs) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::FindData" ); + // normalize + Reference< XInterface > xIFace( xElement, UNO_QUERY ); + + for ( size_t i = 0; i < pDataList->size(); i++ ) + { + FmEntryData* pEntryData = pDataList->at( i ); + if ( pEntryData->GetElement().get() == xIFace.get() ) + return pEntryData; + else if (bRecurs) + { + pEntryData = FindData( xElement, pEntryData->GetChildList() ); + if (pEntryData) + return pEntryData; + } + } + return NULL; + } + + //------------------------------------------------------------------------ + FmEntryData* NavigatorTreeModel::FindData( const ::rtl::OUString& rText, FmFormData* pParentData, sal_Bool bRecurs ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::FindData" ); + FmEntryDataList* pDataList; + if( !pParentData ) + pDataList = GetRootList(); + else + pDataList = pParentData->GetChildList(); + + ::rtl::OUString aEntryText; + FmEntryData* pEntryData; + FmEntryData* pChildData; + + for( size_t i = 0; i < pDataList->size(); i++ ) + { + pEntryData = pDataList->at( i ); + aEntryText = pEntryData->GetText(); + + if (rText == aEntryText) + return pEntryData; + + if( bRecurs && pEntryData->ISA(FmFormData) ) + { + pChildData = FindData( rText, (FmFormData*)pEntryData ); + if( pChildData ) + return pChildData; + } + } + + return NULL; + } + + //------------------------------------------------------------------------ + void NavigatorTreeModel::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::Notify" ); + if( rHint.ISA(SdrHint) ) + { + SdrHint* pSdrHint = (SdrHint*)&rHint; + switch( pSdrHint->GetKind() ) + { + case HINT_OBJINSERTED: + InsertSdrObj(pSdrHint->GetObject()); + break; + case HINT_OBJREMOVED: + RemoveSdrObj(pSdrHint->GetObject()); + break; + default: + break; + } + } + // hat sich die shell verabschiedet? + else if ( rHint.ISA(SfxSimpleHint) && ((SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING) + UpdateContent((FmFormShell*)NULL); + + // hat sich die Markierung der Controls veraendert ? + else if (rHint.ISA(FmNavViewMarksChanged)) + { + FmNavViewMarksChanged* pvmcHint = (FmNavViewMarksChanged*)&rHint; + BroadcastMarkedObjects( pvmcHint->GetAffectedView()->GetMarkedObjectList() ); + } + } + + //------------------------------------------------------------------------ + void NavigatorTreeModel::InsertSdrObj( const SdrObject* pObj ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::InsertSdrObj" ); + const FmFormObj* pFormObject = FmFormObj::GetFormObject( pObj ); + if ( pFormObject ) + { + try + { + Reference< XFormComponent > xFormComponent( pFormObject->GetUnoControlModel(), UNO_QUERY_THROW ); + Reference< XIndexAccess > xContainer( xFormComponent->getParent(), UNO_QUERY_THROW ); + + sal_Int32 nPos = getElementPos( xContainer, xFormComponent ); + InsertFormComponent( xFormComponent, nPos ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + else if ( pObj->IsGroupObject() ) + { + SdrObjListIter aIter( *pObj->GetSubList() ); + while ( aIter.IsMore() ) + InsertSdrObj( aIter.Next() ); + } + } + + //------------------------------------------------------------------------ + void NavigatorTreeModel::RemoveSdrObj( const SdrObject* pObj ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::RemoveSdrObj" ); + const FmFormObj* pFormObject = FmFormObj::GetFormObject( pObj ); + if ( pFormObject ) + { + try + { + Reference< XFormComponent > xFormComponent( pFormObject->GetUnoControlModel(), UNO_QUERY_THROW ); + FmEntryData* pEntryData = FindData( xFormComponent, GetRootList(), sal_True ); + if ( pEntryData ) + Remove( pEntryData ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + else if ( pObj->IsGroupObject() ) + { + SdrObjListIter aIter( *pObj->GetSubList() ); + while ( aIter.IsMore() ) + RemoveSdrObj( aIter.Next() ); + } + } + + sal_Bool NavigatorTreeModel::InsertFormComponent(FmNavRequestSelectHint& rHint, SdrObject* pObject) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::InsertFormComponent" ); + if ( pObject->ISA(SdrObjGroup) ) + { // rekursiv absteigen + const SdrObjList *pChilds = ((SdrObjGroup*)pObject)->GetSubList(); + for ( sal_uInt16 i=0; i<pChilds->GetObjCount(); ++i ) + { + SdrObject* pCurrent = pChilds->GetObj(i); + if (!InsertFormComponent(rHint, pCurrent)) + return sal_False; + } + } + else + { + FmFormObj* pFormObject = FmFormObj::GetFormObject( pObject ); + if ( !pFormObject ) + return sal_False; + + try + { + Reference< XFormComponent > xFormViewControl( pFormObject->GetUnoControlModel(), UNO_QUERY_THROW ); + FmEntryData* pControlData = FindData( xFormViewControl, GetRootList() ); + if ( !pControlData ) + return sal_False; + + rHint.AddItem( pControlData ); + return sal_True; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + return sal_False; + } + } + + return sal_True; + } + + void NavigatorTreeModel::BroadcastMarkedObjects(const SdrMarkList& mlMarked) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::BroadcastMarkedObjects" ); + // gehen wir durch alle markierten Objekte und suchen wir die raus, mit denen ich was anfangen kann + FmNavRequestSelectHint rshRequestSelection; + sal_Bool bIsMixedSelection = sal_False; + + for (ULONG i=0; (i<mlMarked.GetMarkCount()) && !bIsMixedSelection; i++) + { + SdrObject* pobjCurrent = mlMarked.GetMark(i)->GetMarkedSdrObj(); + bIsMixedSelection |= !InsertFormComponent(rshRequestSelection, pobjCurrent); + // bei einem Nicht-Form-Control liefert InsertFormComponent sal_False ! + } + + rshRequestSelection.SetMixedSelection(bIsMixedSelection); + if (bIsMixedSelection) + rshRequestSelection.ClearItems(); + + Broadcast(rshRequestSelection); + // eine leere Liste interpretiert der NavigatorTree so, dass er seine Selektion komplett rausnimmt + } + + //------------------------------------------------------------------------ + void NavigatorTreeModel::UpdateContent( const Reference< XNameContainer > & xForms ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::UpdateContent" ); + ////////////////////////////////////////////////////////////////////// + // Model von der Root aufwaerts neu fuellen + Clear(); + if (xForms.is()) + { + Reference< XContainer > xFormContainer(xForms, UNO_QUERY); + if (xFormContainer.is()) + xFormContainer->addContainerListener((XContainerListener*)m_pPropChangeList); + + FillBranch(NULL); + + // jetzt in meinem Tree genau die das in meiner View markierte Control selektieren + // (bzw alle solchen), falls es eines gibt ... + if(!m_pFormShell) return; // keine Shell -> wech + + FmFormView* pFormView = m_pFormShell->GetFormView(); + DBG_ASSERT(pFormView != NULL, "NavigatorTreeModel::UpdateContent : keine FormView"); + BroadcastMarkedObjects(pFormView->GetMarkedObjectList()); + } + } + + //------------------------------------------------------------------------ + void NavigatorTreeModel::UpdateContent( FmFormShell* pShell ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::UpdateContent" ); + ////////////////////////////////////////////////////////////////////// + // Wenn Shell sich nicht veraendert hat, nichts machen + FmFormPage* pNewPage = pShell ? pShell->GetCurPage() : NULL; + if ((pShell == m_pFormShell) && (m_pFormPage == pNewPage)) + return; + + ////////////////////////////////////////////////////////////////////// + // Als Listener abmelden + if( m_pFormShell ) + { + if (m_pFormModel) + EndListening( *m_pFormModel ); + m_pFormModel = NULL; + EndListening( *m_pFormShell ); + Clear(); + } + + ////////////////////////////////////////////////////////////////////// + // Vollupdate + m_pFormShell = pShell; + if (m_pFormShell) + { + m_pFormPage = pNewPage; + UpdateContent(m_pFormPage->GetForms()); + } else + m_pFormPage = NULL; + + ////////////////////////////////////////////////////////////////////// + // Als Listener neu anmelden + if( m_pFormShell ) + { + StartListening( *m_pFormShell ); + m_pFormModel = m_pFormShell->GetFormModel(); + if( m_pFormModel ) + StartListening( *m_pFormModel ); + } + } + + //------------------------------------------------------------------------ + Reference< XIndexContainer > NavigatorTreeModel::GetFormComponents( FmFormData* pFormData ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::GetFormComponents" ); + ////////////////////////////////////////////////////////////////////// + // Von der Form Components holen + if (pFormData) + return Reference< XIndexContainer > (pFormData->GetFormIface(), UNO_QUERY); + + return Reference< XIndexContainer > (); + } + + //------------------------------------------------------------------------ + sal_Bool NavigatorTreeModel::CheckEntry( FmEntryData* pEntryData ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::CheckEntry" ); + ////////////////////////////////////////////////////////////////////// + // Nur Forms duerfen auf Doppeldeutigkeit untersucht werden + if( !pEntryData->ISA(FmFormData) ) return sal_True; + + ////////////////////////////////////////////////////////////////////// + // ChildListe des Parents holen + FmFormData* pParentData = (FmFormData*)pEntryData->GetParent(); + FmEntryDataList* pChildList; + if( !pParentData ) + pChildList = GetRootList(); + else + pChildList = pParentData->GetChildList(); + + ////////////////////////////////////////////////////////////////////// + // In ChildListe nach doppelten Namen suchen + ::rtl::OUString aChildText; + FmEntryData* pChildData; + + for( size_t i = 0; i < pChildList->size(); i++ ) + { + pChildData = pChildList->at( i ); + aChildText = pChildData->GetText(); + + ////////////////////////////////////////////////////////////////////// + // Gleichen Eintrag gefunden + if ( (aChildText == pEntryData->GetText()) + && (pEntryData!=pChildData) + ) + { + + + SQLContext aError; + aError.Message = String(SVX_RES(RID_ERR_CONTEXT_ADDFORM)); + aError.Details = String(SVX_RES(RID_ERR_DUPLICATE_NAME)); + displayException(aError); + + return sal_False; + } + } + + return sal_True; + } + + //------------------------------------------------------------------------ + sal_Bool NavigatorTreeModel::Rename( FmEntryData* pEntryData, const ::rtl::OUString& rNewText ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::Rename" ); + ////////////////////////////////////////////////////////////////////// + // Wenn Name schon vorhanden, Fehlermeldung + pEntryData->SetText( rNewText ); + + ////////////////////////////////////////////////////////////////////// + // PropertySet besorgen + Reference< XFormComponent > xFormComponent; + + if( pEntryData->ISA(FmFormData) ) + { + FmFormData* pFormData = (FmFormData*)pEntryData; + Reference< XForm > xForm( pFormData->GetFormIface()); + xFormComponent = Reference< XFormComponent > (xForm, UNO_QUERY); + } + + if( pEntryData->ISA(FmControlData) ) + { + FmControlData* pControlData = (FmControlData*)pEntryData; + xFormComponent = pControlData->GetFormComponent(); + } + + if( !xFormComponent.is() ) return sal_False; + Reference< XPropertySet > xSet(xFormComponent, UNO_QUERY); + if( !xSet.is() ) return sal_False; + + ////////////////////////////////////////////////////////////////////// + // Namen setzen + xSet->setPropertyValue( FM_PROP_NAME, makeAny(rNewText) ); + + return sal_True; + } + + //------------------------------------------------------------------------ + sal_Bool NavigatorTreeModel::IsNameAlreadyDefined( const ::rtl::OUString& rName, FmFormData* pParentData ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::IsNameAlreadyDefined" ); + ////////////////////////////////////////////////////////////////////// + // Form in der Root + if( !pParentData ) + { + if (GetForms()->hasByName(rName)) + return sal_True; + } + + ////////////////////////////////////////////////////////////////////// + // Restliche Components + else + { + Reference< XNameContainer > xFormComponents(GetFormComponents(pParentData), UNO_QUERY); + if (xFormComponents.is() && xFormComponents->hasByName(rName)) + return sal_True; + } + + return sal_False; + } + + //------------------------------------------------------------------------ + SdrObject* NavigatorTreeModel::GetSdrObj( FmControlData* pControlData ) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::GetSdrObj" ); + if (!pControlData || !m_pFormShell) + return NULL; + + ////////////////////////////////////////////////////////////////////// + // In der Page das entsprechende SdrObj finden und selektieren + Reference< XFormComponent > xFormComponent( pControlData->GetFormComponent()); + if (!xFormComponent.is()) + return NULL; + + FmFormView* pFormView = m_pFormShell->GetFormView(); + SdrPageView* pPageView = pFormView->GetSdrPageView(); + SdrPage* pPage = pPageView->GetPage(); + + SdrObjListIter aIter( *pPage ); + return Search(aIter, xFormComponent); + } + + //------------------------------------------------------------------ + SdrObject* NavigatorTreeModel::Search(SdrObjListIter& rIter, const Reference< XFormComponent > & xComp) + { + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "NavigatorTreeModel::Search" ); + while (rIter.IsMore()) + { + SdrObject* pObj = rIter.Next(); + FmFormObj* pFormObject = FmFormObj::GetFormObject( pObj ); + if ( pFormObject ) + { + Reference< XFormComponent > xFormViewControl( pFormObject->GetUnoControlModel(), UNO_QUERY ); + if ( xFormViewControl == xComp ) + return pObj; + } + else if ( pObj->IsGroupObject() ) + { + SdrObjListIter aIter( *pObj->GetSubList() ); + pObj = Search( aIter, xComp ); + if ( pObj ) + return pObj; + } + } + return NULL; + } + +//............................................................................ +} // namespace svxform +//............................................................................ + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/sdbdatacolumn.cxx b/svx/source/form/sdbdatacolumn.cxx new file mode 100644 index 000000000000..120c8f8bb41d --- /dev/null +++ b/svx/source/form/sdbdatacolumn.cxx @@ -0,0 +1,290 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include "sdbdatacolumn.hxx" + +//.............................................................................. +namespace svxform +{ +//.............................................................................. + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::io; + using namespace ::com::sun::star::container; + + //========================================================================== + //= DataColumn - a class wrapping an object implementing a sdb::DataColumn service + //========================================================================== + DataColumn::DataColumn(const Reference< ::com::sun::star::beans::XPropertySet>& _rxIFace) + { + m_xPropertySet = _rxIFace; + m_xColumn = Reference< ::com::sun::star::sdb::XColumn>(_rxIFace, UNO_QUERY); + m_xColumnUpdate = Reference< ::com::sun::star::sdb::XColumnUpdate>(_rxIFace, UNO_QUERY); + + if (!m_xPropertySet.is() || !m_xColumn.is()) + { + m_xPropertySet = NULL; + m_xColumn = NULL; + m_xColumnUpdate = NULL; + } + } + + // Reference< XPropertySet> + Reference< XPropertySetInfo> DataColumn::getPropertySetInfo() const throw( RuntimeException ) + { + return m_xPropertySet->getPropertySetInfo(); + } + + void DataColumn::setPropertyValue(const ::rtl::OUString& aPropertyName, const Any& aValue) throw( UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException ) + { + m_xPropertySet->setPropertyValue(aPropertyName, aValue); + } + + Any DataColumn::getPropertyValue(const ::rtl::OUString& PropertyName) const throw( UnknownPropertyException, WrappedTargetException, RuntimeException ) + { + return m_xPropertySet->getPropertyValue(PropertyName); + } + + void DataColumn::addPropertyChangeListener(const ::rtl::OUString& aPropertyName, const Reference< XPropertyChangeListener>& xListener) throw( UnknownPropertyException, WrappedTargetException, RuntimeException ) + { + m_xPropertySet->addPropertyChangeListener(aPropertyName, xListener); + } + + void DataColumn::removePropertyChangeListener(const ::rtl::OUString& aPropertyName, const Reference< XPropertyChangeListener>& aListener) throw( UnknownPropertyException, WrappedTargetException, RuntimeException ) + { + m_xPropertySet->removePropertyChangeListener(aPropertyName, aListener); + } + + void DataColumn::addVetoableChangeListener(const ::rtl::OUString& PropertyName, const Reference< XVetoableChangeListener>& aListener) throw( UnknownPropertyException, WrappedTargetException, RuntimeException ) + { + m_xPropertySet->addVetoableChangeListener(PropertyName, aListener); + } + + void DataColumn::removeVetoableChangeListener(const ::rtl::OUString& PropertyName, const Reference< XVetoableChangeListener>& aListener) throw( UnknownPropertyException, WrappedTargetException, RuntimeException ) + { + m_xPropertySet->removeVetoableChangeListener(PropertyName, aListener); + } + + // XColumn + sal_Bool DataColumn::wasNull() throw( SQLException, RuntimeException ) + { + return m_xColumn->wasNull(); + } + + ::rtl::OUString DataColumn::getString() throw( SQLException, RuntimeException ) + { + return m_xColumn->getString(); + } + + sal_Bool DataColumn::getBoolean() throw( SQLException, RuntimeException ) + { + return m_xColumn->getBoolean(); + } + + sal_Int8 DataColumn::getByte() throw( SQLException, RuntimeException ) + { + return m_xColumn->getByte(); + } + + sal_Int16 DataColumn::getShort() throw( SQLException, RuntimeException ) + { + return m_xColumn->getShort(); + } + + sal_Int32 DataColumn::getInt() throw( SQLException, RuntimeException ) + { + return m_xColumn->getInt(); + } + + sal_Int64 DataColumn::getLong() throw( SQLException, RuntimeException ) + { + return m_xColumn->getLong(); + } + + float DataColumn::getFloat() throw( SQLException, RuntimeException ) + { + return m_xColumn->getFloat(); + } + + double DataColumn::getDouble() throw( SQLException, RuntimeException ) + { + return m_xColumn->getDouble(); + } + + Sequence< sal_Int8 > DataColumn::getBytes() throw( SQLException, RuntimeException ) + { + return m_xColumn->getBytes(); + } + + com::sun::star::util::Date DataColumn::getDate() throw( SQLException, RuntimeException ) + { + return m_xColumn->getDate(); + } + + com::sun::star::util::Time DataColumn::getTime() throw( SQLException, RuntimeException ) + { + return m_xColumn->getTime(); + } + + com::sun::star::util::DateTime DataColumn::getTimestamp() throw( SQLException, RuntimeException ) + { + return m_xColumn->getTimestamp(); + } + + Reference< XInputStream> DataColumn::getBinaryStream() throw( SQLException, RuntimeException ) + { + return m_xColumn->getBinaryStream(); + } + + Reference< XInputStream> DataColumn::getCharacterStream() throw( SQLException, RuntimeException ) + { + return m_xColumn->getCharacterStream(); + } + + Any DataColumn::getObject(const Reference< XNameAccess>& typeMap) throw( SQLException, RuntimeException ) + { + return m_xColumn->getObject(typeMap); + } + + Reference< XRef> DataColumn::getRef() throw( SQLException, RuntimeException ) + { + return m_xColumn->getRef(); + } + + Reference< XBlob> DataColumn::getBlob() throw( SQLException, RuntimeException ) + { + return m_xColumn->getBlob(); + } + + Reference< XClob> DataColumn::getClob() throw( SQLException, RuntimeException ) + { + return m_xColumn->getClob(); + } + + Reference< XArray> DataColumn::getArray() throw( SQLException, RuntimeException ) + { + return m_xColumn->getArray(); + } + + // XColumnUpdate + void DataColumn::updateNull() throw( SQLException, RuntimeException ) + { + m_xColumnUpdate->updateNull(); + } + + void DataColumn::updateBoolean(sal_Bool x) throw( SQLException, RuntimeException ) + { + m_xColumnUpdate->updateBoolean(x); + } + + void DataColumn::updateByte(sal_Int8 x) throw( SQLException, RuntimeException ) + { + m_xColumnUpdate->updateByte(x); + } + + void DataColumn::updateShort(sal_Int16 x) throw( SQLException, RuntimeException ) + { + m_xColumnUpdate->updateShort(x); + } + + void DataColumn::updateInt(sal_Int32 x) throw( SQLException, RuntimeException ) + { + m_xColumnUpdate->updateInt(x); + } + + void DataColumn::updateLong(sal_Int64 x) throw( SQLException, RuntimeException ) + { + m_xColumnUpdate->updateLong(x); + } + + void DataColumn::updateFloat(float x) throw( SQLException, RuntimeException ) + { + m_xColumnUpdate->updateFloat(x); + } + + void DataColumn::updateDouble(double x) throw( SQLException, RuntimeException ) + { + m_xColumnUpdate->updateDouble(x); + } + + void DataColumn::updateString(const ::rtl::OUString& x) throw( SQLException, RuntimeException ) + { + m_xColumnUpdate->updateString(x); + } + + void DataColumn::updateBytes(const Sequence< sal_Int8 >& x) throw( SQLException, RuntimeException ) + { + m_xColumnUpdate->updateBytes(x); + } + + void DataColumn::updateDate(const com::sun::star::util::Date& x) throw( SQLException, RuntimeException ) + { + m_xColumnUpdate->updateDate(x); + } + + void DataColumn::updateTime(const com::sun::star::util::Time& x) throw( SQLException, RuntimeException ) + { + m_xColumnUpdate->updateTime(x); + } + + void DataColumn::updateTimestamp(const com::sun::star::util::DateTime& x) throw( SQLException, RuntimeException ) + { + m_xColumnUpdate->updateTimestamp(x); + } + + void DataColumn::updateBinaryStream(const Reference< XInputStream>& x, sal_Int32 length) throw( SQLException, RuntimeException ) + { + m_xColumnUpdate->updateBinaryStream(x, length); + } + + void DataColumn::updateCharacterStream(const Reference< XInputStream>& x, sal_Int32 length) throw( SQLException, RuntimeException ) + { + m_xColumnUpdate->updateCharacterStream(x, length); + } + + void DataColumn::updateObject(const Any& x) throw( SQLException, RuntimeException ) + { + m_xColumnUpdate->updateObject(x); + } + + void DataColumn::updateNumericObject(const Any& x, sal_Int32 scale) throw( SQLException, RuntimeException ) + { + m_xColumnUpdate->updateNumericObject(x, scale); + } + + //.............................................................................. +} // namespace svxform +//.............................................................................. + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/sqlparserclient.cxx b/svx/source/form/sqlparserclient.cxx new file mode 100644 index 000000000000..3c1b786e9659 --- /dev/null +++ b/svx/source/form/sqlparserclient.cxx @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include "sqlparserclient.hxx" +#include "ParseContext.hxx" + +//........................................................................ +namespace svxform +{ +//........................................................................ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + + //==================================================================== + //= OSQLParserClient + //==================================================================== + //-------------------------------------------------------------------- + OSQLParserClient::OSQLParserClient(const Reference< XMultiServiceFactory >& _rxORB) + { + m_xORB = _rxORB; + } + //-------------------------------------------------------------------- + bool OSQLParserClient::ensureLoaded() const + { + if ( !ODbtoolsClient::ensureLoaded() ) + return false; + m_xParser = getFactory()->createSQLParser(m_xORB,getParseContext()); + return m_xParser.is(); + } + +//........................................................................ +} // namespace svxform +//........................................................................ + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/stringlistresource.cxx b/svx/source/form/stringlistresource.cxx new file mode 100644 index 000000000000..83d6274d1e5d --- /dev/null +++ b/svx/source/form/stringlistresource.cxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include "stringlistresource.hxx" + +/** === begin UNO includes === **/ +/** === end UNO includes === **/ + +#include <tools/rcid.h> + +//........................................................................ +namespace svx +{ +//........................................................................ + + /** === begin UNO using === **/ + /** === end UNO using === **/ + + //==================================================================== + //= StringListResource + //==================================================================== + //-------------------------------------------------------------------- + StringListResource::StringListResource( const ResId& _rResId ) + :Resource( _rResId ) + { + USHORT nLocalID = 1; + ResId aLocalID( nLocalID, *_rResId.GetResMgr() ); + while ( IsAvailableRes( aLocalID.SetRT( RSC_STRING ) ) ) + { + String sLocalString( aLocalID ); + m_aStrings.push_back( sLocalString ); + aLocalID = ResId( ++nLocalID, *_rResId.GetResMgr() ); + } + } + + //-------------------------------------------------------------------- + StringListResource::~StringListResource() + { + FreeResource(); + } + +//........................................................................ +} // namespace svx +//........................................................................ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/tabwin.cxx b/svx/source/form/tabwin.cxx new file mode 100644 index 000000000000..5c8ddbd0f662 --- /dev/null +++ b/svx/source/form/tabwin.cxx @@ -0,0 +1,470 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include "tabwin.hxx" +#include "svx/fmtools.hxx" +#include "fmservs.hxx" +#include "stringlistresource.hxx" + +#include <svx/svxids.hrc> +#include <svx/dbaexchange.hxx> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include <com/sun/star/sdbc/XPreparedStatement.hpp> +#include <com/sun/star/awt/XControlContainer.hpp> +#include <com/sun/star/util/XLocalizedAliases.hpp> +#include <comphelper/processfactory.hxx> +#include <comphelper/stl_types.hxx> + +#include "fmhelp.hrc" +#include <svx/fmshell.hxx> +#include "fmshimp.hxx" +#include "svx/dbtoolsclient.hxx" +#include <svx/fmpage.hxx> + +#include "fmpgeimp.hxx" + +#include "fmprop.hrc" + +#include "fmresids.hrc" +#include <svx/dialmgr.hxx> +#include <tools/shl.hxx> +#include <svx/svdpagv.hxx> +#include <sfx2/objitem.hxx> +#include <sfx2/dispatch.hxx> +#include <comphelper/property.hxx> +#include <sfx2/frame.hxx> +#include <svx/dataaccessdescriptor.hxx> + +const long STD_WIN_POS_X = 50; +const long STD_WIN_POS_Y = 50; + +const long STD_WIN_SIZE_X = 120; +const long STD_WIN_SIZE_Y = 150; + +const long MIN_WIN_SIZE_X = 50; +const long MIN_WIN_SIZE_Y = 50; + +const long LISTBOX_BORDER = 2; + +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::datatransfer; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star; +using namespace ::svxform; +using namespace ::svx; + + +struct ColumnInfo +{ + ::rtl::OUString sColumnName; + ::rtl::OUString sLabel; + bool bColumn; + ColumnInfo(const ::rtl::OUString& i_sColumnName,const ::rtl::OUString& i_sLabel) + : sColumnName(i_sColumnName) + , sLabel(i_sLabel) + , bColumn(true) + { + } + ColumnInfo(const ::rtl::OUString& i_sColumnName) + : sColumnName(i_sColumnName) + , bColumn(false) + { + } +}; + +void lcl_addToList( SvTreeListBox& _rListBox, const uno::Reference< container::XNameAccess>& i_xColumns ) +{ + uno::Sequence< ::rtl::OUString > aEntries = i_xColumns->getElementNames(); + const ::rtl::OUString* pEntries = aEntries.getConstArray(); + sal_Int32 nEntries = aEntries.getLength(); + for ( sal_Int32 i = 0; i < nEntries; ++i, ++pEntries ) + { + uno::Reference< beans::XPropertySet> xColumn(i_xColumns->getByName(*pEntries),UNO_QUERY_THROW); + ::rtl::OUString sLabel; + if ( xColumn->getPropertySetInfo()->hasPropertyByName(FM_PROP_LABEL) ) + xColumn->getPropertyValue(FM_PROP_LABEL) >>= sLabel; + if ( sLabel.getLength() ) + _rListBox.InsertEntry( sLabel,NULL,FALSE,LIST_APPEND,new ColumnInfo(*pEntries,sLabel) ); + else + _rListBox.InsertEntry( *pEntries,NULL,FALSE,LIST_APPEND,new ColumnInfo(*pEntries,sLabel) ); + } +} +//================================================================== +// class FmFieldWinListBox +//================================================================== +DBG_NAME(FmFieldWinListBox) +//------------------------------------------------------------------------------ +FmFieldWinListBox::FmFieldWinListBox( FmFieldWin* pParent ) + :SvTreeListBox( pParent, WB_HASBUTTONS|WB_BORDER ) + ,pTabWin( pParent ) +{ + DBG_CTOR(FmFieldWinListBox,NULL); + SetHelpId( HID_FIELD_SEL ); + + SetHighlightRange( ); +} + +//------------------------------------------------------------------------------ +FmFieldWinListBox::~FmFieldWinListBox() +{ + DBG_DTOR(FmFieldWinListBox,NULL); +} + +//------------------------------------------------------------------------------ +sal_Int8 FmFieldWinListBox::AcceptDrop( const AcceptDropEvent& /*rEvt*/ ) +{ + return DND_ACTION_NONE; +} + +//------------------------------------------------------------------------------ +sal_Int8 FmFieldWinListBox::ExecuteDrop( const ExecuteDropEvent& /*rEvt*/ ) +{ + return DND_ACTION_NONE; +} + +//------------------------------------------------------------------------------ +BOOL FmFieldWinListBox::DoubleClickHdl() +{ + if ( pTabWin->createSelectionControls() ) + return sal_True; + + return SvTreeListBox::DoubleClickHdl(); +} + +//------------------------------------------------------------------------------ +void FmFieldWinListBox::StartDrag( sal_Int8 /*_nAction*/, const Point& /*_rPosPixel*/ ) +{ + SvLBoxEntry* pSelected = FirstSelected(); + if (!pSelected) + // no drag without a field + return; + + ::svx::ODataAccessDescriptor aDescriptor; + aDescriptor[ daDataSource ] <<= pTabWin->GetDatabaseName(); + aDescriptor[ daConnection ] <<= pTabWin->GetConnection().getTyped(); + aDescriptor[ daCommand ] <<= pTabWin->GetObjectName(); + aDescriptor[ daCommandType ]<<= pTabWin->GetObjectType(); + ColumnInfo* pInfo = static_cast<ColumnInfo*>(pSelected->GetUserData()); + aDescriptor[ daColumnName ] <<= pInfo->sColumnName; + + TransferableHelper* pTransferColumn = new OColumnTransferable( + aDescriptor, CTF_FIELD_DESCRIPTOR | CTF_CONTROL_EXCHANGE | CTF_COLUMN_DESCRIPTOR + ); + Reference< XTransferable> xEnsureDelete = pTransferColumn; + if (pTransferColumn) + { + EndSelection(); + pTransferColumn->StartDrag( this, DND_ACTION_COPY ); + } +} + +//======================================================================== +// class FmFieldWinData +//======================================================================== +DBG_NAME(FmFieldWinData); +//----------------------------------------------------------------------- +FmFieldWinData::FmFieldWinData() +{ + DBG_CTOR(FmFieldWinData,NULL); +} + +//----------------------------------------------------------------------- +FmFieldWinData::~FmFieldWinData() +{ + DBG_DTOR(FmFieldWinData,NULL); +} + +//======================================================================== +// class FmFieldWin +//======================================================================== +DBG_NAME(FmFieldWin); +//----------------------------------------------------------------------- +FmFieldWin::FmFieldWin(SfxBindings* _pBindings, SfxChildWindow* _pMgr, Window* _pParent) + :SfxFloatingWindow(_pBindings, _pMgr, _pParent, WinBits(WB_STDMODELESS|WB_SIZEABLE)) + ,SfxControllerItem(SID_FM_FIELDS_CONTROL, *_pBindings) + ,::comphelper::OPropertyChangeListener(m_aMutex) + ,pData(new FmFieldWinData) + ,m_nObjectType(0) + ,m_pChangeListener(NULL) +{ + DBG_CTOR(FmFieldWin,NULL); + SetHelpId( HID_FIELD_SEL_WIN ); + + SetBackground( Wallpaper( Application::GetSettings().GetStyleSettings().GetFaceColor()) ); + pListBox = new FmFieldWinListBox( this ); + pListBox->Show(); + UpdateContent(NULL); + SetSizePixel(Size(STD_WIN_SIZE_X,STD_WIN_SIZE_Y)); +} + +//----------------------------------------------------------------------- +FmFieldWin::~FmFieldWin() +{ + if (m_pChangeListener) + { + m_pChangeListener->dispose(); + m_pChangeListener->release(); + // delete m_pChangeListener; + } + delete pListBox; + delete pData; + DBG_DTOR(FmFieldWin,NULL); +} + +//----------------------------------------------------------------------- +void FmFieldWin::GetFocus() +{ + if ( pListBox ) + pListBox->GrabFocus(); + else + SfxFloatingWindow::GetFocus(); +} + +//----------------------------------------------------------------------- +sal_Bool FmFieldWin::createSelectionControls( ) +{ + SvLBoxEntry* pSelected = pListBox->FirstSelected(); + if ( pSelected ) + { + // build a descriptor for the currently selected field + ODataAccessDescriptor aDescr; + aDescr.setDataSource(GetDatabaseName()); + + aDescr[ daConnection ] <<= GetConnection().getTyped(); + + aDescr[ daCommand ] <<= GetObjectName(); + aDescr[ daCommandType ] <<= GetObjectType(); + ColumnInfo* pInfo = static_cast<ColumnInfo*>(pSelected->GetUserData()); + aDescr[ daColumnName ] <<= pInfo->sColumnName;//::rtl::OUString( pListBox->GetEntryText( pSelected) ); + + // transfer this to the SFX world + SfxUnoAnyItem aDescriptorItem( SID_FM_DATACCESS_DESCRIPTOR, makeAny( aDescr.createPropertyValueSequence() ) ); + const SfxPoolItem* pArgs[] = + { + &aDescriptorItem, NULL + }; + + // execute the create slot + GetBindings().Execute( SID_FM_CREATE_FIELDCONTROL, pArgs ); + } + + return NULL != pSelected; +} + +//----------------------------------------------------------------------- +long FmFieldWin::PreNotify( NotifyEvent& _rNEvt ) +{ + if ( EVENT_KEYINPUT == _rNEvt.GetType() ) + { + const KeyCode& rKeyCode = _rNEvt.GetKeyEvent()->GetKeyCode(); + if ( ( 0 == rKeyCode.GetModifier() ) && ( KEY_RETURN == rKeyCode.GetCode() ) ) + { + if ( createSelectionControls() ) + return 1; + } + } + + return SfxFloatingWindow::PreNotify( _rNEvt ); +} + +//----------------------------------------------------------------------- +sal_Bool FmFieldWin::Close() +{ + return SfxFloatingWindow::Close(); +} + +//----------------------------------------------------------------------- +void FmFieldWin::_propertyChanged(const ::com::sun::star::beans::PropertyChangeEvent& evt) throw( ::com::sun::star::uno::RuntimeException ) +{ + ::com::sun::star::uno::Reference< ::com::sun::star::form::XForm > xForm(evt.Source, ::com::sun::star::uno::UNO_QUERY); + UpdateContent(xForm); +} + +//----------------------------------------------------------------------- +void FmFieldWin::StateChanged(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState) +{ + if (!pState || SID_FM_FIELDS_CONTROL != nSID) + return; + + if (eState >= SFX_ITEM_AVAILABLE) + { + FmFormShell* pShell = PTR_CAST(FmFormShell,((SfxObjectItem*)pState)->GetShell()); + UpdateContent(pShell); + } + else + UpdateContent(NULL); +} + +//----------------------------------------------------------------------- +void FmFieldWin::UpdateContent(FmFormShell* pShell) +{ + pListBox->Clear(); + String aTitle( SVX_RES( RID_STR_FIELDSELECTION ) ); + SetText( aTitle ); + + if (!pShell || !pShell->GetImpl()) + return; + + Reference< XForm > xForm = pShell->GetImpl()->getCurrentForm(); + if ( xForm.is() ) + UpdateContent( xForm ); +} + +//----------------------------------------------------------------------- +void FmFieldWin::UpdateContent(const ::com::sun::star::uno::Reference< ::com::sun::star::form::XForm > & xForm) +{ + try + { + // ListBox loeschen + pListBox->Clear(); + UniString aTitle(SVX_RES(RID_STR_FIELDSELECTION)); + SetText(aTitle); + + if (!xForm.is()) + return; + + Reference< XPreparedStatement > xStatement; + Reference< XPropertySet > xSet(xForm, UNO_QUERY); + + m_aObjectName = ::comphelper::getString(xSet->getPropertyValue(FM_PROP_COMMAND)); + m_aDatabaseName = ::comphelper::getString(xSet->getPropertyValue(FM_PROP_DATASOURCE)); + m_nObjectType = ::comphelper::getINT32(xSet->getPropertyValue(FM_PROP_COMMANDTYPE)); + + // get the connection of the form + OStaticDataAccessTools aTools; + m_aConnection.reset( + aTools.connectRowset( Reference< XRowSet >( xForm, UNO_QUERY ), ::comphelper::getProcessServiceFactory(), sal_True ), + SharedConnection::NoTakeOwnership + ); + // TODO: When incompatible changes (such as extending the "virtualdbtools" interface by ensureRowSetConnection) + // are allowed, again, we should change this: dbtools should consistently use SharedConnection all over + // the place, and connectRowset should be replaced with ensureRowSetConnection + + // get the fields of the object + + if ( m_aConnection.is() && m_aObjectName.getLength() ) + { + Reference< XComponent > xKeepFieldsAlive; + Reference< XNameAccess > xColumns = getFieldsByCommandDescriptor( m_aConnection, m_nObjectType, m_aObjectName,xKeepFieldsAlive ); + if ( xColumns.is() ) + lcl_addToList(*pListBox,xColumns); + } + + // Prefix setzen + UniString aPrefix; + StringListResource aPrefixes( SVX_RES( RID_RSC_TABWIN_PREFIX ) ); + + switch (m_nObjectType) + { + case CommandType::TABLE: + aPrefix = aPrefixes[0]; + break; + case CommandType::QUERY: + aPrefix = aPrefixes[1]; + break; + default: + aPrefix = aPrefixes[2]; + break; + } + + // an dem PropertySet nach Aenderungen der ControlSource lauschen + if (m_pChangeListener) + { + m_pChangeListener->dispose(); + m_pChangeListener->release(); + } + m_pChangeListener = new ::comphelper::OPropertyChangeMultiplexer(this, xSet); + m_pChangeListener->acquire(); + m_pChangeListener->addProperty(FM_PROP_DATASOURCE); + m_pChangeListener->addProperty(FM_PROP_COMMAND); + m_pChangeListener->addProperty(FM_PROP_COMMANDTYPE); + + // Titel setzen + aTitle.AppendAscii(" "); + aTitle += aPrefix; + aTitle.AppendAscii(" "); + aTitle += m_aObjectName.getStr(); + SetText( aTitle ); + } + catch( const Exception& ) + { + DBG_ERROR( "FmTabWin::UpdateContent: caught an exception!" ); + } +} + +//----------------------------------------------------------------------- +void FmFieldWin::Resize() +{ + SfxFloatingWindow::Resize(); + + Point aPos(GetPosPixel()); + Size aOutputSize( GetOutputSizePixel() ); + + ////////////////////////////////////////////////////////////////////// + + // Groesse der ::com::sun::star::form::ListBox anpassen + Point aLBPos( LISTBOX_BORDER, LISTBOX_BORDER ); + Size aLBSize( aOutputSize ); + aLBSize.Width() -= (2*LISTBOX_BORDER); + aLBSize.Height() -= (2*LISTBOX_BORDER); + + pListBox->SetPosSizePixel( aLBPos, aLBSize ); +} + +//----------------------------------------------------------------------- +void FmFieldWin::FillInfo( SfxChildWinInfo& rInfo ) const +{ + rInfo.bVisible = sal_False; +} + +//----------------------------------------------------------------------- +SFX_IMPL_FLOATINGWINDOW(FmFieldWinMgr, SID_FM_ADD_FIELD) + +//----------------------------------------------------------------------- +FmFieldWinMgr::FmFieldWinMgr(Window* _pParent, sal_uInt16 _nId, + SfxBindings* _pBindings, SfxChildWinInfo* _pInfo) + :SfxChildWindow(_pParent, _nId) +{ + pWindow = new FmFieldWin(_pBindings, this, _pParent); + SetHideNotDelete(sal_True); + eChildAlignment = SFX_ALIGN_NOALIGNMENT; + ((SfxFloatingWindow*)pWindow)->Initialize( _pInfo ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/tbxform.cxx b/svx/source/form/tbxform.cxx new file mode 100644 index 000000000000..96c37148b166 --- /dev/null +++ b/svx/source/form/tbxform.cxx @@ -0,0 +1,469 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include <string> // HACK: prevent conflict between STLPORT and Workshop headers +#include <tools/ref.hxx> +#include <tools/shl.hxx> +#include <svl/intitem.hxx> +#include <svl/eitem.hxx> +#include <svl/stritem.hxx> +#include <sfx2/dispatch.hxx> +#include <vcl/toolbox.hxx> +#include <vcl/fixed.hxx> +#include "fmitems.hxx" +#include "formtoolbars.hxx" + + +#include <vcl/sound.hxx> +#include <svx/dialmgr.hxx> +#include <svx/dialogs.hrc> +#include "tbxctl.hxx" +#include "tbxdraw.hxx" +#include "tbxform.hxx" +#include "fmresids.hrc" +#include "fmitems.hxx" +#include "fmhelp.hrc" +#include <sfx2/viewfrm.hxx> +#include <sfx2/viewsh.hxx> +#include <sfx2/imagemgr.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::frame; +using ::com::sun::star::beans::XPropertySet; + + +//======================================================================== +// class SvxFmAbsRecWin +//======================================================================== + +// ----------------------------------------------------------------------- +SvxFmAbsRecWin::SvxFmAbsRecWin( Window* _pParent, SfxToolBoxControl* _pController ) + :NumericField( _pParent, WB_BORDER ) + ,m_pController(_pController) +{ + SetMin(1); + SetFirst(1); + SetSpinSize(1); + SetSizePixel( Size(70,19) ); + + SetDecimalDigits(0); + SetStrictFormat(TRUE); +} + +// ----------------------------------------------------------------------- +SvxFmAbsRecWin::~SvxFmAbsRecWin() +{ +} + +// ----------------------------------------------------------------------- +void SvxFmAbsRecWin::FirePosition( sal_Bool _bForce ) +{ + if ( _bForce || ( GetText() != GetSavedValue() ) ) + { + sal_Int64 nRecord = GetValue(); + if (nRecord < GetMin() || nRecord > GetMax()) + { + Sound::Beep(); + return; + } + + SfxInt32Item aPositionParam( FN_PARAM_1, static_cast<INT32>(nRecord) ); + + Any a; + Sequence< PropertyValue > aArgs( 1 ); + aArgs[0].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Position" )); + aPositionParam.QueryValue( a ); + aArgs[0].Value = a; + m_pController->Dispatch( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".uno:AbsoluteRecord" )), + aArgs ); + m_pController->updateStatus(); + + SaveValue(); + } +} + +// ----------------------------------------------------------------------- +void SvxFmAbsRecWin::LoseFocus() +{ + FirePosition( sal_False ); +} + +// ----------------------------------------------------------------------- +void SvxFmAbsRecWin::KeyInput( const KeyEvent& rKeyEvent ) +{ + if( rKeyEvent.GetKeyCode() == KEY_RETURN && GetText().Len() ) + FirePosition( sal_True ); + else + NumericField::KeyInput( rKeyEvent ); +} + +//======================================================================== +// class SvxFmTbxCtlConfig +//======================================================================== + +struct MapSlotToCmd +{ + USHORT nSlotId; + const char* pCommand; +}; + +static MapSlotToCmd SlotToCommands[] = +{ + { SID_FM_PUSHBUTTON, ".uno:Pushbutton" }, + { SID_FM_RADIOBUTTON, ".uno:RadioButton" }, + { SID_FM_CHECKBOX, ".uno:CheckBox" }, + { SID_FM_FIXEDTEXT, ".uno:Label" }, + { SID_FM_GROUPBOX, ".uno:GroupBox" }, + { SID_FM_LISTBOX, ".uno:ListBox" }, + { SID_FM_COMBOBOX, ".uno:ComboBox" }, + { SID_FM_EDIT, ".uno:Edit" }, + { SID_FM_DBGRID, ".uno:Grid" }, + { SID_FM_IMAGEBUTTON, ".uno:Imagebutton" }, + { SID_FM_IMAGECONTROL, ".uno:ImageControl" }, + { SID_FM_FILECONTROL, ".uno:FileControl" }, + { SID_FM_DATEFIELD, ".uno:DateField" }, + { SID_FM_TIMEFIELD, ".uno:TimeField" }, + { SID_FM_NUMERICFIELD, ".uno:NumericField" }, + { SID_FM_CURRENCYFIELD, ".uno:CurrencyField" }, + { SID_FM_PATTERNFIELD, ".uno:PatternField" }, + { SID_FM_DESIGN_MODE, ".uno:SwitchControlDesignMode" }, + { SID_FM_FORMATTEDFIELD, ".uno:FormattedField" }, + { SID_FM_SCROLLBAR, ".uno:ScrollBar" }, + { SID_FM_SPINBUTTON, ".uno:SpinButton" }, + { 0, "" } +}; + +SFX_IMPL_TOOLBOX_CONTROL( SvxFmTbxCtlConfig, SfxUInt16Item ); + +//----------------------------------------------------------------------- +SvxFmTbxCtlConfig::SvxFmTbxCtlConfig( USHORT nSlotId, USHORT nId, ToolBox& rTbx ) + : SfxToolBoxControl( nSlotId, nId, rTbx ) + ,nLastSlot( 0 ) +{ + rTbx.SetItemBits( nId, TIB_DROPDOWN | rTbx.GetItemBits( nId ) ); +} + +//----------------------------------------------------------------------- +void SvxFmTbxCtlConfig::StateChanged(USHORT nSID, SfxItemState eState, const SfxPoolItem* pState ) +{ + if (nSID == SID_FM_CONFIG) + { + UINT16 nSlot = 0; + if (eState >= SFX_ITEM_AVAILABLE) + nSlot = ((SfxUInt16Item*)pState)->GetValue(); + + switch( nSlot ) + { + case SID_FM_PUSHBUTTON: + case SID_FM_RADIOBUTTON: + case SID_FM_CHECKBOX: + case SID_FM_FIXEDTEXT: + case SID_FM_GROUPBOX: + case SID_FM_LISTBOX: + case SID_FM_COMBOBOX: + case SID_FM_NAVIGATIONBAR: + case SID_FM_EDIT: + case SID_FM_DBGRID: + case SID_FM_IMAGEBUTTON: + case SID_FM_IMAGECONTROL: + case SID_FM_FILECONTROL: + case SID_FM_DATEFIELD: + case SID_FM_TIMEFIELD: + case SID_FM_NUMERICFIELD: + case SID_FM_CURRENCYFIELD: + case SID_FM_PATTERNFIELD: + case SID_FM_DESIGN_MODE: + case SID_FM_FORMATTEDFIELD: + case SID_FM_SCROLLBAR: + case SID_FM_SPINBUTTON: + { // set a new image, matching to this slot + rtl::OUString aSlotURL( RTL_CONSTASCII_USTRINGPARAM( "slot:" )); + aSlotURL += rtl::OUString::valueOf( sal_Int32( nSlot )); + Image aImage = GetImage( m_xFrame, aSlotURL, hasBigImages() ); + GetToolBox().SetItemImage( GetId(), aImage ); + nLastSlot = nSlot; + } + break; + } + } + SfxToolBoxControl::StateChanged( nSID, eState,pState ); +} + +//----------------------------------------------------------------------- +SfxPopupWindowType SvxFmTbxCtlConfig::GetPopupWindowType() const +{ + return( nLastSlot == 0 ? SFX_POPUPWINDOW_ONCLICK : SFX_POPUPWINDOW_ONTIMEOUT ); +} + +//----------------------------------------------------------------------- +SfxPopupWindow* SvxFmTbxCtlConfig::CreatePopupWindow() +{ + if ( GetSlotId() == SID_FM_CONFIG ) + { + ::svxform::FormToolboxes aToolboxes( m_xFrame ); + createAndPositionSubToolBar( aToolboxes.getToolboxResourceName( SID_FM_CONFIG ) ); + } + return NULL; +} + +//----------------------------------------------------------------------- +void SvxFmTbxCtlConfig::Select( USHORT /*nModifier*/ ) +{ + ////////////////////////////////////////////////////////////////////// + // Click auf den Button SID_FM_CONFIG in der ObjectBar + if ( nLastSlot ) + { + USHORT n = 0; + while( SlotToCommands[n].nSlotId > 0 ) + { + if ( SlotToCommands[n].nSlotId == nLastSlot ) + break; + n++; + } + + if ( SlotToCommands[n].nSlotId > 0 ) + { + Sequence< PropertyValue > aArgs; + Dispatch( rtl::OUString::createFromAscii( SlotToCommands[n].pCommand ), + aArgs ); + } + } +} + + +//======================================================================== +// class SvxFmTbxCtlAbsRec +//======================================================================== + +SFX_IMPL_TOOLBOX_CONTROL( SvxFmTbxCtlAbsRec, SfxInt32Item ); +DBG_NAME(SvxFmTbxCtlAbsRec); +//----------------------------------------------------------------------- +SvxFmTbxCtlAbsRec::SvxFmTbxCtlAbsRec( USHORT nSlotId, USHORT nId, ToolBox& rTbx ) + :SfxToolBoxControl( nSlotId, nId, rTbx ) +{ + DBG_CTOR(SvxFmTbxCtlAbsRec,NULL); +} + +//----------------------------------------------------------------------- +SvxFmTbxCtlAbsRec::~SvxFmTbxCtlAbsRec() +{ + DBG_DTOR(SvxFmTbxCtlAbsRec,NULL); +} + +//----------------------------------------------------------------------- +void SvxFmTbxCtlAbsRec::StateChanged( USHORT nSID, SfxItemState eState, const SfxPoolItem* pState ) +{ + USHORT nId = GetId(); + ToolBox* pToolBox = &GetToolBox(); + SvxFmAbsRecWin* pWin = (SvxFmAbsRecWin*)( pToolBox->GetItemWindow(nId) ); + + DBG_ASSERT( pWin, "Control not found!" ); + + if (pState) + { + const SfxInt32Item* pItem = PTR_CAST( SfxInt32Item, pState ); + DBG_ASSERT( pItem, "SvxFmTbxCtlAbsRec::StateChanged: invalid item!" ); + pWin->SetValue( pItem ? pItem->GetValue() : -1 ); + } + + BOOL bEnable = SFX_ITEM_DISABLED != eState && pState; + if (!bEnable) + pWin->SetText(String()); + + ////////////////////////////////////////////////////////////////////// + // Enablen/disablen des Fensters + pToolBox->EnableItem(nId, bEnable); + SfxToolBoxControl::StateChanged( nSID, eState,pState ); +} + +//----------------------------------------------------------------------- +Window* SvxFmTbxCtlAbsRec::CreateItemWindow( Window* pParent ) +{ + SvxFmAbsRecWin* pWin = new SvxFmAbsRecWin( pParent, this ); + pWin->SetUniqueId( UID_ABSOLUTE_RECORD_WINDOW ); + return pWin; +} + + +//======================================================================== +// SvxFmTbxCtlRecText +//======================================================================== + +SFX_IMPL_TOOLBOX_CONTROL( SvxFmTbxCtlRecText, SfxBoolItem ); +DBG_NAME(SvxFmTbxCtlRecText); +//----------------------------------------------------------------------- +SvxFmTbxCtlRecText::SvxFmTbxCtlRecText( USHORT nSlotId, USHORT nId, ToolBox& rTbx ) + :SfxToolBoxControl( nSlotId, nId, rTbx ) +{ + DBG_CTOR(SvxFmTbxCtlRecText,NULL); +} + +//----------------------------------------------------------------------- +SvxFmTbxCtlRecText::~SvxFmTbxCtlRecText() +{ + DBG_DTOR(SvxFmTbxCtlRecText,NULL); +} + +//----------------------------------------------------------------------- +Window* SvxFmTbxCtlRecText::CreateItemWindow( Window* pParent ) +{ + XubString aText( SVX_RES(RID_STR_REC_TEXT) ); + FixedText* pFixedText = new FixedText( pParent ); + Size aSize( pFixedText->GetTextWidth( aText ), pFixedText->GetTextHeight( ) ); + pFixedText->SetText( aText ); + aSize.Width() += 6; + pFixedText->SetSizePixel( aSize ); + pFixedText->SetBackground(Wallpaper(Color(COL_TRANSPARENT))); + + return pFixedText; +} + + +//======================================================================== +// SvxFmTbxCtlRecFromText +//======================================================================== + +SFX_IMPL_TOOLBOX_CONTROL( SvxFmTbxCtlRecFromText, SfxBoolItem ); +DBG_NAME(SvxFmTbxCtlRecFromText); +//----------------------------------------------------------------------- +SvxFmTbxCtlRecFromText::SvxFmTbxCtlRecFromText( USHORT nSlotId, USHORT nId, ToolBox& rTbx ) + :SfxToolBoxControl( nSlotId, nId, rTbx ) +{ + DBG_CTOR(SvxFmTbxCtlRecFromText,NULL); +} + +//----------------------------------------------------------------------- +SvxFmTbxCtlRecFromText::~SvxFmTbxCtlRecFromText() +{ + DBG_DTOR(SvxFmTbxCtlRecFromText,NULL); +} + +//----------------------------------------------------------------------- +Window* SvxFmTbxCtlRecFromText::CreateItemWindow( Window* pParent ) +{ + XubString aText( SVX_RES(RID_STR_REC_FROM_TEXT) ); + FixedText* pFixedText = new FixedText( pParent, WB_CENTER ); + Size aSize( pFixedText->GetTextWidth( aText ), pFixedText->GetTextHeight( ) ); + aSize.Width() += 12; + pFixedText->SetText( aText ); + pFixedText->SetSizePixel( aSize ); + pFixedText->SetBackground(Wallpaper(Color(COL_TRANSPARENT))); + return pFixedText; +} + + +//======================================================================== +// SvxFmTbxCtlRecTotal +//======================================================================== +DBG_NAME(SvxFmTbxCtlRecTotal); +SFX_IMPL_TOOLBOX_CONTROL( SvxFmTbxCtlRecTotal, SfxStringItem ); + +//----------------------------------------------------------------------- +SvxFmTbxCtlRecTotal::SvxFmTbxCtlRecTotal( USHORT nSlotId, USHORT nId, ToolBox& rTbx ) + :SfxToolBoxControl( nSlotId, nId, rTbx ) + ,pFixedText( NULL ) +{ + DBG_CTOR(SvxFmTbxCtlRecTotal,NULL); +} + +//----------------------------------------------------------------------- +SvxFmTbxCtlRecTotal::~SvxFmTbxCtlRecTotal() +{ + DBG_DTOR(SvxFmTbxCtlRecTotal,NULL); +} + +//----------------------------------------------------------------------- +Window* SvxFmTbxCtlRecTotal::CreateItemWindow( Window* pParent ) +{ + pFixedText = new FixedText( pParent ); + String aSample(RTL_CONSTASCII_USTRINGPARAM("123456")); + Size aSize( pFixedText->GetTextWidth( aSample ), pFixedText->GetTextHeight( ) ); + aSize.Width() += 12; + pFixedText->SetSizePixel( aSize ); + pFixedText->SetBackground(); + pFixedText->SetPaintTransparent(TRUE); + return pFixedText; +} + +//----------------------------------------------------------------------- +void SvxFmTbxCtlRecTotal::StateChanged( USHORT nSID, SfxItemState eState, const SfxPoolItem* pState ) +{ + ////////////////////////////////////////////////////////////////////// + // Setzen des FixedTextes + if (GetSlotId() != SID_FM_RECORD_TOTAL) + return; + + XubString aText; + if (pState) + aText = ((SfxStringItem*)pState)->GetValue(); + else + aText = '?'; + + pFixedText->SetText( aText ); + pFixedText->Update(); + pFixedText->Flush(); + + SfxToolBoxControl::StateChanged( nSID, eState,pState ); +} + +//======================================================================== +// SvxFmTbxNextRec +//======================================================================== +SFX_IMPL_TOOLBOX_CONTROL( SvxFmTbxNextRec, SfxBoolItem ); + +//----------------------------------------------------------------------- +SvxFmTbxNextRec::SvxFmTbxNextRec( USHORT nSlotId, USHORT nId, ToolBox& rTbx ) + :SfxToolBoxControl( nSlotId, nId, rTbx ) +{ + rTbx.SetItemBits(nId, rTbx.GetItemBits(nId) | TIB_REPEAT); + + AllSettings aSettings = rTbx.GetSettings(); + MouseSettings aMouseSettings = aSettings.GetMouseSettings(); + aMouseSettings.SetButtonRepeat(aMouseSettings.GetButtonRepeat() / 4); + aSettings.SetMouseSettings(aMouseSettings); + rTbx.SetSettings(aSettings, TRUE); +} + +//======================================================================== +// SvxFmTbxPrevRec +//======================================================================== +SFX_IMPL_TOOLBOX_CONTROL( SvxFmTbxPrevRec, SfxBoolItem ); + +//----------------------------------------------------------------------- +SvxFmTbxPrevRec::SvxFmTbxPrevRec( USHORT nSlotId, USHORT nId, ToolBox& rTbx ) + :SfxToolBoxControl( nSlotId, nId, rTbx ) +{ + rTbx.SetItemBits(nId, rTbx.GetItemBits(nId) | TIB_REPEAT); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/typeconversionclient.cxx b/svx/source/form/typeconversionclient.cxx new file mode 100644 index 000000000000..fd9427c1aa1a --- /dev/null +++ b/svx/source/form/typeconversionclient.cxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include "typeconversionclient.hxx" + +//........................................................................ +namespace svxform +{ +//........................................................................ + + //==================================================================== + //= OTypeConversionClient + //==================================================================== + //-------------------------------------------------------------------- + OTypeConversionClient::OTypeConversionClient() + { + } + + //-------------------------------------------------------------------- + bool OTypeConversionClient::ensureLoaded() const + { + if ( !ODbtoolsClient::ensureLoaded() ) + return false; + m_xTypeConversion = getFactory()->getTypeConversionHelper(); + return m_xTypeConversion.is(); + } + +//........................................................................ +} // namespace svxform +//........................................................................ + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/typemap.cxx b/svx/source/form/typemap.cxx new file mode 100644 index 000000000000..d0f9763d770f --- /dev/null +++ b/svx/source/form/typemap.cxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include <sfx2/objitem.hxx> +#include <sfx2/msg.hxx> +#include <svl/stritem.hxx> +#include <svl/intitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/cntritem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/postitem.hxx> +#include "clipfmtitem.hxx" +#include <editeng/fhgtitem.hxx> +#include "editeng/fontitem.hxx" +#include <editeng/charreliefitem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/charscaleitem.hxx> +#include <editeng/akrnitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/lspcitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/tstpitem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/emphitem.hxx> + +#include <editeng/memberids.hrc> +#define SFX_TYPEMAP +#include "svxslots.hxx" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/form/xfm_addcondition.cxx b/svx/source/form/xfm_addcondition.cxx new file mode 100644 index 000000000000..aff2199bd49d --- /dev/null +++ b/svx/source/form/xfm_addcondition.cxx @@ -0,0 +1,193 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include "xfm_addcondition.hxx" + +/** === begin UNO includes === **/ +/** === end UNO includes === **/ +#include <cppuhelper/typeprovider.hxx> +#include "datanavi.hxx" +#include <vcl/msgbox.hxx> + +//........................................................................ +namespace svxform +{ +//........................................................................ + +#define PROPERTY_ID_BINDING 5724 +#define PROPERTY_ID_FORM_MODEL 5725 +#define PROPERTY_ID_FACET_NAME 5726 +#define PROPERTY_ID_CONDITION_VALUE 5727 + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::xforms; + + //==================================================================== + //= OAddConditionDialog + //==================================================================== + //-------------------------------------------------------------------- + Reference< XInterface > SAL_CALL OAddConditionDialog_Create( const Reference< XMultiServiceFactory > & _rxORB ) + { + return OAddConditionDialog::Create( _rxORB ); + } + + //-------------------------------------------------------------------- + Sequence< ::rtl::OUString > SAL_CALL OAddConditionDialog_GetSupportedServiceNames() + { + ::comphelper::StringSequence aSupported( 1 ); + aSupported.getArray()[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.xforms.ui.dialogs.AddCondition" ) ); + return aSupported; + } + + //-------------------------------------------------------------------- + ::rtl::OUString SAL_CALL OAddConditionDialog_GetImplementationName() + { + return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("org.openoffice.comp.svx.OAddConditionDialog")); + } + + //==================================================================== + //= OAddConditionDialog + //==================================================================== + //-------------------------------------------------------------------- + OAddConditionDialog::OAddConditionDialog( const Reference< XMultiServiceFactory >& _rxORB ) + :OAddConditionDialogBase( _rxORB ) + { + registerProperty( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Binding" ) ), + PROPERTY_ID_BINDING, + PropertyAttribute::TRANSIENT, + &m_xBinding, + ::getCppuType( &m_xBinding ) + ); + + registerProperty( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FacetName" ) ), + PROPERTY_ID_FACET_NAME, + PropertyAttribute::TRANSIENT, + &m_sFacetName, + ::getCppuType( &m_sFacetName ) + ); + + registerProperty( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ConditionValue" ) ), + PROPERTY_ID_CONDITION_VALUE, + PropertyAttribute::TRANSIENT, + &m_sConditionValue, + ::getCppuType( &m_sConditionValue ) + ); + + registerProperty( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FormModel" ) ), + PROPERTY_ID_FORM_MODEL, + PropertyAttribute::TRANSIENT, + &m_xWorkModel, + ::getCppuType( &m_xWorkModel ) + ); + } + + //------------------------------------------------------------------------- + Sequence<sal_Int8> SAL_CALL OAddConditionDialog::getImplementationId( ) throw(RuntimeException) + { + static ::cppu::OImplementationId * pId = 0; + if (! pId) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if (! pId) + { + static ::cppu::OImplementationId aId; + pId = &aId; + } + } + return pId->getImplementationId(); + } + + //------------------------------------------------------------------------- + Reference< XInterface > SAL_CALL OAddConditionDialog::Create( const Reference< XMultiServiceFactory >& _rxFactory ) + { + return *( new OAddConditionDialog( _rxFactory ) ); + } + + //------------------------------------------------------------------------- + ::rtl::OUString SAL_CALL OAddConditionDialog::getImplementationName() throw(RuntimeException) + { + return OAddConditionDialog_GetImplementationName(); + } + + //------------------------------------------------------------------------- + Sequence< ::rtl::OUString > SAL_CALL OAddConditionDialog::getSupportedServiceNames() throw(RuntimeException) + { + return OAddConditionDialog_GetSupportedServiceNames(); + } + + //------------------------------------------------------------------------- + Reference<XPropertySetInfo> SAL_CALL OAddConditionDialog::getPropertySetInfo() throw(RuntimeException) + { + return createPropertySetInfo( getInfoHelper() ); + } + + //------------------------------------------------------------------------- + ::cppu::IPropertyArrayHelper& OAddConditionDialog::getInfoHelper() + { + return *const_cast< OAddConditionDialog* >( this )->getArrayHelper(); + } + + //------------------------------------------------------------------------------ + ::cppu::IPropertyArrayHelper* OAddConditionDialog::createArrayHelper( ) const + { + Sequence< Property > aProperties; + describeProperties( aProperties ); + return new ::cppu::OPropertyArrayHelper( aProperties ); + } + + //------------------------------------------------------------------------------ + Dialog* OAddConditionDialog::createDialog(Window* _pParent) + { + if ( !m_xBinding.is() || !m_sFacetName.getLength() ) + throw RuntimeException( ::rtl::OUString(), *this ); + + return new AddConditionDialog( _pParent, m_sFacetName, m_xBinding ); + } + + //------------------------------------------------------------------------------ + void OAddConditionDialog::executedDialog( sal_Int16 _nExecutionResult ) + { + OAddConditionDialogBase::executedDialog( _nExecutionResult ); + if ( _nExecutionResult == RET_OK ) + m_sConditionValue = static_cast< AddConditionDialog* >( m_pDialog )->GetCondition(); + } + +//........................................................................ +} // namespace svxformv +//........................................................................ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |