/* * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * */ package com.sun.javafx.fxml.expression; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javafx.beans.InvalidationListener; import javafx.beans.property.ReadOnlyProperty; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValueBase; import javafx.collections.ListChangeListener; import javafx.collections.MapChangeListener; import javafx.collections.ObservableList; import javafx.collections.ObservableMap; import com.sun.javafx.fxml.BeanAdapter; /** * Class representing an observable expression value. */ public class ExpressionValue extends ObservableValueBase { // Monitors a namespace for changes along a key path private class KeyPathMonitor { private String key; private KeyPathMonitor next; private Object namespace = null; private ListChangeListener listChangeListener = new ListChangeListener() { @Override public void onChanged(Change change) { while (change.next()) { int index = Integer.parseInt(key); if (index >= change.getFrom() && index < change.getTo()) { fireValueChangedEvent(); remonitor(); } } } }; private MapChangeListener mapChangeListener = new MapChangeListener() { @Override public void onChanged(Change change) { if (key.equals(change.getKey())) { fireValueChangedEvent(); remonitor(); } } }; private ChangeListener propertyChangeListener = new ChangeListener() { @Override public void changed(ObservableValue observable, Object oldValue, Object newValue) { fireValueChangedEvent(); remonitor(); } }; public KeyPathMonitor(Iterator keyPathIterator) { this.key = keyPathIterator.next(); if (keyPathIterator.hasNext()) { next = new KeyPathMonitor(keyPathIterator); } else { next = null; } } @SuppressWarnings("unchecked") public void monitor(Object namespace) { if (namespace instanceof ObservableList) { ((ObservableList)namespace).addListener(listChangeListener); } else if (namespace instanceof ObservableMap) { ((ObservableMap)namespace).addListener(mapChangeListener); } else { BeanAdapter namespaceAdapter = new BeanAdapter(namespace); ObservableValue propertyModel = namespaceAdapter.getPropertyModel(key); if (propertyModel != null) { propertyModel.addListener(propertyChangeListener); } namespace = namespaceAdapter; } this.namespace = namespace; if (next != null) { Object value = Expression.get(namespace, key); if (value != null) { next.monitor(value); } } } @SuppressWarnings("unchecked") public void unmonitor() { if (namespace instanceof ObservableList) { ((ObservableList)namespace).removeListener(listChangeListener); } else if (namespace instanceof ObservableMap) { ((ObservableMap)namespace).removeListener(mapChangeListener); } else if (namespace != null) { BeanAdapter namespaceAdapter = (BeanAdapter)namespace; ObservableValue propertyModel = namespaceAdapter.getPropertyModel(key); if (propertyModel != null) { propertyModel.removeListener(propertyChangeListener); } } namespace = null; if (next != null) { next.unmonitor(); } } public void remonitor() { if (next != null) { next.unmonitor(); Object value = Expression.get(namespace, key); if (value != null) { next.monitor(value); } } } } private Object namespace; private Expression expression; private Class type; private ArrayList argumentMonitors; private int listenerCount = 0; public ExpressionValue(Object namespace, Expression expression, Class type) { if (namespace == null) { throw new NullPointerException(); } if (expression == null) { throw new NullPointerException(); } if (type == null) { throw new NullPointerException(); } this.namespace = namespace; this.expression = expression; this.type = type; List arguments = expression.getArguments(); argumentMonitors = new ArrayList(arguments.size()); for (KeyPath argument : arguments) { argumentMonitors.add(new KeyPathMonitor(argument.iterator())); } } @Override public Object getValue() { return BeanAdapter.coerce(expression.evaluate(namespace), type); } @Override public void addListener(InvalidationListener listener) { if (listenerCount == 0) { monitorArguments(); } super.addListener(listener); listenerCount++; } @Override public void removeListener(InvalidationListener listener) { super.removeListener(listener); listenerCount--; if (listenerCount == 0) { unmonitorArguments(); } } @Override public void addListener(ChangeListener listener) { if (listenerCount == 0) { monitorArguments(); } super.addListener(listener); listenerCount++; } @Override public void removeListener(ChangeListener listener) { super.removeListener(listener); listenerCount--; if (listenerCount == 0) { unmonitorArguments(); } } private void monitorArguments() { for (KeyPathMonitor argumentMonitor : argumentMonitors) { argumentMonitor.monitor(namespace); } } private void unmonitorArguments() { for (KeyPathMonitor argumentMonitor : argumentMonitors) { argumentMonitor.unmonitor(); } } }