diff options
Diffstat (limited to '')
-rw-r--r-- | forms/source/component/Filter.cxx | 890 |
1 files changed, 890 insertions, 0 deletions
diff --git a/forms/source/component/Filter.cxx b/forms/source/component/Filter.cxx new file mode 100644 index 000000000..a2a2ec5ca --- /dev/null +++ b/forms/source/component/Filter.cxx @@ -0,0 +1,890 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <config_features.h> +#include <config_fuzzers.h> + +#include "Filter.hxx" +#include <strings.hrc> +#include <frm_resource.hxx> +#include <frm_strings.hxx> + +#include <com/sun/star/awt/VclWindowPeerAttribute.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/XRadioButton.hpp> +#include <com/sun/star/awt/XVclWindowPeer.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/form/FormComponentType.hpp> +#include <com/sun/star/sdb/ErrorMessageDialog.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbc/XRowSet.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#include <com/sun/star/util/NumberFormatter.hpp> +#include <com/sun/star/awt/XItemList.hpp> + +#include <comphelper/property.hxx> +#include <comphelper/types.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/formattedcolumnvalue.hxx> +#include <connectivity/predicateinput.hxx> +#include <o3tl/safeint.hxx> +#include <rtl/ustrbuf.hxx> +#include <tools/diagnose_ex.h> +#include <tools/gen.hxx> + + +namespace frm +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::sdb; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::sdbcx; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::form; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::ui::dialogs; + + using namespace ::connectivity; + + OFilterControl::OFilterControl( const Reference< XComponentContext >& _rxORB ) + :m_aTextListeners( *this ) + ,m_xContext( _rxORB ) + ,m_nControlClass( FormComponentType::TEXTFIELD ) + ,m_bFilterList( false ) + ,m_bMultiLine( false ) + ,m_bFilterListFilled( false ) + { + } + + + bool OFilterControl::ensureInitialized( ) + { +#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS + if ( !m_xField.is() ) + { + OSL_FAIL( "OFilterControl::ensureInitialized: improperly initialized: no field!" ); + return false; + } + + if ( !m_xConnection.is() ) + { + OSL_FAIL( "OFilterControl::ensureInitialized: improperly initialized: no connection!" ); + return false; + } + + if ( !m_xFormatter.is() ) + { + // we can create one from the connection, if it's an SDB connection + + Reference< XNumberFormatsSupplier > xFormatSupplier = ::dbtools::getNumberFormats( m_xConnection, true, m_xContext ); + + if ( xFormatSupplier.is() ) + { + m_xFormatter.set(NumberFormatter::create(m_xContext), UNO_QUERY_THROW ); + m_xFormatter->attachNumberFormatsSupplier( xFormatSupplier ); + } + } + if ( !m_xFormatter.is() ) + { + OSL_FAIL( "OFilterControl::ensureInitialized: no number formatter!" ); + // no fallback anymore + return false; + } +#endif + return true; + } + + + Any SAL_CALL OFilterControl::queryAggregation( const Type & rType ) + { + Any aRet = UnoControl::queryAggregation( rType); + if(!aRet.hasValue()) + aRet = OFilterControl_BASE::queryInterface(rType); + + return aRet; + } + + + OUString OFilterControl::GetComponentServiceName() const + { + OUString aServiceName; + switch (m_nControlClass) + { + case FormComponentType::RADIOBUTTON: + aServiceName = "radiobutton"; + break; + case FormComponentType::CHECKBOX: + aServiceName = "checkbox"; + break; + case FormComponentType::COMBOBOX: + aServiceName = "combobox"; + break; + case FormComponentType::LISTBOX: + aServiceName = "listbox"; + break; + default: + if (m_bMultiLine) + aServiceName = "MultiLineEdit"; + else + aServiceName = "Edit"; + } + return aServiceName; + } + + // XComponent + + void OFilterControl::dispose() + { + EventObject aEvt(*this); + m_aTextListeners.disposeAndClear( aEvt ); + UnoControl::dispose(); + } + + + void OFilterControl::createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer ) + { + UnoControl::createPeer( rxToolkit, rParentPeer ); + + try + { + Reference< XVclWindowPeer > xVclWindow( getPeer(), UNO_QUERY_THROW ); + switch ( m_nControlClass ) + { + case FormComponentType::CHECKBOX: + { + // checkboxes always have a tristate-mode + xVclWindow->setProperty( PROPERTY_TRISTATE, Any( true ) ); + xVclWindow->setProperty( PROPERTY_STATE, Any( sal_Int32( TRISTATE_INDET ) ) ); + + Reference< XCheckBox > xBox( getPeer(), UNO_QUERY_THROW ); + xBox->addItemListener( this ); + + } + break; + + case FormComponentType::RADIOBUTTON: + { + xVclWindow->setProperty( PROPERTY_STATE, Any( sal_Int32( TRISTATE_FALSE ) ) ); + + Reference< XRadioButton > xRadio( getPeer(), UNO_QUERY_THROW ); + xRadio->addItemListener( this ); + } + break; + + case FormComponentType::LISTBOX: + { + Reference< XListBox > xListBox( getPeer(), UNO_QUERY_THROW ); + xListBox->addItemListener( this ); + [[fallthrough]]; + } + + case FormComponentType::COMBOBOX: + { + xVclWindow->setProperty(PROPERTY_AUTOCOMPLETE, Any( true ) ); + [[fallthrough]]; + } + + default: + { + Reference< XWindow > xWindow( getPeer(), UNO_QUERY ); + xWindow->addFocusListener( this ); + + Reference< XTextComponent > xText( getPeer(), UNO_QUERY ); + if (xText.is()) + xText->setMaxTextLen(0); + } + break; + } + + // filter controls are _never_ readonly + Reference< XPropertySet > xModel( getModel(), UNO_QUERY_THROW ); + Reference< XPropertySetInfo > xModelPSI( xModel->getPropertySetInfo(), UNO_SET_THROW ); + if ( xModelPSI->hasPropertyByName( PROPERTY_READONLY ) ) + xVclWindow->setProperty( PROPERTY_READONLY, Any( false ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("forms.component"); + } + + if (m_bFilterList) + m_bFilterListFilled = false; + } + + + void OFilterControl::PrepareWindowDescriptor( WindowDescriptor& rDescr ) + { + if (m_bFilterList) + rDescr.WindowAttributes |= VclWindowPeerAttribute::DROPDOWN; + } + + + void OFilterControl::ImplSetPeerProperty( const OUString& rPropName, const Any& rVal ) + { + // these properties are ignored + if (rPropName == PROPERTY_TEXT || + rPropName == PROPERTY_STATE) + return; + + UnoControl::ImplSetPeerProperty( rPropName, rVal ); + } + + // XEventListener + + void SAL_CALL OFilterControl::disposing(const EventObject& Source) + { + UnoControl::disposing(Source); + } + + // XItemListener + + void SAL_CALL OFilterControl::itemStateChanged( const ItemEvent& rEvent ) + { +#if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS + (void) rEvent; +#else + OUStringBuffer aText; + switch (m_nControlClass) + { + case FormComponentType::CHECKBOX: + { + if ( ( rEvent.Selected == TRISTATE_TRUE ) || ( rEvent.Selected == TRISTATE_FALSE ) ) + { + sal_Int32 nBooleanComparisonMode = ::dbtools::DatabaseMetaData( m_xConnection ).getBooleanComparisonMode(); + + bool bSelected = ( rEvent.Selected == TRISTATE_TRUE ); + + OUString sExpressionMarker( "$expression$" ); + ::dbtools::getBooleanComparisonPredicate( + sExpressionMarker, + bSelected, + nBooleanComparisonMode, + aText + ); + + OUString sText( aText.makeStringAndClear() ); + sal_Int32 nMarkerPos( sText.indexOf( sExpressionMarker ) ); + OSL_ENSURE( nMarkerPos == 0, "OFilterControl::itemStateChanged: unsupported boolean comparison mode!" ); + // If this assertion fails, then getBooleanComparisonPredicate created a predicate which + // does not start with the expression we gave it. The only known case is when + // the comparison mode is ACCESS_COMPAT, and the value is TRUE. In this case, + // the expression is rather complex. + // Well, so this is a known issue - the filter controls (and thus the form based filter) + // do not work with boolean MS Access fields. + // To fix this, we would probably have to revert here to always return "1" or "0" as normalized + // filter, and change our client code to properly translate this (which could be some effort). + if ( nMarkerPos == 0 ) + aText.append( sText.subView(sExpressionMarker.getLength()) ); + else + { + // fallback + aText.appendAscii( bSelected ? "1" : "0" ); + } + } + } + break; + + case FormComponentType::LISTBOX: + { + try + { + const Reference< XItemList > xItemList( getModel(), UNO_QUERY_THROW ); + OUString sItemText( xItemList->getItemText( rEvent.Selected ) ); + + const MapString2String::const_iterator itemPos = m_aDisplayItemToValueItem.find( sItemText ); + if ( itemPos != m_aDisplayItemToValueItem.end() ) + { + sItemText = itemPos->second; + if ( !sItemText.isEmpty() ) + { + ::dbtools::OPredicateInputController aPredicateInput( m_xContext, m_xConnection, getParseContext() ); + OUString sErrorMessage; + OSL_VERIFY( aPredicateInput.normalizePredicateString( sItemText, m_xField, &sErrorMessage ) ); + } + } + aText.append( sItemText ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("forms.component"); + } + } + break; + + case FormComponentType::RADIOBUTTON: + { + if ( rEvent.Selected == TRISTATE_TRUE ) + aText.append( ::comphelper::getString( Reference< XPropertySet >( getModel(), UNO_QUERY_THROW )->getPropertyValue( PROPERTY_REFVALUE ) ) ); + } + break; + } + + OUString sText( aText.makeStringAndClear() ); + if ( m_aText != sText ) + { + m_aText = sText; + TextEvent aEvt; + aEvt.Source = *this; + ::comphelper::OInterfaceIteratorHelper3 aIt(m_aTextListeners); + while( aIt.hasMoreElements() ) + aIt.next()->textChanged(aEvt); + } +#endif + } + + + void OFilterControl::implInitFilterList() + { +#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS + if ( !ensureInitialized( ) ) + // already asserted in ensureInitialized + return; + + // ensure the cursor and the statement are disposed as soon as we leave + ::utl::SharedUNOComponent< XResultSet > xListCursor; + ::utl::SharedUNOComponent< XStatement > xStatement; + + try + { + m_bFilterListFilled = true; + + if ( !m_xField.is() ) + return; + + OUString sFieldName; + m_xField->getPropertyValue( PROPERTY_NAME ) >>= sFieldName; + + // here we need a table to which the field belongs to + const Reference< XChild > xModelAsChild( getModel(), UNO_QUERY_THROW ); + const Reference< XRowSet > xForm( xModelAsChild->getParent(), UNO_QUERY_THROW ); + const Reference< XPropertySet > xFormProps( xForm, UNO_QUERY_THROW ); + + // create a query composer + Reference< XColumnsSupplier > xSuppColumns; + xFormProps->getPropertyValue("SingleSelectQueryComposer") >>= xSuppColumns; + + const Reference< XConnection > xConnection( ::dbtools::getConnection( xForm ), UNO_SET_THROW ); + const Reference< XNameAccess > xFieldNames( xSuppColumns->getColumns(), UNO_SET_THROW ); + if ( !xFieldNames->hasByName( sFieldName ) ) + return; + OUString sRealFieldName, sTableName; + const Reference< XPropertySet > xComposerFieldProps( xFieldNames->getByName( sFieldName ), UNO_QUERY_THROW ); + xComposerFieldProps->getPropertyValue( PROPERTY_REALNAME ) >>= sRealFieldName; + xComposerFieldProps->getPropertyValue( PROPERTY_TABLENAME ) >>= sTableName; + + // obtain the table of the field + const Reference< XTablesSupplier > xSuppTables( xSuppColumns, UNO_QUERY_THROW ); + const Reference< XNameAccess > xTablesNames( xSuppTables->getTables(), UNO_SET_THROW ); + const Reference< XNamed > xNamedTable( xTablesNames->getByName( sTableName ), UNO_QUERY_THROW ); + sTableName = xNamedTable->getName(); + + // create a statement selecting all values for the given field + OUStringBuffer aStatement; + + const Reference< XDatabaseMetaData > xMeta( xConnection->getMetaData(), UNO_SET_THROW ); + const OUString sQuoteChar = xMeta->getIdentifierQuoteString(); + + aStatement.append( "SELECT DISTINCT " ); + aStatement.append( sQuoteChar ); + aStatement.append( sRealFieldName ); + aStatement.append( sQuoteChar ); + + // if the field had an alias in our form's statement, give it this alias in the new statement, too + if ( !sFieldName.isEmpty() && ( sFieldName != sRealFieldName ) ) + { + aStatement.append(" AS "); + aStatement.append( sQuoteChar ); + aStatement.append( sFieldName ); + aStatement.append( sQuoteChar ); + } + + aStatement.append( " FROM " ); + + OUString sCatalog, sSchema, sTable; + ::dbtools::qualifiedNameComponents( xMeta, sTableName, sCatalog, sSchema, sTable, ::dbtools::EComposeRule::InDataManipulation ); + aStatement.append( ::dbtools::composeTableNameForSelect( xConnection, sCatalog, sSchema, sTable ) ); + + // execute the statement + xStatement.reset( xConnection->createStatement() ); + const OUString sSelectStatement( aStatement.makeStringAndClear( ) ); + xListCursor.reset( xStatement->executeQuery( sSelectStatement ) ); + + // retrieve the one column which we take the values from + const Reference< XColumnsSupplier > xSupplyCols( xListCursor, UNO_QUERY_THROW ); + const Reference< XIndexAccess > xFields( xSupplyCols->getColumns(), UNO_QUERY_THROW ); + const Reference< XPropertySet > xDataField( xFields->getByIndex(0), UNO_QUERY_THROW ); + + // ensure the values will be formatted according to the field format + const ::dbtools::FormattedColumnValue aFormatter( m_xFormatter, xDataField ); + + ::std::vector< OUString > aProposals; + aProposals.reserve(16); + + while ( xListCursor->next() && ( aProposals.size() < o3tl::make_unsigned( SHRT_MAX ) ) ) + { + const OUString sCurrentValue = aFormatter.getFormattedValue(); + aProposals.push_back( sCurrentValue ); + } + + // fill the list items into our peer + Sequence< OUString> aStringSeq( comphelper::containerToSequence(aProposals) ); + + const Reference< XComboBox > xComboBox( getPeer(), UNO_QUERY_THROW ); + xComboBox->addItems( aStringSeq, 0 ); + + // set the drop down line count to something reasonable + const sal_Int16 nLineCount = ::std::min( sal_Int16( 16 ), sal_Int16( aStringSeq.getLength() ) ); + xComboBox->setDropDownLineCount( nLineCount ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("forms.component"); + } +#endif + } + + // XFocusListener + + void SAL_CALL OFilterControl::focusGained(const FocusEvent& /*e*/) + { + // should we fill the combobox? + if (m_bFilterList && !m_bFilterListFilled) + implInitFilterList(); + } + + + void SAL_CALL OFilterControl::focusLost(const FocusEvent& /*e*/) + { + } + + + sal_Bool SAL_CALL OFilterControl::commit() + { +#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS + if ( !ensureInitialized( ) ) + // already asserted in ensureInitialized + return true; + + OUString aText; + switch (m_nControlClass) + { + case FormComponentType::TEXTFIELD: + case FormComponentType::COMBOBOX: + { + Reference< XTextComponent > xText( getPeer(), UNO_QUERY ); + if (xText.is()) + aText = xText->getText(); + } break; + default: + return true; + } + if ( m_aText == aText ) + return true; + // check the text with the SQL-Parser + OUString aNewText = aText.trim(); + if ( !aNewText.isEmpty() ) + { + ::dbtools::OPredicateInputController aPredicateInput( m_xContext, m_xConnection, getParseContext() ); + OUString sErrorMessage; + if ( !aPredicateInput.normalizePredicateString( aNewText, m_xField, &sErrorMessage ) ) + { + // display the error and outta here + SQLContext aError; + aError.Message = ResourceManager::loadString(RID_STR_SYNTAXERROR); + aError.Details = sErrorMessage; + displayException( aError ); + return false; + } + } + + setText(aNewText); + TextEvent aEvt; + aEvt.Source = *this; + ::comphelper::OInterfaceIteratorHelper3 aIt(m_aTextListeners); + while( aIt.hasMoreElements() ) + aIt.next()->textChanged(aEvt); +#endif + return true; + } + + // XTextComponent + + void SAL_CALL OFilterControl::addTextListener(const Reference< XTextListener > & l) + { + m_aTextListeners.addInterface( l ); + } + + + void SAL_CALL OFilterControl::removeTextListener(const Reference< XTextListener > & l) + { + m_aTextListeners.removeInterface( l ); + } + + + void SAL_CALL OFilterControl::setText( const OUString& aText ) + { + if ( !ensureInitialized( ) ) + // already asserted in ensureInitialized + return; + + switch (m_nControlClass) + { + case FormComponentType::CHECKBOX: + { + Reference< XVclWindowPeer > xVclWindow( getPeer(), UNO_QUERY ); + if (xVclWindow.is()) + { + Any aValue; + if ( aText == "1" + || aText.equalsIgnoreAsciiCase("TRUE") + || aText.equalsIgnoreAsciiCase("IS TRUE") + ) + { + aValue <<= sal_Int32(TRISTATE_TRUE); + } + else if ( aText == "0" || aText.equalsIgnoreAsciiCase("FALSE") ) + { + aValue <<= sal_Int32(TRISTATE_FALSE); + } + else + aValue <<= sal_Int32(TRISTATE_INDET); + + m_aText = aText; + xVclWindow->setProperty( PROPERTY_STATE, aValue ); + } + } break; + case FormComponentType::RADIOBUTTON: + { + Reference< XVclWindowPeer > xVclWindow( getPeer(), UNO_QUERY ); + if (xVclWindow.is()) + { + OUString aRefText = ::comphelper::getString(css::uno::Reference< XPropertySet > (getModel(), UNO_QUERY_THROW)->getPropertyValue(PROPERTY_REFVALUE)); + Any aValue; + if (aText == aRefText) + aValue <<= sal_Int32(TRISTATE_TRUE); + else + aValue <<= sal_Int32(TRISTATE_FALSE); + m_aText = aText; + xVclWindow->setProperty(PROPERTY_STATE, aValue); + } + } break; + case FormComponentType::LISTBOX: + { + Reference< XListBox > xListBox( getPeer(), UNO_QUERY ); + if (xListBox.is()) + { + m_aText = aText; + MapString2String::const_iterator itemPos = m_aDisplayItemToValueItem.find( m_aText ); + if ( itemPos == m_aDisplayItemToValueItem.end() ) + { + const bool isQuoted = ( m_aText.getLength() > 1 ) + && ( m_aText[0] == '\'' ) + && ( m_aText[ m_aText.getLength() - 1 ] == '\'' ); + if ( isQuoted ) + { + m_aText = m_aText.copy( 1, m_aText.getLength() - 2 ); + itemPos = m_aDisplayItemToValueItem.find( m_aText ); + } + } + + OSL_ENSURE( ( itemPos != m_aDisplayItemToValueItem.end() ) || m_aText.isEmpty(), + "OFilterControl::setText: this text is not in my display list!" ); + if ( itemPos == m_aDisplayItemToValueItem.end() ) + m_aText.clear(); + + if ( m_aText.isEmpty() ) + { + while ( xListBox->getSelectedItemPos() >= 0 ) + { + xListBox->selectItemPos( xListBox->getSelectedItemPos(), false ); + } + } + else + { + xListBox->selectItem( m_aText, true ); + } + } + } + break; + + default: + { + Reference< XTextComponent > xText( getPeer(), UNO_QUERY ); + if (xText.is()) + { + m_aText = aText; + xText->setText(aText); + } + } + } + } + + + void SAL_CALL OFilterControl::insertText( const css::awt::Selection& rSel, const OUString& aText ) + { + Reference< XTextComponent > xText( getPeer(), UNO_QUERY ); + if (xText.is()) + { + xText->insertText(rSel, aText); + m_aText = xText->getText(); + } + } + + + OUString SAL_CALL OFilterControl::getText() + { + return m_aText; + } + + + OUString SAL_CALL OFilterControl::getSelectedText() + { + OUString aSelected; + Reference< XTextComponent > xText( getPeer(), UNO_QUERY ); + if (xText.is()) + aSelected = xText->getSelectedText(); + + return aSelected; + } + + + void SAL_CALL OFilterControl::setSelection( const css::awt::Selection& aSelection ) + { + Reference< XTextComponent > xText( getPeer(), UNO_QUERY ); + if (xText.is()) + xText->setSelection( aSelection ); + } + + + css::awt::Selection SAL_CALL OFilterControl::getSelection() + { + css::awt::Selection aSel; + Reference< XTextComponent > xText( getPeer(), UNO_QUERY ); + if (xText.is()) + aSel = xText->getSelection(); + return aSel; + } + + + sal_Bool SAL_CALL OFilterControl::isEditable() + { + Reference< XTextComponent > xText( getPeer(), UNO_QUERY ); + return xText.is() && xText->isEditable(); + } + + + void SAL_CALL OFilterControl::setEditable( sal_Bool bEditable ) + { + Reference< XTextComponent > xText( getPeer(), UNO_QUERY ); + if (xText.is()) + xText->setEditable(bEditable); + } + + + sal_Int16 SAL_CALL OFilterControl::getMaxTextLen() + { + Reference< XTextComponent > xText( getPeer(), UNO_QUERY ); + return xText.is() ? xText->getMaxTextLen() : 0; + } + + + void SAL_CALL OFilterControl::setMaxTextLen( sal_Int16 nLength ) + { + Reference< XTextComponent > xText( getPeer(), UNO_QUERY ); + if (xText.is()) + xText->setMaxTextLen(nLength); + } + + + void OFilterControl::displayException( const css::sdb::SQLContext& _rExcept ) + { + try + { + Reference< XExecutableDialog > xErrorDialog = ErrorMessageDialog::create( m_xContext, "", m_xMessageParent, Any(_rExcept)); + xErrorDialog->execute(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("forms.component"); + } + } + + + void SAL_CALL OFilterControl::initialize( const Sequence< Any >& aArguments ) + { + const Any* pArguments = aArguments.getConstArray(); + const Any* pArgumentsEnd = pArguments + aArguments.getLength(); + + PropertyValue aProp; + NamedValue aValue; + const OUString* pName = nullptr; + const Any* pValue = nullptr; + Reference< XPropertySet > xControlModel; + + if (aArguments.getLength() == 3 + && (aArguments[0] >>= m_xMessageParent) + && (aArguments[1] >>= m_xFormatter) + && (aArguments[2] >>= xControlModel)) + { + initControlModel(xControlModel); + } + else for ( ; pArguments != pArgumentsEnd; ++pArguments ) + { + // we recognize PropertyValues and NamedValues + if ( *pArguments >>= aProp ) + { + pName = &aProp.Name; + pValue = &aProp.Value; + } + else if ( *pArguments >>= aValue ) + { + pName = &aValue.Name; + pValue = &aValue.Value; + } + else + { + OSL_FAIL( "OFilterControl::initialize: unrecognized argument!" ); + continue; + } + + if ( *pName == "MessageParent" ) + { + // the message parent + *pValue >>= m_xMessageParent; + OSL_ENSURE( m_xMessageParent.is(), "OFilterControl::initialize: invalid MessageParent!" ); + } + else if ( *pName == "NumberFormatter" ) + { + // the number format. This argument is optional. + *pValue >>= m_xFormatter; + OSL_ENSURE( m_xFormatter.is(), "OFilterControl::initialize: invalid NumberFormatter!" ); + } + else if ( *pName == "ControlModel" ) + { + // the control model for which we act as filter control + if ( !(*pValue >>= xControlModel ) ) + { + OSL_FAIL( "OFilterControl::initialize: invalid control model argument!" ); + continue; + } + initControlModel(xControlModel); + } + } + } + + void OFilterControl::initControlModel(Reference< XPropertySet > const & xControlModel) + { +#if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS + (void) xControlModel; +#else + if ( !xControlModel.is() ) + { + OSL_FAIL( "OFilterControl::initialize: invalid control model argument!" ); + return; + } + // some properties which are "derived" from the control model we're working for + + // the field + m_xField.clear(); + OSL_ENSURE( ::comphelper::hasProperty( PROPERTY_BOUNDFIELD, xControlModel ), "OFilterControl::initialize: control model needs a bound field property!" ); + xControlModel->getPropertyValue( PROPERTY_BOUNDFIELD ) >>= m_xField; + + + // filter list and control class + m_bFilterList = ::comphelper::hasProperty( PROPERTY_FILTERPROPOSAL, xControlModel ) && ::comphelper::getBOOL( xControlModel->getPropertyValue( PROPERTY_FILTERPROPOSAL ) ); + if ( m_bFilterList ) + m_nControlClass = FormComponentType::COMBOBOX; + else + { + sal_Int16 nClassId = ::comphelper::getINT16( xControlModel->getPropertyValue( PROPERTY_CLASSID ) ); + switch (nClassId) + { + case FormComponentType::CHECKBOX: + case FormComponentType::RADIOBUTTON: + case FormComponentType::LISTBOX: + case FormComponentType::COMBOBOX: + m_nControlClass = nClassId; + if ( FormComponentType::LISTBOX == nClassId ) + { + Sequence< OUString > aDisplayItems; + OSL_VERIFY( xControlModel->getPropertyValue( PROPERTY_STRINGITEMLIST ) >>= aDisplayItems ); + Sequence< OUString > aValueItems; + OSL_VERIFY( xControlModel->getPropertyValue( PROPERTY_VALUE_SEQ ) >>= aValueItems ); + OSL_ENSURE( aDisplayItems.getLength() == aValueItems.getLength(), "OFilterControl::initialize: inconsistent item lists!" ); + for ( sal_Int32 i=0; i < ::std::min( aDisplayItems.getLength(), aValueItems.getLength() ); ++i ) + m_aDisplayItemToValueItem[ aDisplayItems[i] ] = aValueItems[i]; + } + break; + default: + m_bMultiLine = ::comphelper::hasProperty( PROPERTY_MULTILINE, xControlModel ) && ::comphelper::getBOOL( xControlModel->getPropertyValue( PROPERTY_MULTILINE ) ); + m_nControlClass = FormComponentType::TEXTFIELD; + break; + } + } + + + // the connection meta data for the form which we're working for + Reference< XChild > xModel( xControlModel, UNO_QUERY ); + Reference< XRowSet > xForm; + if ( xModel.is() ) + xForm.set(xModel->getParent(), css::uno::UNO_QUERY); + m_xConnection = ::dbtools::getConnection( xForm ); + OSL_ENSURE( m_xConnection.is(), "OFilterControl::initialize: unable to determine the form's connection!" ); +#endif + } + + OUString SAL_CALL OFilterControl::getImplementationName( ) + { + return "com.sun.star.comp.forms.OFilterControl"; + } + + sal_Bool SAL_CALL OFilterControl::supportsService( const OUString& ServiceName ) + { + return cppu::supportsService(this, ServiceName); + } + + Sequence< OUString > SAL_CALL OFilterControl::getSupportedServiceNames( ) + { + return { "com.sun.star.form.control.FilterControl", + "com.sun.star.awt.UnoControl" }; + } +} // namespace frm + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_forms_OFilterControl_get_implementation(css::uno::XComponentContext* context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new frm::OFilterControl(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |