/******************************************************************************
* Copyright (c) 2016 Oracle
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Konstantin Komissarchik - initial implementation and ongoing maintenance
******************************************************************************/
package org.eclipse.sapphire.modeling.el;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.sapphire.Element;
import org.eclipse.sapphire.ElementList;
import org.eclipse.sapphire.ElementType;
import org.eclipse.sapphire.FilteredListener;
import org.eclipse.sapphire.ListProperty;
import org.eclipse.sapphire.Listener;
import org.eclipse.sapphire.LocalizableText;
import org.eclipse.sapphire.PropertyContentEvent;
import org.eclipse.sapphire.PropertyDef;
import org.eclipse.sapphire.Text;
import org.eclipse.sapphire.ValueProperty;
/**
* @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a>
*/
public abstract class AggregateFunction extends Function
{
@Text( "Property {0}.{1} could not be found." )
private static LocalizableText missingProperty;
@Text( "Property {0}.{1} is not a value property." )
private static LocalizableText notValueProperty;
@Text( "Element type {0} does not contain a value property." )
private static LocalizableText noValueProperties;
static
{
LocalizableText.init( AggregateFunction.class );
}
protected static abstract class AggregateFunctionResult extends FunctionResult
{
private Element lastListParentElement;
private String lastListenerModelPath;
private Listener listener;
public AggregateFunctionResult( final Function function,
final FunctionContext context )
{
super( function, context );
}
@Override
protected final Object evaluate()
{
final Object collection = operand( 0 );
final List<Object> items = new ArrayList<Object>();
if( collection != null )
{
if( collection instanceof ElementList )
{
final ElementList<?> list = (ElementList<?>) collection;
final ListProperty listProperty = list.definition();
final ElementType listEntryType = listProperty.getType();
final ValueProperty listEntryProperty;
if( operands().size() > 1 )
{
final String listEntryPropertyName = cast( operand( 1 ), String.class );
final PropertyDef prop = listEntryType.property( listEntryPropertyName );
if( prop == null )
{
throw new FunctionException( missingProperty.format( listEntryType.getSimpleName(), listEntryPropertyName ) );
}
if( ! ( prop instanceof ValueProperty ) )
{
throw new FunctionException( notValueProperty.format( listEntryType.getSimpleName(), listEntryPropertyName ) );
}
listEntryProperty = (ValueProperty) prop;
}
else
{
ValueProperty prop = null;
for( PropertyDef p : listEntryType.properties() )
{
if( p instanceof ValueProperty )
{
prop = (ValueProperty) p;
break;
}
}
if( prop == null )
{
throw new FunctionException( noValueProperties.format( listEntryType.getSimpleName() ) );
}
listEntryProperty = prop;
}
for( Element item : list )
{
items.add( item.property( listEntryProperty ).content() );
}
final Element listParentElement = list.element();
final String listenerModelPath = listProperty.name() + "/" + listEntryProperty.name();
if( this.lastListParentElement != listParentElement || ! this.lastListenerModelPath.equals( listenerModelPath ) )
{
if( this.lastListParentElement != null )
{
this.lastListParentElement.detach( this.listener, this.lastListenerModelPath );
}
this.lastListParentElement = listParentElement;
this.lastListenerModelPath = listenerModelPath;
if( this.listener == null )
{
this.listener = new FilteredListener<PropertyContentEvent>()
{
@Override
protected void handleTypedEvent( final PropertyContentEvent event )
{
refresh();
}
};
}
listParentElement.attach( this.listener, listenerModelPath );
}
}
else if( collection instanceof Object[] )
{
for( Object item : (Object[]) collection )
{
items.add( item );
}
}
else if( collection instanceof Collection )
{
items.addAll( (Collection<?>) collection );
}
}
return evaluate( items );
}
protected abstract Object evaluate( List<Object> items );
@Override
public void dispose()
{
super.dispose();
if( this.lastListParentElement != null )
{
this.lastListParentElement.detach( this.listener, this.lastListenerModelPath );
}
}
}
}