/****************************************************************************** * 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 org.eclipse.sapphire.Event; import org.eclipse.sapphire.Listener; import org.eclipse.sapphire.modeling.util.MiscUtil; /** * A function that reads a property from the context or a child element. * * @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a> */ public final class PropertyAccessFunction extends Function { public static PropertyAccessFunction create( final Function element, final Function property ) { final PropertyAccessFunction literal = new PropertyAccessFunction(); literal.init( element, property ); return literal; } public static PropertyAccessFunction create( final Function element, final String property ) { return create( element, Literal.create( property ) ); } public static PropertyAccessFunction create( final Function property ) { final PropertyAccessFunction literal = new PropertyAccessFunction(); literal.init( property ); return literal; } public static PropertyAccessFunction create( final String property ) { return create( Literal.create( property ) ); } @Override public String name() { return "."; } @Override public boolean operator() { return true; } @Override public int precedence() { return 1; } @Override public FunctionResult evaluate( final FunctionContext context ) { return new FunctionResult( this, context ) { private Object lastElement; private String lastPropertyName; private FunctionResult lastPropertyValueResult; private Listener lastPropertyValueListener; @Override protected void init() { super.init(); this.lastPropertyValueListener = new Listener() { @Override public void handle( final Event event ) { refresh(); } }; } @Override protected Object evaluate() { final Object element; final String property; if( operands().size() == 1 ) { element = context; property = cast( operand( 0 ), String.class ); } else { element = operand( 0 ); property = cast( operand( 1 ), String.class ); } if( this.lastPropertyValueResult != null ) { if( this.lastElement != element || ! MiscUtil.equal( this.lastPropertyName, property ) ) { this.lastElement = null; this.lastPropertyName = null; this.lastPropertyValueResult.dispose(); this.lastPropertyValueResult = null; } } if( property != null && this.lastPropertyName == null ) { this.lastElement = element; this.lastPropertyName = property; this.lastPropertyValueResult = context().property( element, property ); this.lastPropertyValueResult.attach( this.lastPropertyValueListener ); } return ( this.lastPropertyValueResult == null ? null : this.lastPropertyValueResult.value() ); } @Override public void dispose() { super.dispose(); if( this.lastPropertyValueResult != null ) { this.lastPropertyValueResult.dispose(); } } }; } @Override public void toString( final StringBuilder buf, final boolean topLevel ) { if( operands().size() == 1 ) { buf.append( (String) ( (Literal) operand( 0 ) ).value() ); } else { operand( 0 ).toString( buf, false ); final Function p = operand( 1 ); if( p instanceof Literal ) { buf.append( '.' ); ( (Literal) p ).toString( buf, false ); } else { buf.append( "[ " ); p.toString( buf, false ); buf.append( " ]" ); } } } }