Kaydet (Commit) 2b1d6f0d authored tarafından Lionel Elie Mamane's avatar Lionel Elie Mamane

tdf#96370 rework filtering to be aware of WHERE vs HAVING clause

Several bugs (AFAIK not filed into tdf bugzilla) fixed.

Remaining problems:

When some filter clauses go into WHERE and others in HAVING,
they are always logically ANDed (it cannot be any other way),
but that is not communicated to the user in the UI.

Some things left undone:

* DatabaseDataProvider (and its users?) needs to be updated
  to be HAVING-aware, too.

* Form-based filter (.uno:FormFilter) not HAVING-aware
  it reads the current filter in function
  svxform::FormController::setFilter
  in
  svx/source/form/formcontrollers.cxx
  That's one place that needs to be updated.
  The other place is the one that applies the filter.

Change-Id: I0e9d30a1927b6739a16ae7627e8d0dae8823b376
üst aba73077
......@@ -52,6 +52,7 @@ namespace dbtools
using namespace ::com::sun::star::uno;
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::lang;
......@@ -1007,6 +1008,40 @@ OUString getDefaultReportEngineServiceName(const Reference< XComponentContext >&
return OUString();
}
bool isAggregateColumn(const Reference< XSingleSelectQueryComposer > &_xParser, const Reference< XPropertySet > &_xField, bool whenNotFound)
{
OUString sName;
_xField->getPropertyValue("Name") >>= sName;
Reference< XColumnsSupplier > xColumnsSupplier(_xParser, UNO_QUERY);
Reference< css::container::XNameAccess > xCols;
if (xColumnsSupplier.is())
xCols = xColumnsSupplier->getColumns();
return isAggregateColumn(xCols, sName, whenNotFound);
}
bool isAggregateColumn(const Reference< XNameAccess > &_xColumns, const OUString &_sName, bool whenNotFound)
{
if ( _xColumns.is() && _xColumns->hasByName(_sName) )
{
Reference<XPropertySet> xProp(_xColumns->getByName(_sName),UNO_QUERY);
assert(xProp.is());
return isAggregateColumn( xProp );
}
return whenNotFound;
}
bool isAggregateColumn( const Reference< XPropertySet > &_xColumn )
{
bool bAgg(false);
static const char sAgg[] = "AggregateFunction";
if ( _xColumn->getPropertySetInfo()->hasPropertyByName(sAgg) )
_xColumn->getPropertyValue(sAgg) >>= bAgg;
return bAgg;
}
} // namespace dbtools
......
......@@ -62,20 +62,64 @@ namespace dbtools
const OUString& FilterManager::getFilterComponent( FilterComponent _eWhich ) const
{
return _eWhich == FilterComponent::PublicFilter ? m_aPublicFilterComponent : m_aLinkFilterComponent;
switch (_eWhich)
{
case FilterComponent::PublicFilter:
return m_aPublicFilterComponent;
case FilterComponent::PublicHaving:
return m_aPublicHavingComponent;
case FilterComponent::LinkFilter:
return m_aLinkFilterComponent;
case FilterComponent::LinkHaving:
return m_aLinkHavingComponent;
}
assert(false);
static OUString sErr("#FilterManager::getFilterComponent unknown component#");
return sErr;
}
void FilterManager::setFilterComponent( FilterComponent _eWhich, const OUString& _rComponent )
{
if (_eWhich == FilterComponent::PublicFilter)
switch (_eWhich)
{
case FilterComponent::PublicFilter:
m_aPublicFilterComponent = _rComponent;
else
break;
case FilterComponent::PublicHaving:
m_aPublicHavingComponent = _rComponent;
break;
case FilterComponent::LinkFilter:
m_aLinkFilterComponent = _rComponent;
break;
case FilterComponent::LinkHaving:
m_aLinkHavingComponent = _rComponent;
break;
}
try
{
if ( m_xComponentAggregate.is() && (( _eWhich != FilterComponent::PublicFilter ) || m_bApplyPublicFilter ) )
m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FILTER), makeAny( getComposedFilter() ) );
if ( m_xComponentAggregate.is() )
{
bool propagate(true);
switch (_eWhich)
{
case FilterComponent::PublicFilter:
propagate = propagate && m_bApplyPublicFilter;
SAL_FALLTHROUGH;
case FilterComponent::LinkFilter:
if (propagate)
m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FILTER), makeAny( getComposedFilter() ) );
break;
case FilterComponent::PublicHaving:
propagate = propagate && m_bApplyPublicFilter;
SAL_FALLTHROUGH;
case FilterComponent::LinkHaving:
if (propagate)
m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_HAVINGCLAUSE), makeAny( getComposedHaving() ) );
break;
}
}
}
catch( const Exception& )
{
......@@ -93,9 +137,13 @@ namespace dbtools
try
{
if ( m_xComponentAggregate.is() && !getFilterComponent( FilterComponent::PublicFilter ).isEmpty() )
{ // only if there changed something
m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FILTER), makeAny( getComposedFilter() ) );
if ( m_xComponentAggregate.is())
{
// only where/if something changed
if (!getFilterComponent( FilterComponent::PublicFilter ).isEmpty())
m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FILTER), makeAny( getComposedFilter() ) );
if (!getFilterComponent( FilterComponent::PublicHaving ).isEmpty())
m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_HAVINGCLAUSE), makeAny( getComposedHaving() ) );
}
}
catch( const Exception& )
......@@ -120,7 +168,7 @@ namespace dbtools
}
bool FilterManager::isThereAtMostOneComponent( OUString& o_singleComponent ) const
bool FilterManager::isThereAtMostOneFilterComponent( OUString& o_singleComponent ) const
{
if (m_bApplyPublicFilter) {
if (!m_aPublicFilterComponent.isEmpty() && !m_aLinkFilterComponent.isEmpty())
......@@ -143,12 +191,35 @@ namespace dbtools
}
}
bool FilterManager::isThereAtMostOneHavingComponent( OUString& o_singleComponent ) const
{
if (m_bApplyPublicFilter) {
if (!m_aPublicHavingComponent.isEmpty() && !m_aLinkHavingComponent.isEmpty())
return false;
if (!m_aPublicHavingComponent.isEmpty())
o_singleComponent = m_aPublicHavingComponent;
else if (!m_aLinkHavingComponent.isEmpty())
o_singleComponent = m_aLinkHavingComponent;
else
o_singleComponent.clear();
return true;
}
else
{
if (m_aLinkHavingComponent.isEmpty())
o_singleComponent.clear();
else
o_singleComponent = m_aLinkHavingComponent;
return true;
}
}
OUString FilterManager::getComposedFilter( ) const
{
// if we have only one non-empty component, then there's no need to compose anything
OUString singleComponent;
if ( isThereAtMostOneComponent( singleComponent ) )
if ( isThereAtMostOneFilterComponent( singleComponent ) )
{
return singleComponent;
}
......@@ -161,6 +232,23 @@ namespace dbtools
}
OUString FilterManager::getComposedHaving( ) const
{
// if we have only one non-empty component, then there's no need to compose anything
OUString singleComponent;
if ( isThereAtMostOneHavingComponent( singleComponent ) )
{
return singleComponent;
}
// append the single components
OUStringBuffer aComposedFilter(singleComponent);
if (m_bApplyPublicFilter)
appendFilterComponent( aComposedFilter, m_aPublicHavingComponent );
appendFilterComponent( aComposedFilter, m_aLinkHavingComponent );
return aComposedFilter.makeStringAndClear();
}
} // namespace dbtools
......
......@@ -245,7 +245,9 @@ namespace dbtools
void ParameterManager::classifyLinks( const Reference< XNameAccess >& _rxParentColumns,
const Reference< XNameAccess >& _rxColumns, std::vector< OUString >& _out_rAdditionalFilterComponents )
const Reference< XNameAccess >& _rxColumns,
std::vector< OUString >& _out_rAdditionalFilterComponents,
std::vector< OUString >& _out_rAdditionalHavingComponents )
{
OSL_PRECOND( m_aMasterFields.size() == m_aDetailFields.size(),
"ParameterManager::classifyLinks: master and detail fields should have the same length!" );
......@@ -309,7 +311,10 @@ namespace dbtools
aInsertionPos.first->second.eType = ParameterClassification::LinkedByColumnName;
// remember the filter component
_out_rAdditionalFilterComponents.push_back( sFilterCondition );
if (isAggregateColumn(xDetailField))
_out_rAdditionalHavingComponents.push_back( sFilterCondition );
else
_out_rAdditionalFilterComponents.push_back( sFilterCondition );
// remember the new "detail field" for this link
aStrippedDetailFields.push_back( sNewParamName );
......@@ -381,7 +386,8 @@ namespace dbtools
// classify the links - depending on what the detail fields in each link pair denotes
std::vector< OUString > aAdditionalFilterComponents;
classifyLinks( xParentColumns, xColumns, aAdditionalFilterComponents );
std::vector< OUString > aAdditionalHavingComponents;
classifyLinks( xParentColumns, xColumns, aAdditionalFilterComponents, aAdditionalHavingComponents );
// did we find links where the detail field refers to a detail column (instead of a parameter name)?
if ( !aAdditionalFilterComponents.empty() )
......@@ -401,11 +407,34 @@ namespace dbtools
sAdditionalFilter.append(" )");
}
// now set this filter at the 's filter manager
// now set this filter at the filter manager
_rFilterManager.setFilterComponent( FilterManager::FilterComponent::LinkFilter, sAdditionalFilter.makeStringAndClear() );
_rColumnsInLinkDetails = true;
}
if ( !aAdditionalHavingComponents.empty() )
{
// build a conjunction of all the filter components
OUStringBuffer sAdditionalHaving;
for ( std::vector< OUString >::const_iterator aComponent = aAdditionalHavingComponents.begin();
aComponent != aAdditionalHavingComponents.end();
++aComponent
)
{
if ( !sAdditionalHaving.isEmpty() )
sAdditionalHaving.append(" AND ");
sAdditionalHaving.append("( ");
sAdditionalHaving.append(*aComponent);
sAdditionalHaving.append(" )");
}
// now set this having clause at the filter manager
_rFilterManager.setFilterComponent( FilterManager::FilterComponent::LinkHaving, sAdditionalHaving.makeStringAndClear() );
_rColumnsInLinkDetails = true;
}
}
catch( const Exception& )
{
......
......@@ -47,6 +47,8 @@
#include <vector>
#include <list>
// TODO: update for new HavingClause-aware FilterManager
namespace dbaccess
{
using namespace ::com::sun::star;
......
......@@ -2006,18 +2006,7 @@ void SbaXDataBrowserController::Execute(sal_uInt16 nId, const Sequence< Property
break;
// check if the column is a aggregate function
bool bHaving = false;
OUString sName;
xField->getPropertyValue(PROPERTY_NAME) >>= sName;
Reference< XColumnsSupplier > xColumnsSupplier(m_xParser, UNO_QUERY);
Reference< css::container::XNameAccess > xCols = xColumnsSupplier.is() ? xColumnsSupplier->getColumns() : Reference< css::container::XNameAccess > ();
if ( xCols.is() && xCols->hasByName(sName) )
{
Reference<XPropertySet> xProp(xCols->getByName(sName),UNO_QUERY);
static const char sAgg[] = "AggregateFunction";
if ( xProp->getPropertySetInfo()->hasPropertyByName(sAgg) )
xProp->getPropertyValue(sAgg) >>= bHaving;
}
const bool bHaving(isAggregateColumn(m_xParser, xField));
Reference< XSingleSelectQueryComposer > xParser = createParser_nothrow();
const OUString sOldFilter = xParser->getFilter();
......@@ -2029,7 +2018,8 @@ void SbaXDataBrowserController::Execute(sal_uInt16 nId, const Sequence< Property
// -> completely overwrite it, else append one
if (!bApplied)
{
DO_SAFE( (bHaving ? xParser->setHavingClause(OUString()) : xParser->setFilter(::OUString())), "SbaXDataBrowserController::Execute : caught an exception while resetting the new filter !" );
DO_SAFE( xParser->setFilter( OUString()), "SbaXDataBrowserController::Execute : caught an exception while resetting unapplied filter !" );
DO_SAFE( xParser->setHavingClause(OUString()), "SbaXDataBrowserController::Execute : caught an exception while resetting unapplied HAVING clause !" );
}
bool bParserSuccess = false;
......
......@@ -169,9 +169,10 @@ DlgFilterCrit::DlgFilterCrit(vcl::Window * pParent,
// insert the criteria into the dialog
Sequence<Sequence<PropertyValue > > aValues = m_xQueryComposer->getStructuredFilter();
fillLines(aValues);
int i(0);
fillLines(i, aValues);
aValues = m_xQueryComposer->getStructuredHavingClause();
fillLines(aValues);
fillLines(i, aValues);
EnableLines();
......@@ -467,7 +468,7 @@ IMPL_LINK( DlgFilterCrit, PredicateLoseFocus, Control&, rControl, void )
}
}
void DlgFilterCrit::SetLine( sal_uInt16 nIdx,const PropertyValue& _rItem,bool _bOr )
void DlgFilterCrit::SetLine( int nIdx, const PropertyValue& _rItem, bool _bOr )
{
OUString aStr;
_rItem.Value >>= aStr;
......@@ -785,13 +786,13 @@ void DlgFilterCrit::BuildWherePart()
}
}
void DlgFilterCrit::fillLines(const Sequence<Sequence<PropertyValue > >& _aValues)
void DlgFilterCrit::fillLines(int &i, const Sequence< Sequence< PropertyValue > >& _aValues)
{
const Sequence<PropertyValue >* pOrIter = _aValues.getConstArray();
const Sequence<PropertyValue >* pOrEnd = pOrIter + _aValues.getLength();
for(sal_uInt16 i=0;pOrIter != pOrEnd; ++pOrIter)
bool bOr(i != 0); // WHERE clause and HAVING clause are always ANDed, nor ORed
for(; pOrIter != pOrEnd; ++pOrIter)
{
bool bOr = true;
const PropertyValue* pAndIter = pOrIter->getConstArray();
const PropertyValue* pAndEnd = pAndIter + pOrIter->getLength();
for(;pAndIter != pAndEnd; ++pAndIter)
......@@ -799,6 +800,7 @@ void DlgFilterCrit::fillLines(const Sequence<Sequence<PropertyValue > >& _aValue
SetLine( i++,*pAndIter,bOr);
bOr = false;
}
bOr=true;
}
}
......
......@@ -94,12 +94,12 @@ namespace dbaui
DECL_LINK( ListSelectHdl, ListBox&, void );
DECL_LINK( ListSelectCompHdl, ListBox&, void );
void SetLine( sal_uInt16 nIdx,const css::beans::PropertyValue& _rItem,bool _bOr );
void SetLine( int nIdx, const css::beans::PropertyValue& _rItem, bool _bOr );
void EnableLines();
sal_Int32 GetOSQLPredicateType( const OUString& _rSelectedPredicate ) const;
static sal_Int32 GetSelectionPos(sal_Int32 eType,const ListBox& rListBox);
bool getCondition(const ListBox& _rField,const ListBox& _rComp,const Edit& _rValue,css::beans::PropertyValue& _rFilter) const;
void fillLines(const css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > >& _aValues);
void fillLines(int &i, const css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > >& _aValues);
css::uno::Reference< css::beans::XPropertySet > getMatchingColumn( const Edit& _rValueInput ) const;
css::uno::Reference< css::beans::XPropertySet > getColumn( const OUString& _rFieldName ) const;
......
......@@ -1288,7 +1288,7 @@ void ODatabaseForm::describeFixedAndAggregateProperties(
Sequence< Property >& _rProps,
Sequence< Property >& _rAggregateProps ) const
{
_rProps.realloc( 22 );
_rProps.realloc( 23 );
css::beans::Property* pProperties = _rProps.getArray();
if (m_xAggregateSet.is())
......@@ -1312,6 +1312,7 @@ void ODatabaseForm::describeFixedAndAggregateProperties(
// (e.g. the ones which result from linking master fields to detail fields
// via column names instead of parameters)
RemoveProperty( _rAggregateProps, PROPERTY_FILTER );
RemoveProperty( _rAggregateProps, PROPERTY_HAVINGCLAUSE );
RemoveProperty( _rAggregateProps, PROPERTY_APPLYFILTER );
DECL_IFACE_PROP4( ACTIVE_CONNECTION,XConnection, BOUND, TRANSIENT, MAYBEVOID, CONSTRAINED);
......@@ -1322,6 +1323,7 @@ void ODatabaseForm::describeFixedAndAggregateProperties(
DECL_PROP2 ( DATASOURCE, OUString, BOUND, CONSTRAINED );
DECL_PROP3 ( CYCLE, TabulatorCycle, BOUND, MAYBEVOID, MAYBEDEFAULT );
DECL_PROP2 ( FILTER, OUString, BOUND, MAYBEDEFAULT );
DECL_PROP2 ( HAVINGCLAUSE, OUString, BOUND, MAYBEDEFAULT );
DECL_BOOL_PROP2 ( INSERTONLY, BOUND, MAYBEDEFAULT );
DECL_PROP1 ( NAVIGATION, NavigationBarMode, BOUND );
DECL_BOOL_PROP1 ( ALLOWADDITIONS, BOUND );
......@@ -1464,6 +1466,10 @@ void ODatabaseForm::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
rValue <<= m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicFilter );
break;
case PROPERTY_ID_HAVINGCLAUSE:
rValue <<= m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicHaving );
break;
case PROPERTY_ID_APPLYFILTER:
rValue <<= m_aFilterManager.isApplyPublicFilter();
break;
......@@ -1546,6 +1552,10 @@ sal_Bool ODatabaseForm::convertFastPropertyValue( Any& rConvertedValue, Any& rOl
bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicFilter ) );
break;
case PROPERTY_ID_HAVINGCLAUSE:
bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicHaving ) );
break;
case PROPERTY_ID_APPLYFILTER:
bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aFilterManager.isApplyPublicFilter() );
break;
......@@ -1635,6 +1645,14 @@ void ODatabaseForm::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const A
}
break;
case PROPERTY_ID_HAVINGCLAUSE:
{
OUString sNewFilter;
rValue >>= sNewFilter;
m_aFilterManager.setFilterComponent( FilterManager::FilterComponent::PublicHaving, sNewFilter );
}
break;
case PROPERTY_ID_APPLYFILTER:
{
bool bApply = true;
......@@ -1780,6 +1798,13 @@ PropertyState ODatabaseForm::getPropertyStateByHandle(sal_Int32 nHandle)
eState = PropertyState_DIRECT_VALUE;
break;
case PROPERTY_ID_HAVINGCLAUSE:
if ( m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicHaving ).isEmpty() )
eState = PropertyState_DEFAULT_VALUE;
else
eState = PropertyState_DIRECT_VALUE;
break;
case PROPERTY_ID_APPLYFILTER:
eState = m_aFilterManager.isApplyPublicFilter() ? PropertyState_DEFAULT_VALUE : PropertyState_DIRECT_VALUE;
break;
......@@ -1813,6 +1838,7 @@ void ODatabaseForm::setPropertyToDefaultByHandle(sal_Int32 nHandle)
{
case PROPERTY_ID_INSERTONLY:
case PROPERTY_ID_FILTER:
case PROPERTY_ID_HAVINGCLAUSE:
case PROPERTY_ID_APPLYFILTER:
case PROPERTY_ID_NAVIGATION:
case PROPERTY_ID_CYCLE:
......@@ -1843,6 +1869,10 @@ Any ODatabaseForm::getPropertyDefaultByHandle( sal_Int32 nHandle ) const
aReturn <<= OUString();
break;
case PROPERTY_ID_HAVINGCLAUSE:
aReturn <<= OUString();
break;
case PROPERTY_ID_APPLYFILTER:
aReturn <<= true;
break;
......@@ -3741,7 +3771,7 @@ void SAL_CALL ODatabaseForm::write(const Reference<XObjectOutputStream>& _rxOutS
OFormComponents::write(_rxOutStream);
// version
_rxOutStream->writeShort(0x0003);
_rxOutStream->writeShort(0x0004);
// Name
_rxOutStream << m_sName;
......@@ -3819,10 +3849,13 @@ void SAL_CALL ODatabaseForm::write(const Reference<XObjectOutputStream>& _rxOutS
_rxOutStream->writeShort((sal_Int16)m_eNavigation);
OUString sFilter;
OUString sHaving;
OUString sOrder;
if (m_xAggregateSet.is())
{
m_xAggregateSet->getPropertyValue(PROPERTY_FILTER) >>= sFilter;
// version 4
m_xAggregateSet->getPropertyValue(PROPERTY_HAVINGCLAUSE) >>= sHaving;
m_xAggregateSet->getPropertyValue(PROPERTY_SORT) >>= sOrder;
}
_rxOutStream << sFilter;
......@@ -3922,6 +3955,11 @@ void SAL_CALL ODatabaseForm::read(const Reference<XObjectInputStream>& _rxInStre
_rxInStream >> sAggregateProp;
setPropertyValue(PROPERTY_FILTER, makeAny(sAggregateProp));
if(nVersion > 3)
{
_rxInStream >> sAggregateProp;
setPropertyValue(PROPERTY_HAVINGCLAUSE, makeAny(sAggregateProp));
}
_rxInStream >> sAggregateProp;
if (m_xAggregateSet.is())
......
......@@ -53,6 +53,7 @@ namespace frm
#define PROPERTY_RELEVANT "Relevant"
#define PROPERTY_ISREADONLY "IsReadOnly"
#define PROPERTY_FILTER "Filter"
#define PROPERTY_HAVINGCLAUSE "HavingClause"
#define PROPERTY_WIDTH "Width"
#define PROPERTY_SEARCHABLE "IsSearchable"
#define PROPERTY_MULTILINE "MultiLine"
......
......@@ -173,7 +173,7 @@ namespace frm
#define PROPERTY_ID_AUTOINCREMENT (PROPERTY_ID_START +133) // UINT16
// free
#define PROPERTY_ID_FILTER (PROPERTY_ID_START +135) // ::rtl::OUString
// free
#define PROPERTY_ID_HAVINGCLAUSE (PROPERTY_ID_START +136) // ::rtl::OUString
#define PROPERTY_ID_QUERY (PROPERTY_ID_START +137) // ::rtl::OUString
#define PROPERTY_ID_DEFAULT_LONG_VALUE (PROPERTY_ID_START +138) // Double
#define PROPERTY_ID_DEFAULT_DATE (PROPERTY_ID_START +139) // UINT32
......
......@@ -307,8 +307,10 @@ namespace frm
case FormFeature::ToggleApplyFilter:
{
OUString sFilter;
m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sFilter;
if ( !sFilter.isEmpty() )
OUString sHaving;
m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sFilter;
m_xCursorProperties->getPropertyValue( PROPERTY_HAVINGCLAUSE ) >>= sHaving;
if ( ! (sFilter.isEmpty() && sHaving.isEmpty()) )
{
aState.State = m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER );
aState.Enabled = !impl_isInsertOnlyForm_throw();
......@@ -718,13 +720,15 @@ namespace frm
OSL_ENSURE( xProperties.is(), "FormOperations::execute: no multi property access!" );
if ( xProperties.is() )
{
Sequence< OUString > aNames( 2 );
Sequence< OUString > aNames( 3 );
aNames[0] = PROPERTY_FILTER;
aNames[1] = PROPERTY_SORT;
aNames[1] = PROPERTY_HAVINGCLAUSE;
aNames[2] = PROPERTY_SORT;
Sequence< Any> aValues( 2 );
Sequence< Any> aValues( 3 );
aValues[0] <<= OUString();
aValues[1] <<= OUString();
aValues[2] <<= OUString();
WaitObject aWO( nullptr );
xProperties->setPropertyValues( aNames, aValues );
......@@ -1034,6 +1038,11 @@ namespace frm
if ( m_xParser->getFilter() != sNewValue )
m_xParser->setFilter( sNewValue );
}
else if ( _rEvent.PropertyName == PROPERTY_HAVINGCLAUSE )
{
if ( m_xParser->getHavingClause() != sNewValue )
m_xParser->setHavingClause( sNewValue );
}
else if ( _rEvent.PropertyName == PROPERTY_SORT )
{
_rEvent.NewValue >>= sNewValue;
......@@ -1221,14 +1230,17 @@ namespace frm
{
OUString sStatement;
OUString sFilter;
OUString sHaving;
OUString sSort;
m_xCursorProperties->getPropertyValue( PROPERTY_ACTIVECOMMAND ) >>= sStatement;
m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sFilter;
m_xCursorProperties->getPropertyValue( PROPERTY_HAVINGCLAUSE ) >>= sHaving;
m_xCursorProperties->getPropertyValue( PROPERTY_SORT ) >>= sSort;
m_xParser->setElementaryQuery( sStatement );
m_xParser->setFilter ( sFilter );
m_xParser->setHavingClause ( sHaving );
m_xParser->setOrder ( sSort );
}
......@@ -1236,6 +1248,7 @@ namespace frm
// we can keep our parser in sync
m_xCursorProperties->addPropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
m_xCursorProperties->addPropertyChangeListener( PROPERTY_FILTER, this );
m_xCursorProperties->addPropertyChangeListener( PROPERTY_HAVINGCLAUSE, this );
m_xCursorProperties->addPropertyChangeListener( PROPERTY_SORT, this );
}
}
......@@ -1257,6 +1270,7 @@ namespace frm
if ( m_xParser.is() && m_xCursorProperties.is() )
{
m_xCursorProperties->removePropertyChangeListener( PROPERTY_FILTER, this );
m_xCursorProperties->removePropertyChangeListener( PROPERTY_HAVINGCLAUSE, this );
m_xCursorProperties->removePropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
m_xCursorProperties->removePropertyChangeListener( PROPERTY_SORT, this );
}
......@@ -1337,7 +1351,9 @@ namespace frm
bool FormOperations::impl_hasFilterOrOrder_throw() const
{
return impl_isParseable_throw() && ( !m_xParser->getFilter().isEmpty() || !m_xParser->getOrder().isEmpty() );
return impl_isParseable_throw() && ( !m_xParser->getFilter().isEmpty() ||
!m_xParser->getHavingClause().isEmpty() ||
!m_xParser->getOrder().isEmpty() );
}
......@@ -1600,21 +1616,27 @@ namespace frm
return;
OUString sOriginalFilter;
m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sOriginalFilter;
OUString sOriginalHaving;
m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sOriginalFilter;
m_xCursorProperties->getPropertyValue( PROPERTY_HAVINGCLAUSE ) >>= sOriginalHaving;
bool bApplied = true;
m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER ) >>= bApplied;
// if we have a filter, but it's not applied, then we have to overwrite it, else append one
if ( !bApplied )
{
m_xParser->setFilter( OUString() );
m_xParser->setHavingClause( OUString() );
}
impl_appendFilterByColumn_throw aAction(this, xBoundField);
impl_appendFilterByColumn_throw aAction(this, m_xParser, xBoundField);
impl_doActionInSQLContext_throw( aAction, RID_STR_COULD_NOT_SET_FILTER );
WaitObject aWO( nullptr );
try
{
m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
m_xCursorProperties->setPropertyValue( PROPERTY_HAVINGCLAUSE, makeAny( m_xParser->getHavingClause() ) );
m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, makeAny( true ) );
m_xLoadableForm->reload();
......@@ -1629,9 +1651,11 @@ namespace frm
{ // something went wrong -> restore the original state
try
{
m_xParser->setOrder( sOriginalFilter );
m_xParser->setFilter ( sOriginalFilter );
m_xParser->setHavingClause( sOriginalHaving );
m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, makeAny( bApplied ) );
m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
m_xCursorProperties->setPropertyValue( PROPERTY_HAVINGCLAUSE, makeAny( m_xParser->getHavingClause() ) );
m_xLoadableForm->reload();
}
catch( const Exception& )
......@@ -1678,7 +1702,10 @@ namespace frm
{
WaitObject aWO( nullptr );
if ( _bFilter )
m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
{
m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
m_xCursorProperties->setPropertyValue( PROPERTY_HAVINGCLAUSE, makeAny( m_xParser->getHavingClause() ) );
}
else
m_xCursorProperties->setPropertyValue( PROPERTY_SORT, makeAny( m_xParser->getOrder() ) );
m_xLoadableForm->reload();
......
......@@ -25,8 +25,10 @@
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/form/XForm.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/form/XLoadable.hpp>
#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
#include <com/sun/star/util/XModifyListener.hpp>
#include <com/sun/star/container/XIndexAccess.hpp>
#include <com/sun/star/lang/XInitialization.hpp>
......@@ -35,7 +37,7 @@
#include <cppuhelper/basemutex.hxx>
#include <cppuhelper/compbase.hxx>
#include <connectivity/dbtools.hxx>
namespace frm
{
......@@ -320,14 +322,22 @@ namespace frm
{
public:
impl_appendFilterByColumn_throw(const FormOperations *pFO,
css::uno::Reference< css::sdb::XSingleSelectQueryComposer > const & xParser,
css::uno::Reference< css::beans::XPropertySet > const & xField)
: m_pFO(pFO)
, m_xParser(xParser)
, m_xField(xField)
{};
void operator()() { m_pFO->m_xParser->appendFilterByColumn( m_xField, true, css::sdb::SQLFilterOperator::EQUAL ); }
void operator()() {
if (dbtools::isAggregateColumn( m_xParser, m_xField ))