/******************************************************************************* * Copyright (c) 2010-2012, Abel Hegedus, Istvan Rath and Daniel Varro * 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: * Abel Hegedus - initial API and implementation *******************************************************************************/ package org.eclipse.incquery.databinding.runtime.api; import java.util.ArrayList; import java.util.List; import org.eclipse.core.databinding.observable.list.IObservableList; import org.eclipse.core.databinding.observable.set.IObservableSet; import org.eclipse.core.databinding.observable.value.IObservableValue; import org.eclipse.core.databinding.observable.value.IValueChangeListener; import org.eclipse.emf.common.notify.Notifier; import org.eclipse.emf.databinding.EMFProperties; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.incquery.databinding.runtime.adapter.DatabindingAdapterUtil; import org.eclipse.incquery.databinding.runtime.collection.ObservablePatternMatchList; import org.eclipse.incquery.databinding.runtime.collection.ObservablePatternMatchSet; import org.eclipse.incquery.runtime.api.IMatcherFactory; import org.eclipse.incquery.runtime.api.IPatternMatch; import org.eclipse.incquery.runtime.api.IncQueryMatcher; /** * Utility class for observing EMF-IncQuery related objects, such as match sets, match parameters. * * @author Abel Hegedus * */ public class IncQueryObservables { /** * Hidden constructor for utility class */ private IncQueryObservables() { } /** * Create an observable list of the match set of the given query on the selected notifier. * * <p> * The matches are ordered by appearance, so a new match is always put on the end of the list. * * <p> * Use the generated matcher factories for initialization, in the generic case, you may have to accept an unchecked * invocation (or use the Generic classes if you are sure). * * @param factory * the matcher factory for the query to observe * @param notifier * the notifier to use for the matcher * @return an observable list of matches */ public static <Match extends IPatternMatch, Matcher extends IncQueryMatcher<Match>> IObservableList observeMatchesAsList( IMatcherFactory<Matcher> factory, Notifier notifier) { return new ObservablePatternMatchList<Match>(factory, notifier); } /** * Create an observable set of the match set of the given query on the selected notifier. * * <p> * Use the generated matcher factories for initialization, in the generic case, you may have to accept an unchecked * invocation (or use the Generic classes if you are sure). * * @param factory * the matcher factory for the query to observe * @param notifier * the notifier to use for the matcher * @return an observable set of matches */ public static <Match extends IPatternMatch, Matcher extends IncQueryMatcher<Match>> IObservableSet observeMatchesAsSet( IMatcherFactory<Matcher> factory, Notifier notifier) { return new ObservablePatternMatchSet<Match>(factory, notifier); } /** * Registers the given changeListener for the appropriate features of the given signature. The features will be * computed based on the message parameter. * * @param signature * the signature instance * @param changeListener * the changle listener * @param message * the message which can be found in the appropriate PatternUI annotation * @return the list of IObservableValue instances for which the IValueChangeListener was registered */ public static List<IObservableValue> observeFeatures(IPatternMatch match, IValueChangeListener changeListener, String message) { List<IObservableValue> affectedValues = new ArrayList<IObservableValue>(); if (message != null) { String[] tokens = message.split("\\$"); for (int i = 0; i < tokens.length; i++) { // odd tokens if (i % 2 != 0) { IObservableValue value = IncQueryObservables.getObservableValue(match, tokens[i]); if (value != null) { value.addValueChangeListener(changeListener); affectedValues.add(value); } } } } return affectedValues; } /** * Registers the given change listener on the given object's all accessible fields. This function uses Java * Reflection. * * @param changeListener * the changle listener * @param object * the observed object * @return the list of IObservableValue instances for which the IValueChangeListener was registered */ public static List<IObservableValue> observeAllAttributes(IValueChangeListener changeListener, Object object) { List<IObservableValue> affectedValues = new ArrayList<IObservableValue>(); if (object instanceof EObject) { for (EStructuralFeature feature : ((EObject) object).eClass().getEAllStructuralFeatures()) { IObservableValue val = EMFProperties.value(feature).observe(object); affectedValues.add(val); val.addValueChangeListener(changeListener); } } return affectedValues; } /** * Returns an IObservableValue for the given match based on the given expression. If an attribute is not present in * the expression than it tries with the 'name' attribute. If it is not present the returned value will be null. * * @param match * the match object * @param expression * the expression * @return IObservableValue instance or null */ public static IObservableValue getObservableValue(IPatternMatch match, String expression) { IObservableValue val = null; String[] objectTokens = expression.split("\\."); if (objectTokens.length > 0) { Object o = null; EStructuralFeature feature = null; if (objectTokens.length == 2) { o = match.get(objectTokens[0]); feature = DatabindingAdapterUtil.getFeature(o, objectTokens[1]); } if (objectTokens.length == 1) { o = match.get(objectTokens[0]); feature = DatabindingAdapterUtil.getFeature(o, "name"); } if (o != null && feature != null) { val = EMFProperties.value(feature).observe(o); } } return val; } }