diff options
author | Tom Schindl | 2013-04-13 09:50:25 +0000 |
---|---|---|
committer | Tom Schindl | 2013-04-13 09:50:25 +0000 |
commit | e5d523417f5fb78a9dc709c2543afc4b0c760e9e (patch) | |
tree | af9f06978524e0b41cd15ba25bbe33f89706b8d5 /bundles | |
parent | 99780bf8fba2d33ac5f3ec04e18bf78ae7c5b436 (diff) | |
download | org.eclipse.efxclipse-e5d523417f5fb78a9dc709c2543afc4b0c760e9e.tar.gz org.eclipse.efxclipse-e5d523417f5fb78a9dc709c2543afc4b0c760e9e.tar.xz org.eclipse.efxclipse-e5d523417f5fb78a9dc709c2543afc4b0c760e9e.zip |
initial checkin
Diffstat (limited to 'bundles')
27 files changed, 1819 insertions, 0 deletions
diff --git a/bundles/runtime/org.eclipse.fx.databinding/.classpath b/bundles/runtime/org.eclipse.fx.databinding/.classpath new file mode 100755 index 000000000..b1dabee38 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/bundles/runtime/org.eclipse.fx.databinding/.gitignore b/bundles/runtime/org.eclipse.fx.databinding/.gitignore new file mode 100755 index 000000000..4dc009173 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/.gitignore @@ -0,0 +1,2 @@ +/target +/bin diff --git a/bundles/runtime/org.eclipse.fx.databinding/.project b/bundles/runtime/org.eclipse.fx.databinding/.project new file mode 100755 index 000000000..615e24b53 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.fx.databinding</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/bundles/runtime/org.eclipse.fx.databinding/.settings/org.eclipse.core.resources.prefs b/bundles/runtime/org.eclipse.fx.databinding/.settings/org.eclipse.core.resources.prefs new file mode 100755 index 000000000..4824b8026 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/bundles/runtime/org.eclipse.fx.databinding/.settings/org.eclipse.core.runtime.prefs b/bundles/runtime/org.eclipse.fx.databinding/.settings/org.eclipse.core.runtime.prefs new file mode 100755 index 000000000..deae05a97 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/.settings/org.eclipse.core.runtime.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +line.separator=\r\n diff --git a/bundles/runtime/org.eclipse.fx.databinding/.settings/org.eclipse.jdt.core.prefs b/bundles/runtime/org.eclipse.fx.databinding/.settings/org.eclipse.jdt.core.prefs new file mode 100755 index 000000000..f42de363a --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/bundles/runtime/org.eclipse.fx.databinding/META-INF/MANIFEST.MF b/bundles/runtime/org.eclipse.fx.databinding/META-INF/MANIFEST.MF new file mode 100755 index 000000000..c1dd2b394 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/META-INF/MANIFEST.MF @@ -0,0 +1,39 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %Bundle-Name +Bundle-SymbolicName: org.eclipse.fx.databinding +Bundle-Version: 0.8.1.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.7 +Require-Bundle: org.eclipse.core.databinding.observable;bundle-version="1.4.0", + org.eclipse.core.databinding.property;bundle-version="1.4.0", + org.eclipse.equinox.common;bundle-version="3.6.0" +Import-Package: javafx.animation;version="2.0.0", + javafx.application;version="2.0.0", + javafx.beans;version="2.0.0", + javafx.beans.binding;version="2.0.0", + javafx.beans.property;version="2.0.0", + javafx.beans.value;version="2.0.0", + javafx.collections;version="2.0.0", + javafx.concurrent;version="2.0.0", + javafx.embed.swing;version="2.0.0", + javafx.event;version="2.0.0", + javafx.fxml;version="2.0.0", + javafx.geometry;version="2.0.0", + javafx.scene;version="2.0.0", + javafx.scene.chart;version="2.0.0", + javafx.scene.control;version="2.0.0", + javafx.scene.control.cell;version="2.0.0", + javafx.scene.effect;version="2.0.0", + javafx.scene.image;version="2.0.0", + javafx.scene.input;version="2.0.0", + javafx.scene.layout;version="2.0.0", + javafx.scene.media;version="2.0.0", + javafx.scene.paint;version="2.0.0", + javafx.scene.shape;version="2.0.0", + javafx.scene.text;version="2.0.0", + javafx.scene.transform;version="2.0.0", + javafx.scene.web;version="2.0.0", + javafx.stage;version="2.0.0", + javafx.util;version="2.0.0" +Export-Package: org.eclipse.fx.databinding +Bundle-Vendor: %Bundle-Vendor diff --git a/bundles/runtime/org.eclipse.fx.databinding/OSGI-INF/l10n/bundle.properties b/bundles/runtime/org.eclipse.fx.databinding/OSGI-INF/l10n/bundle.properties new file mode 100755 index 000000000..3db214f6e --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/OSGI-INF/l10n/bundle.properties @@ -0,0 +1,3 @@ +#Properties file for org.eclipse.fx.databinding
+Bundle-Vendor = BestSolution.at
+Bundle-Name = JavaFX Eclipse Databinding
\ No newline at end of file diff --git a/bundles/runtime/org.eclipse.fx.databinding/about.html b/bundles/runtime/org.eclipse.fx.databinding/about.html new file mode 100755 index 000000000..ecd1378e9 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/about.html @@ -0,0 +1,28 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> +<title>About</title> +</head> +<body lang="EN-US"> +<h2>About This Content</h2> + +<p>June 2, 2006</p> +<h3>License</h3> + +<p>The BestSolution.at makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available +at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>. +For purposes of the EPL, "Program" will mean the Content.</p> + +<p>If you did not receive this Content directly from the BestSolution.at, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p> + +</body> +</html>
\ No newline at end of file diff --git a/bundles/runtime/org.eclipse.fx.databinding/build.properties b/bundles/runtime/org.eclipse.fx.databinding/build.properties new file mode 100755 index 000000000..bad151d65 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/build.properties @@ -0,0 +1,6 @@ +source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ about.html,\
+ OSGI-INF/
diff --git a/bundles/runtime/org.eclipse.fx.databinding/pom.xml b/bundles/runtime/org.eclipse.fx.databinding/pom.xml new file mode 100755 index 000000000..2a2285ebd --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/pom.xml @@ -0,0 +1,34 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <name>e(fx)clipse - Runtime - Eclipse Databinding Support</name> + <groupId>org.eclipse.fx.runtime</groupId> + <artifactId>org.eclipse.fx.databinding</artifactId> + <packaging>eclipse-plugin</packaging> + + <parent> + <groupId>org.eclipse.fx</groupId> + <artifactId>releng</artifactId> + <relativePath>../../../releng/org.eclipse.fx.releng/pom.xml</relativePath> + <version>0.8.1-SNAPSHOT</version> + </parent> + + <build> + <resources> + <!-- to ensure that the feature lookup of the ui test works --> + <resource> + <directory>.</directory> + <includes> + <include>META-INF/</include> + </includes> + </resource> + </resources> + <plugins> + <plugin> + <groupId>org.eclipse.tycho</groupId> + <artifactId>tycho-source-plugin</artifactId> + </plugin> + </plugins> + </build> + +</project>
\ No newline at end of file diff --git a/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/AdapterFactory.java b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/AdapterFactory.java new file mode 100755 index 000000000..d4a6f7bb4 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/AdapterFactory.java @@ -0,0 +1,518 @@ +/*******************************************************************************
+ * Copyright (c) 2012 BestSolution.at and others.
+ * 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:
+ * Tom Schindl<tom.schindl@bestsolution.at> - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.fx.databinding;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import javafx.beans.InvalidationListener;
+import javafx.beans.binding.Bindings;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.beans.value.WritableValue;
+import javafx.collections.ListChangeListener;
+import javafx.collections.ListChangeListener.Change;
+import javafx.collections.ObservableList;
+
+import org.eclipse.core.databinding.observable.ChangeEvent;
+import org.eclipse.core.databinding.observable.DisposeEvent;
+import org.eclipse.core.databinding.observable.IChangeListener;
+import org.eclipse.core.databinding.observable.IDisposeListener;
+import org.eclipse.core.databinding.observable.list.IListChangeListener;
+import org.eclipse.core.databinding.observable.list.IObservableList;
+import org.eclipse.core.databinding.observable.list.ListChangeEvent;
+import org.eclipse.core.databinding.observable.list.ListDiffEntry;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.databinding.observable.value.IValueChangeListener;
+import org.eclipse.core.databinding.observable.value.ValueChangeEvent;
+
+public class AdapterFactory {
+ static class WrappedList<E> implements ObservableList<E> {
+
+ private List<InvalidationListener> fxInvalidationListeners;
+ private List<ListChangeListener<? super E>> fxChangeListeners;
+
+ private final IObservableList list;
+ private IChangeListener dbInvalidationListener;
+ private IListChangeListener dbChangeListener;
+
+ public WrappedList(IObservableList list) {
+ this.list = list;
+ this.list.addDisposeListener(new IDisposeListener() {
+
+ @Override
+ public void handleDispose(DisposeEvent event) {
+ fxInvalidationListeners.clear();
+ dbInvalidationListener = null;
+
+ fxChangeListeners.clear();
+ dbChangeListener = null;
+ }
+ });
+ }
+
+ @Override
+ public int size() {
+ return list.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return list.isEmpty();
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ return list.contains(o);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Iterator<E> iterator() {
+ return list.iterator();
+ }
+
+ @Override
+ public Object[] toArray() {
+ return list.toArray();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T> T[] toArray(T[] a) {
+ return (T[]) list.toArray(a);
+ }
+
+ @Override
+ public boolean add(E e) {
+ return list.add(e);
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ return list.remove(o);
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> c) {
+ return list.containsAll(c);
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends E> c) {
+ return list.addAll(c);
+ }
+
+ @Override
+ public boolean addAll(int index, Collection<? extends E> c) {
+ return list.addAll(index, c);
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> c) {
+ return list.removeAll(c);
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> c) {
+ return list.retainAll(c);
+ }
+
+ @Override
+ public void clear() {
+ list.clear();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public E get(int index) {
+ return (E) list.get(index);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public E set(int index, E element) {
+ return (E) list.set(index, element);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void add(int index, E element) {
+ list.add(index, element);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public E remove(int index) {
+ return (E) list.remove(index);
+ }
+
+ @Override
+ public int indexOf(Object o) {
+ return list.indexOf(o);
+ }
+
+ @Override
+ public int lastIndexOf(Object o) {
+ return list.lastIndexOf(o);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public ListIterator<E> listIterator() {
+ return list.listIterator();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public ListIterator<E> listIterator(int index) {
+ return list.listIterator(index);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public List<E> subList(int fromIndex, int toIndex) {
+ return list.subList(fromIndex, toIndex);
+ }
+
+ @Override
+ public void addListener(InvalidationListener listener) {
+ if( fxInvalidationListeners == null ) {
+ fxInvalidationListeners = new ArrayList<InvalidationListener>();
+ dbInvalidationListener = new IChangeListener() {
+
+ @Override
+ public void handleChange(ChangeEvent event) {
+ for( InvalidationListener l : fxInvalidationListeners.toArray(new InvalidationListener[0]) ) {
+ l.invalidated(WrappedList.this);
+ }
+ }
+ };
+ list.addChangeListener(dbInvalidationListener);
+ }
+
+ fxInvalidationListeners.add(listener);
+ }
+
+ @Override
+ public void removeListener(InvalidationListener listener) {
+ if( fxInvalidationListeners != null ) {
+ fxInvalidationListeners.remove(listener);
+ if( fxInvalidationListeners.isEmpty() ) {
+ list.removeChangeListener(dbInvalidationListener);
+ dbInvalidationListener = null;
+ fxInvalidationListeners = null;
+ }
+ }
+ }
+
+ @Override
+ public boolean addAll(E... elements) {
+ return list.addAll(Arrays.asList(elements));
+ }
+
+ @Override
+ public void addListener(ListChangeListener<? super E> listener) {
+ if( fxChangeListeners == null ) {
+ fxChangeListeners = new ArrayList<ListChangeListener<? super E>>();
+ dbChangeListener = new IListChangeListener() {
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void handleListChange(ListChangeEvent event) {
+ final ListDiffEntry[] differences = event.diff.getDifferences();
+
+ if( differences.length == 0 ) {
+ return;
+ }
+
+ //TODO We need to make this perform a lot better by calculating range changes
+ for( ListChangeListener<? super E> l : fxChangeListeners.toArray(new ListChangeListener[0]) ) {
+ Change<E> change = new Change<E>(WrappedList.this) {
+ private int index = -1;
+ private ListDiffEntry current;
+
+ @Override
+ public int getFrom() {
+ return current.getPosition();
+ }
+
+ @Override
+ protected int[] getPermutation() {
+ return new int[0];
+ }
+
+ @Override
+ public List<E> getRemoved() {
+ if( ! current.isAddition() ) {
+ return Collections.singletonList((E)current.getElement());
+ }
+ return Collections.emptyList();
+ }
+
+ @Override
+ public int getTo() {
+ if( current.isAddition() ) {
+ return current.getPosition() + 1;
+ } else {
+ return current.getPosition();
+ }
+ }
+
+ public boolean wasAdded() {
+ return current.isAddition();
+ }
+
+ public boolean wasRemoved() {
+ return ! current.isAddition();
+ }
+
+ public boolean wasPermutated() {
+ return false;
+ }
+
+ public boolean wasReplaced() {
+ return false;
+ }
+
+ @Override
+ public boolean next() {
+ index++;
+ if( index < differences.length ) {
+ current = differences[index];
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void reset() {
+ index = 0;
+ }
+ };
+ l.onChanged(change);
+ }
+ }
+ };
+ list.addListChangeListener(dbChangeListener);
+ }
+
+ fxChangeListeners.add(listener);
+ }
+
+ @Override
+ public void removeListener(ListChangeListener<? super E> listener) {
+ if( fxChangeListeners != null ) {
+ fxChangeListeners.remove(listener);
+ if( fxChangeListeners.isEmpty() ) {
+ list.removeListChangeListener(dbChangeListener);
+ dbChangeListener = null;
+ fxChangeListeners = null;
+ }
+ }
+ }
+
+ @Override
+ public void remove(int from, int to) {
+ //TODO Improve performance??
+ for( int idx = to; idx >= from; idx-- ) {
+ list.remove(idx);
+ }
+ }
+
+ @Override
+ public boolean removeAll(E... elements) {
+ return list.removeAll(Arrays.asList(elements));
+ }
+
+
+ @Override
+ public boolean retainAll(E... elements) {
+ return list.retainAll(Arrays.asList(elements));
+ }
+
+ @Override
+ public boolean setAll(E... elements) {
+ //TODO Improve performance
+ list.clear();
+ return list.addAll(Arrays.asList(elements));
+ }
+
+ @Override
+ public boolean setAll(Collection<? extends E> col) {
+ //TODO Improve performance
+ list.clear();
+ return list.addAll(col);
+ }
+ }
+
+ static class WrappedValue<E> implements ObservableWritableValue<E> {
+
+ private List<InvalidationListener> fxInvalidationListeners;
+ private List<ChangeListener<? super E>> fxChangeListeners;
+
+ private final IObservableValue value;
+ private IChangeListener dbInvalidationListener;
+ private IValueChangeListener dbChangeListener;
+
+
+ public WrappedValue(IObservableValue value) {
+ this.value = value;
+ this.value.addDisposeListener(new IDisposeListener() {
+
+ @Override
+ public void handleDispose(DisposeEvent event) {
+ fxInvalidationListeners.clear();
+ dbInvalidationListener = null;
+
+ fxChangeListeners.clear();
+ dbChangeListener = null;
+ }
+ });
+ }
+
+ @Override
+ public void addListener(InvalidationListener listener) {
+ if( fxInvalidationListeners == null ) {
+ fxInvalidationListeners = new ArrayList<InvalidationListener>();
+ dbInvalidationListener = new IChangeListener() {
+
+ @Override
+ public void handleChange(ChangeEvent event) {
+ for( InvalidationListener l : fxInvalidationListeners.toArray(new InvalidationListener[0]) ) {
+ l.invalidated(WrappedValue.this);
+ }
+ }
+ };
+ value.addChangeListener(dbInvalidationListener);
+ }
+
+ fxInvalidationListeners.add(listener);
+ }
+
+ @Override
+ public void removeListener(InvalidationListener listener) {
+ if( fxInvalidationListeners != null ) {
+ fxInvalidationListeners.remove(listener);
+ if( fxInvalidationListeners.isEmpty() ) {
+ value.removeChangeListener(dbInvalidationListener);
+ dbInvalidationListener = null;
+ fxInvalidationListeners = null;
+ }
+ }
+ }
+
+ @Override
+ public void addListener(ChangeListener<? super E> listener) {
+ if( fxChangeListeners == null ) {
+ fxChangeListeners = new ArrayList<ChangeListener<? super E>>();
+ dbChangeListener = new IValueChangeListener() {
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void handleValueChange(ValueChangeEvent event) {
+ for( ChangeListener<? super E> l : fxChangeListeners.toArray(new ChangeListener[0]) ) {
+ l.changed(WrappedValue.this, (E)event.diff.getOldValue(), (E)event.diff.getNewValue());
+ }
+ }
+ };
+ value.addValueChangeListener(dbChangeListener);
+ }
+
+ fxChangeListeners.add(listener);
+ }
+
+ @Override
+ public void removeListener(ChangeListener<? super E> listener) {
+ if( fxChangeListeners != null ) {
+ fxChangeListeners.remove(listener);
+ if( fxChangeListeners.isEmpty() ) {
+ value.removeValueChangeListener(dbChangeListener);
+ dbChangeListener = null;
+ fxChangeListeners = null;
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public E getValue() {
+ return (E) value.getValue();
+ }
+
+ @Override
+ public void setValue(E value) {
+ this.value.setValue(value);
+ }
+ }
+
+ public static <E> ObservableWritableValue<E> adapt(IObservableValue value) {
+ return new WrappedValue<E>(value);
+ }
+
+ public static <E> ObservableList<E> adapt(IObservableList list) {
+ return new WrappedList<E>(list);
+ }
+
+ enum InitialSync {
+ FX_TO_DB,
+ DB_TO_FX
+ }
+
+ public static <E> void bind(ObservableList<E> fxObs, IObservableList dbObs, InitialSync initialSync) {
+ ObservableList<E> dbList = adapt(dbObs);
+ if( initialSync == InitialSync.FX_TO_DB ) {
+ Bindings.bindContent(dbList, fxObs);
+ } else {
+ Bindings.bindContentBidirectional(fxObs, dbList);
+ }
+
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <E, F extends ObservableValue<E> & WritableValue<E>> void bind(F fxObs, IObservableValue dbObs, InitialSync initialSync) {
+ if( initialSync == InitialSync.FX_TO_DB ) {
+ dbObs.setValue(fxObs.getValue());
+ } else {
+ fxObs.setValue((E) dbObs.getValue());
+ }
+ ObservableWritableValue<E> wrapped = adapt(dbObs);
+ do_bind(fxObs, wrapped);
+ }
+
+ private static <E, F extends ObservableValue<E> & WritableValue<E>> void do_bind(final F fxObs, final F dbObs) {
+ fxObs.addListener(new ChangeListener<E>() {
+ boolean syncing;
+ @Override
+ public void changed(ObservableValue<? extends E> observable, E oldValue, E newValue) {
+ if( syncing ) {
+ return;
+ }
+
+ try {
+ syncing = true;
+ if( observable == fxObs ) {
+ dbObs.setValue(newValue);
+ } else {
+ fxObs.setValue(newValue);
+ }
+ } finally {
+ syncing = false;
+ }
+ }
+ });
+ }
+}
diff --git a/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/IJFXBeanObservable.java b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/IJFXBeanObservable.java new file mode 100755 index 000000000..30a1fa1da --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/IJFXBeanObservable.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2007 Brad Reynolds and others. + * 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: + * Brad Reynolds - initial API and implementation + * Brad Reynolds - bug 147515 + ******************************************************************************/ + +package org.eclipse.fx.databinding; + +import java.beans.PropertyDescriptor; + +import org.eclipse.core.databinding.observable.IObserving; + +/** + * Provides access to details of bean observables. + * <p> + * This interface is not meant to be implemented by clients. + * </p> + * + * @since 3.3 + */ +public interface IJFXBeanObservable extends IObserving { + /** + * @return property descriptor of the property being observed, + * <code>null</code> if the runtime time information was not + * provided on construction of the observable + */ + public PropertyDescriptor getPropertyDescriptor(); +} diff --git a/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/IJFXBeanProperty.java b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/IJFXBeanProperty.java new file mode 100755 index 000000000..c334121f5 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/IJFXBeanProperty.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2012 BestSolution.at and others. + * 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: + * Tom Schindl<tom.schindl@bestsolution.at> - initial API and implementation + *******************************************************************************/ +package org.eclipse.fx.databinding; + +import java.beans.PropertyDescriptor; + +import org.eclipse.core.databinding.property.IProperty; + +public interface IJFXBeanProperty extends IProperty { + public PropertyDescriptor getPropertyDescriptor(); +} diff --git a/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/IJFXBeanValueProperty.java b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/IJFXBeanValueProperty.java new file mode 100755 index 000000000..f4ec4573c --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/IJFXBeanValueProperty.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2012 BestSolution.at and others. + * 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: + * Tom Schindl<tom.schindl@bestsolution.at> - initial API and implementation + *******************************************************************************/ +package org.eclipse.fx.databinding; + +import org.eclipse.core.databinding.property.value.IValueProperty; + +public interface IJFXBeanValueProperty extends IJFXBeanProperty, IValueProperty { + public IJFXBeanValueProperty value(String propertyName); + + public IJFXBeanValueProperty value(String propertyName, Class<?> valueType); + + public IJFXBeanValueProperty value(IJFXBeanValueProperty property); +} diff --git a/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/JFXBeanProperties.java b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/JFXBeanProperties.java new file mode 100755 index 000000000..2f97d220d --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/JFXBeanProperties.java @@ -0,0 +1,75 @@ +/*******************************************************************************
+ * Copyright (c) 2012 BestSolution.at and others.
+ * 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:
+ * Tom Schindl<tom.schindl@bestsolution.at> - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.fx.databinding;
+
+import java.beans.PropertyDescriptor;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.databinding.property.value.IValueProperty;
+import org.eclipse.fx.databinding.internal.AnonymousFXBeanValueProperty;
+import org.eclipse.fx.databinding.internal.FXBeanPropertyHelper;
+import org.eclipse.fx.databinding.internal.FXBeanValueProperty;
+import org.eclipse.fx.databinding.internal.FXBeanValuePropertyDecorator;
+
+
+import javafx.beans.property.Property;
+
+
+public class JFXBeanProperties {
+ public static IJFXBeanValueProperty value(String propertyName) {
+ return value(null, propertyName, null);
+ }
+
+ public static IJFXBeanValueProperty value(String propertyName, Class valueType) {
+ return value(null, propertyName, valueType);
+ }
+
+ public static IJFXBeanValueProperty value(Class beanClass,
+ String propertyName, Class valueType) {
+ String[] propertyNames = split(propertyName);
+ if (propertyNames.length > 1)
+ valueType = null;
+
+ PropertyDescriptor propertyDescriptor;
+ IValueProperty property;
+ if (beanClass == null) {
+ propertyDescriptor = null;
+ property = new AnonymousFXBeanValueProperty(propertyNames[0],
+ valueType);
+ } else {
+ propertyDescriptor = FXBeanPropertyHelper.getPropertyDescriptor(
+ beanClass, propertyNames[0]);
+ property = new FXBeanValueProperty(propertyDescriptor, valueType);
+ }
+
+ IJFXBeanValueProperty beanProperty = new FXBeanValuePropertyDecorator(
+ property, propertyDescriptor);
+ for (int i = 1; i < propertyNames.length; i++) {
+ beanProperty = beanProperty.value(propertyNames[i]);
+ }
+ return beanProperty;
+ }
+
+ private static String[] split(String propertyName) {
+ if (propertyName.indexOf('.') == -1)
+ return new String[] { propertyName };
+ List<String> propertyNames = new ArrayList<String>();
+ int index;
+ while ((index = propertyName.indexOf('.')) != -1) {
+ propertyNames.add(propertyName.substring(0, index));
+ propertyName = propertyName.substring(index + 1);
+ }
+ propertyNames.add(propertyName);
+ return (String[]) propertyNames
+ .toArray(new String[propertyNames.size()]);
+ }
+}
diff --git a/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/JFXRealm.java b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/JFXRealm.java new file mode 100755 index 000000000..50835bf5c --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/JFXRealm.java @@ -0,0 +1,40 @@ +/*******************************************************************************
+ * Copyright (c) 2012 BestSolution.at and others.
+ * 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:
+ * Tom Schindl<tom.schindl@bestsolution.at> - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.fx.databinding;
+
+import javafx.application.Platform;
+
+import org.eclipse.core.databinding.observable.Realm;
+
+public class JFXRealm extends Realm {
+ public static void createDefault() {
+ setDefault(new JFXRealm());
+ }
+
+ @Override
+ public boolean isCurrent() {
+ return Platform.isFxApplicationThread();
+ }
+
+ @Override
+ public void asyncExec(Runnable runnable) {
+ Platform.runLater(runnable);
+ }
+
+ @Override
+ public void exec(Runnable runnable) {
+ if( isCurrent() ) {
+ runnable.run();
+ } else {
+ Platform.runLater(runnable);
+ }
+ }
+}
\ No newline at end of file diff --git a/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/JFXUIProperties.java b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/JFXUIProperties.java new file mode 100755 index 000000000..15dcaa7d4 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/JFXUIProperties.java @@ -0,0 +1,17 @@ +/*******************************************************************************
+ * Copyright (c) 2012 BestSolution.at and others.
+ * 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:
+ * Tom Schindl<tom.schindl@bestsolution.at> - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.fx.databinding;
+
+public class JFXUIProperties {
+ public static IJFXBeanValueProperty singleListViewSelection() {
+ return JFXBeanProperties.value("selectionModel.selectedItem");
+ }
+}
diff --git a/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/ObservableWritableValue.java b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/ObservableWritableValue.java new file mode 100755 index 000000000..6af0fb838 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/ObservableWritableValue.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2012 BestSolution.at and others. + * 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: + * Tom Schindl<tom.schindl@bestsolution.at> - initial API and implementation + *******************************************************************************/ +package org.eclipse.fx.databinding; + +import javafx.beans.value.ObservableValue; +import javafx.beans.value.WritableValue; + +public interface ObservableWritableValue<E> extends ObservableValue<E>, WritableValue<E> { + +} diff --git a/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/TreeUtil.java b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/TreeUtil.java new file mode 100755 index 000000000..49fc1f5bb --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/TreeUtil.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2012 BestSolution.at and others. + * 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: + * Tom Schindl<tom.schindl@bestsolution.at> - initial API and implementation + *******************************************************************************/ +package org.eclipse.fx.databinding; + +import java.util.Iterator; + +import org.eclipse.core.databinding.observable.list.IListChangeListener; +import org.eclipse.core.databinding.observable.list.IObservableList; +import org.eclipse.core.databinding.observable.list.ListChangeEvent; +import org.eclipse.core.databinding.observable.list.ListDiffVisitor; + +import javafx.collections.ObservableList; +import javafx.scene.control.TreeItem; + +public class TreeUtil { + public static <T> TreeItem<T> createModel(T root, ObservableFactory<T> factory) { + return new TreeItemImpl<T>(root,factory); + } + + public interface ObservableFactory<T> { + public IObservableList createObservable(T parent); + } + + static class TreeItemImpl<T> extends TreeItem<T> { + private IObservableList list; + private ObservableFactory<T> factory; + private boolean hasLoadedChildren = false; + + public TreeItemImpl(T element, ObservableFactory<T> factory) { + setValue(element); + this.factory = factory; + this.list = factory.createObservable(element); + } + + @Override + public ObservableList<TreeItem<T>> getChildren() { + if (hasLoadedChildren == false) { + loadChildren(); + } + return super.getChildren(); + } + + public boolean isLeaf() { + if (hasLoadedChildren == false) { + loadChildren(); + } + return super.getChildren().isEmpty(); + } + + private void loadChildren() { + hasLoadedChildren = true; + if( list != null ) { + final ObservableList<TreeItem<T>> itemList = getChildren(); + list.addListChangeListener(new IListChangeListener() { + + @Override + public void handleListChange(ListChangeEvent event) { + event.diff.accept(new ListDiffVisitor() { + + @Override + public void handleRemove(int index, Object element) { + if( itemList.size() < index ) { + TreeItem<T> t = itemList.get(index); + if( t.getValue() == element ) { + itemList.remove(index); + } else { + Iterator<TreeItem<T>> it = itemList.iterator(); + while(it.hasNext()) { + if( it.next().getValue() == element ) { + it.remove(); + break; + } + } + } + } + } + + @Override + public void handleAdd(int index, Object element) { + if( itemList.size() > index ) { + itemList.add(index, new TreeItemImpl<T>((T) element, factory)); + } else { + itemList.add(new TreeItemImpl<T>((T) element, factory)); + } + } + }); + } + }); + for( Object o : list ) { + itemList.add(new TreeItemImpl<T>((T) o, factory)); + } + } + } + + } +} diff --git a/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/internal/AnonymousFXBeanValueProperty.java b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/internal/AnonymousFXBeanValueProperty.java new file mode 100755 index 000000000..f6e799622 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/internal/AnonymousFXBeanValueProperty.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2008, 2009 Matthew Hall and others. + * 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: + * Matthew Hall - initial API and implementation (bug 247997) + * Matthew Hall - bugs 264307, 264619 + ******************************************************************************/ + +package org.eclipse.fx.databinding.internal; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.databinding.observable.masterdetail.MasterDetailObservables; +import org.eclipse.core.databinding.observable.value.IObservableValue; +import org.eclipse.core.databinding.property.value.DelegatingValueProperty; +import org.eclipse.core.databinding.property.value.IValueProperty; +import org.eclipse.fx.databinding.JFXBeanProperties; + + +/** + * @since 3.3 + * + */ +public class AnonymousFXBeanValueProperty extends DelegatingValueProperty { + private final String propertyName; + + private Map<Class<?>,IValueProperty> delegates; + + /** + * @param propertyName + * @param valueType + */ + public AnonymousFXBeanValueProperty(String propertyName, Class<?> valueType) { + super(valueType); + this.propertyName = propertyName; + this.delegates = new HashMap<Class<?>,IValueProperty>(); + } + + protected IValueProperty doGetDelegate(Object source) { + return getClassDelegate(source.getClass()); + } + + private IValueProperty getClassDelegate(Class<?> beanClass) { + if (delegates.containsKey(beanClass)) + return delegates.get(beanClass); + + IValueProperty delegate; + try { + delegate = JFXBeanProperties.value(beanClass, propertyName, + (Class<?>) getValueType()); + } catch (IllegalArgumentException noSuchProperty) { + delegate = null; + } + delegates.put(beanClass, delegate); + return delegate; + } + + public IObservableValue observeDetail(IObservableValue master) { + Object valueType = getValueType(); + if (valueType == null) + valueType = inferValueType(master.getValueType()); + return MasterDetailObservables.detailValue(master, valueFactory(master + .getRealm()), valueType); + } + + private Object inferValueType(Object masterObservableValueType) { + if (masterObservableValueType instanceof Class) { + return getClassDelegate((Class<?>) masterObservableValueType) + .getValueType(); + } + return null; + } + + public String toString() { + String s = "?." + propertyName; //$NON-NLS-1$ + Class<?> valueType = (Class<?>) getValueType(); + if (valueType != null) + s += "<" + FXBeanPropertyHelper.shortClassName(valueType) + ">"; //$NON-NLS-1$//$NON-NLS-2$ + return s; + } +} diff --git a/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/internal/FXBeanObservableValueDecorator.java b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/internal/FXBeanObservableValueDecorator.java new file mode 100755 index 000000000..71124468d --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/internal/FXBeanObservableValueDecorator.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Brad Reynolds and others. + * 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: + * Brad Reynolds - initial API and implementation + * Matthew Hall - bug 246625 + ******************************************************************************/ + +package org.eclipse.fx.databinding.internal; + +import java.beans.PropertyDescriptor; + +import org.eclipse.core.databinding.observable.IObservable; +import org.eclipse.core.databinding.observable.IObserving; +import org.eclipse.core.databinding.observable.value.DecoratingObservableValue; +import org.eclipse.core.databinding.observable.value.IObservableValue; +import org.eclipse.fx.databinding.IJFXBeanObservable; + + +/** + * {@link IJFXBeanObservable} decorator for an {@link IObservableValue}. + * + * @since 3.3 + */ +public class FXBeanObservableValueDecorator extends DecoratingObservableValue + implements IJFXBeanObservable { + private PropertyDescriptor propertyDescriptor; + + /** + * @param decorated + * @param propertyDescriptor + */ + public FXBeanObservableValueDecorator(IObservableValue decorated, + PropertyDescriptor propertyDescriptor) { + super(decorated, true); + this.propertyDescriptor = propertyDescriptor; + } + + public synchronized void dispose() { + this.propertyDescriptor = null; + super.dispose(); + } + + public Object getObserved() { + IObservable decorated = getDecorated(); + if (decorated instanceof IObserving) + return ((IObserving) decorated).getObserved(); + return null; + } + + public PropertyDescriptor getPropertyDescriptor() { + return propertyDescriptor; + } +} diff --git a/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/internal/FXBeanPropertyHelper.java b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/internal/FXBeanPropertyHelper.java new file mode 100755 index 000000000..c9ac47a7a --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/internal/FXBeanPropertyHelper.java @@ -0,0 +1,241 @@ +/*******************************************************************************
+ * Copyright (c) 2009 Matthew Hall and others.
+ * 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:
+ * Matthew Hall - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.fx.databinding.internal;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+
+public class FXBeanPropertyHelper {
+ /**
+ * Sets the contents of the given property on the given source object to the
+ * given value.
+ *
+ * @param source
+ * the source object which has the property being updated
+ * @param propertyDescriptor
+ * the property being changed
+ * @param value
+ * the new value of the property
+ */
+ public static void writeProperty(Object source,
+ PropertyDescriptor propertyDescriptor, Object value) {
+ try {
+ Method writeMethod = propertyDescriptor.getWriteMethod();
+ if (null == writeMethod) {
+ throw new IllegalArgumentException(
+ "Missing public setter method for " //$NON-NLS-1$
+ + propertyDescriptor.getName() + " property"); //$NON-NLS-1$
+ }
+ if (!writeMethod.isAccessible()) {
+ writeMethod.setAccessible(true);
+ }
+
+ writeMethod.invoke(source, new Object[] { value });
+ } catch (InvocationTargetException e) {
+ /*
+ * InvocationTargetException wraps any exception thrown by the
+ * invoked method.
+ */
+ throw new RuntimeException(e.getCause());
+ } catch (Exception e) {
+//TODO Problems with primitive values
+ /*if (BeansObservables.DEBUG) {
+ Policy
+ .getLog()
+ .log(
+ new Status(
+ IStatus.WARNING,
+ Policy.JFACE_DATABINDING,
+ IStatus.OK,
+ "Could not change value of " + source + "." + propertyDescriptor.getName(), e)); //$NON-NLS-1$ //$NON-NLS-2$
+ }*/
+ }
+ }
+
+ /**
+ * Returns the contents of the given property for the given bean.
+ *
+ * @param source
+ * the source bean
+ * @param propertyDescriptor
+ * the property to retrieve
+ * @return the contents of the given property for the given bean.
+ */
+ public static Object readProperty(Object source,
+ PropertyDescriptor propertyDescriptor) {
+ try {
+ Method readMethod = propertyDescriptor.getReadMethod();
+ if (readMethod == null) {
+ throw new IllegalArgumentException(propertyDescriptor.getName()
+ + " property does not have a read method."); //$NON-NLS-1$
+ }
+ if (!readMethod.isAccessible()) {
+ readMethod.setAccessible(true);
+ }
+ return readMethod.invoke(source);
+ } catch (InvocationTargetException e) {
+ /*
+ * InvocationTargetException wraps any exception thrown by the
+ * invoked method.
+ */
+ throw new RuntimeException(e.getCause());
+ } catch (Exception e) {
+ e.printStackTrace();
+ /*if (BeansObservables.DEBUG) {
+ Policy
+ .getLog()
+ .log(
+ new Status(
+ IStatus.WARNING,
+ Policy.JFACE_DATABINDING,
+ IStatus.OK,
+ "Could not read value of " + source + "." + propertyDescriptor.getName(), e)); //$NON-NLS-1$ //$NON-NLS-2$
+ }*/
+ return null;
+ }
+ }
+
+ /**
+ * Returns the element type of the given collection-typed property for the
+ * given bean.
+ *
+ * @param descriptor
+ * the property being inspected
+ * @return the element type of the given collection-typed property if it is
+ * an array property, or Object.class otherwise.
+ */
+ public static Class getCollectionPropertyElementType(
+ PropertyDescriptor descriptor) {
+ Class propertyType = descriptor.getPropertyType();
+ return propertyType.isArray() ? propertyType.getComponentType()
+ : Object.class;
+ }
+
+ /**
+ * @param beanClass
+ * @param propertyName
+ * @return the PropertyDescriptor for the named property on the given bean
+ * class
+ */
+ public static PropertyDescriptor getPropertyDescriptor(Class beanClass,
+ String propertyName) {
+ if (!beanClass.isInterface()) {
+ BeanInfo beanInfo;
+ try {
+ beanInfo = Introspector.getBeanInfo(beanClass);
+ } catch (IntrospectionException e) {
+ // cannot introspect, give up
+ return null;
+ }
+ PropertyDescriptor[] propertyDescriptors = beanInfo
+ .getPropertyDescriptors();
+ for (int i = 0; i < propertyDescriptors.length; i++) {
+ PropertyDescriptor descriptor = propertyDescriptors[i];
+ if (descriptor.getName().equals(propertyName)) {
+ return descriptor;
+ }
+ }
+ } else {
+ try {
+ PropertyDescriptor propertyDescriptors[];
+ List pds = new ArrayList();
+ getInterfacePropertyDescriptors(pds, beanClass);
+ if (pds.size() > 0) {
+ propertyDescriptors = (PropertyDescriptor[]) pds
+ .toArray(new PropertyDescriptor[pds.size()]);
+ PropertyDescriptor descriptor;
+ for (int i = 0; i < propertyDescriptors.length; i++) {
+ descriptor = propertyDescriptors[i];
+ if (descriptor.getName().equals(propertyName))
+ return descriptor;
+ }
+ }
+ } catch (IntrospectionException e) {
+ // cannot introspect, give up
+ return null;
+ }
+ }
+ throw new IllegalArgumentException(
+ "Could not find property with name " + propertyName + " in class " + beanClass); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Goes recursively into the interface and gets all defined
+ * propertyDescriptors
+ *
+ * @param propertyDescriptors
+ * The result list of all PropertyDescriptors the given interface
+ * defines (hierarchical)
+ * @param iface
+ * The interface to fetch the PropertyDescriptors
+ * @throws IntrospectionException
+ */
+ private static void getInterfacePropertyDescriptors(
+ List propertyDescriptors, Class iface)
+ throws IntrospectionException {
+ BeanInfo beanInfo = Introspector.getBeanInfo(iface);
+ PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
+ for (int i = 0; i < pds.length; i++) {
+ PropertyDescriptor pd = pds[i];
+ propertyDescriptors.add(pd);
+ }
+ Class[] subIntfs = iface.getInterfaces();
+ for (int j = 0; j < subIntfs.length; j++) {
+ getInterfacePropertyDescriptors(propertyDescriptors, subIntfs[j]);
+ }
+ }
+
+ /**
+ * @param observable
+ * @param propertyName
+ * @return property descriptor or <code>null</code>
+ */
+ /* package */public static PropertyDescriptor getValueTypePropertyDescriptor(
+ IObservableValue observable, String propertyName) {
+ if (observable.getValueType() != null)
+ return getPropertyDescriptor((Class) observable.getValueType(),
+ propertyName);
+ return null;
+ }
+
+ /**
+ * @param propertyDescriptor
+ * @return String description of property descriptor
+ */
+ public static String propertyName(PropertyDescriptor propertyDescriptor) {
+ Class beanClass = propertyDescriptor.getReadMethod()
+ .getDeclaringClass();
+ return shortClassName(beanClass)
+ + "." + propertyDescriptor.getName() + ""; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * @param beanClass
+ * @return class name excluding package
+ */
+ public static String shortClassName(Class beanClass) {
+ if (beanClass == null)
+ return "?"; //$NON-NLS-1$
+ String className = beanClass.getName();
+ int lastDot = className.lastIndexOf('.');
+ if (lastDot != -1)
+ className = className.substring(lastDot + 1);
+ return className;
+ }
+}
diff --git a/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/internal/FXBeanPropertyListener.java b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/internal/FXBeanPropertyListener.java new file mode 100755 index 000000000..c7579dbfe --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/internal/FXBeanPropertyListener.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (c) 2009 Matthew Hall and others. + * 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: + * Matthew Hall - initial API and implementation (bug 265561) + * Matthew Hall - bug 268336 + ******************************************************************************/ + +package org.eclipse.fx.databinding.internal; + +import java.beans.PropertyDescriptor; +import java.util.HashMap; +import java.util.Map; + +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; + +import org.eclipse.core.databinding.observable.IDiff; +import org.eclipse.core.databinding.property.IProperty; +import org.eclipse.core.databinding.property.ISimplePropertyListener; +import org.eclipse.core.databinding.property.NativePropertyListener; + +/** + * @since 3.3 + * + */ +public abstract class FXBeanPropertyListener extends NativePropertyListener { + private final PropertyDescriptor propertyDescriptor; + private final Map<Object, ChangeListener<Object>> map = new HashMap<Object, ChangeListener<Object>>(); + + protected FXBeanPropertyListener(IProperty property, + PropertyDescriptor propertyDescriptor, + ISimplePropertyListener listener) { + super(property, listener); + this.propertyDescriptor = propertyDescriptor; + } + + public void propertyChange(java.beans.PropertyChangeEvent evt) { + if (evt.getPropertyName() == null + || propertyDescriptor.getName().equals(evt.getPropertyName())) { + Object oldValue = evt.getOldValue(); + Object newValue = evt.getNewValue(); + IDiff diff; + if (evt.getPropertyName() == null || oldValue == null + || newValue == null) + diff = null; + else + diff = computeDiff(oldValue, newValue); + fireChange(evt.getSource(), diff); + } + } + + protected abstract IDiff computeDiff(Object oldValue, Object newValue); + + protected void doAddTo(Object source) { + if( ! map.containsKey(source) ) { + ChangeListener<Object> l = new ChangeListener<Object>() { + + @Override + public void changed(ObservableValue<? extends Object> source, + Object oldValue, Object newValue) { + IDiff diff; + if (oldValue == null || newValue == null) + diff = null; + else + diff = computeDiff(oldValue, newValue); + fireChange(source, diff); + } + }; + map.put(source, l); + FXBeanPropertyListenerSupport.hookListener(source, + propertyDescriptor.getName(), l); + } + + } + + protected void doRemoveFrom(Object source) { + ChangeListener<Object> l = map.get(source); + if (l != null) { + FXBeanPropertyListenerSupport.unhookListener(source, + propertyDescriptor.getName(), l); + } + } +}
\ No newline at end of file diff --git a/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/internal/FXBeanPropertyListenerSupport.java b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/internal/FXBeanPropertyListenerSupport.java new file mode 100755 index 000000000..0770c21bc --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/internal/FXBeanPropertyListenerSupport.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright (c) 2005, 2009 IBM Corporation and others. + * 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: + * IBM Corporation - initial API and implementation + * Matthew Hall - bug 118516 + *******************************************************************************/ +package org.eclipse.fx.databinding.internal; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IStatus; + +/** + * This is a helper that will hook up and listen for + * <code>PropertyChangeEvent</code> events for a set of target JavaBeans + * + * @since 1.0 + */ +public class FXBeanPropertyListenerSupport { + /** + * Start listen to target (if it supports the JavaBean property change + * listener pattern) + * + * @param bean + * @param propertyName + * @param listener + */ + public static void hookListener(Object bean, String propertyName, + ChangeListener<Object> listener) { + Assert.isNotNull(bean, "Bean cannot be null"); //$NON-NLS-1$ + Assert.isNotNull(listener, "Listener cannot be null"); //$NON-NLS-1$ + Assert.isNotNull(propertyName, "Property name cannot be null"); //$NON-NLS-1$ + processListener(bean, propertyName, listener, + /*"addPropertyChangeListener",*/ "Could not attach listener to ");//$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * Stop listen to target + * + * @param bean + * @param propertyName + * @param listener + */ + public static void unhookListener(Object bean, String propertyName, + ChangeListener<Object> listener) { + Assert.isNotNull(bean, "Bean cannot be null"); //$NON-NLS-1$ + Assert.isNotNull(listener, "Listener cannot be null"); //$NON-NLS-1$ + Assert.isNotNull(propertyName, "Property name cannot be null"); //$NON-NLS-1$ + + processListener( + bean, + propertyName, + listener, + /*"removePropertyChangeListener",*/ "Cound not remove listener from "); //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * Invokes the method for the provided <code>methodName</code> attempting to + * first use the method with the property name and then the unnamed version. + * + * @param bean + * object to invoke the method on + * @param methodName + * either addPropertyChangeListener or + * removePropertyChangeListener + * @param message + * string that will be prefixed to the target in an error message + * + * @return <code>true</code> if the method was invoked successfully + */ + @SuppressWarnings("unchecked") + private static boolean processListener(Object bean, String propertyName, + ChangeListener<Object> listener, /*String methodName,*/ String message) { + try { + Method method = bean.getClass().getMethod(propertyName+"Property"); + Object observable = method.invoke(bean); + if( observable instanceof ObservableValue<?> ) { + ((ObservableValue<Object>) observable).addListener(listener); + return true; + } else { + log(IStatus.WARNING, message, null); + } + + } catch (SecurityException e) { + // ignore + } catch (NoSuchMethodException e) { + log(IStatus.WARNING, message + bean, e); + } catch (IllegalArgumentException e) { + log(IStatus.WARNING, message + bean, e); + } catch (IllegalAccessException e) { + log(IStatus.WARNING, message + bean, e); + } catch (InvocationTargetException e) { + log(IStatus.WARNING, message + bean, e); + } + + return false; + } + + /** + * Logs a message to the Data Binding logger. + */ + private static void log(int severity, String message, Throwable throwable) { + /*if (BeansObservables.DEBUG) { + Policy.getLog().log( + new Status(severity, Policy.JFACE_DATABINDING, IStatus.OK, + message, throwable)); + }*/ + } +} diff --git a/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/internal/FXBeanValueProperty.java b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/internal/FXBeanValueProperty.java new file mode 100755 index 000000000..fc6541e72 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/internal/FXBeanValueProperty.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2008, 2009 Matthew Hall and others. + * 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: + * Matthew Hall - initial API and implementation (bug 194734) + * Matthew Hall - bug 195222, 264307, 265561 + ******************************************************************************/ + +package org.eclipse.fx.databinding.internal; + +import java.beans.PropertyDescriptor; + +import org.eclipse.core.databinding.observable.Diffs; +import org.eclipse.core.databinding.observable.IDiff; +import org.eclipse.core.databinding.property.INativePropertyListener; +import org.eclipse.core.databinding.property.ISimplePropertyListener; +import org.eclipse.core.databinding.property.value.SimpleValueProperty; + +/** + * @since 3.3 + * + */ +public class FXBeanValueProperty extends SimpleValueProperty { + private final PropertyDescriptor propertyDescriptor; + private final Class valueType; + + /** + * @param propertyDescriptor + * @param valueType + */ + public FXBeanValueProperty(PropertyDescriptor propertyDescriptor, + Class valueType) { + this.propertyDescriptor = propertyDescriptor; + this.valueType = valueType == null ? propertyDescriptor + .getPropertyType() : valueType; + } + + public Object getValueType() { + return valueType; + } + + protected Object doGetValue(Object source) { + return FXBeanPropertyHelper.readProperty(source, propertyDescriptor); + } + + protected void doSetValue(Object source, Object value) { + FXBeanPropertyHelper.writeProperty(source, propertyDescriptor, value); + } + + public INativePropertyListener adaptListener( + final ISimplePropertyListener listener) { + return new FXBeanPropertyListener(this, propertyDescriptor, listener) { + protected IDiff computeDiff(Object oldValue, Object newValue) { + return Diffs.createValueDiff(oldValue, newValue); + } + }; + } + + public String toString() { + String s = FXBeanPropertyHelper.propertyName(propertyDescriptor); + if (valueType != null) + s += "<" + FXBeanPropertyHelper.shortClassName(valueType) + ">"; //$NON-NLS-1$//$NON-NLS-2$ + return s; + } +} diff --git a/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/internal/FXBeanValuePropertyDecorator.java b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/internal/FXBeanValuePropertyDecorator.java new file mode 100755 index 000000000..20b1db402 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.databinding/src/org/eclipse/fx/databinding/internal/FXBeanValuePropertyDecorator.java @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright (c) 2008, 2010 Matthew Hall and others. + * 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: + * Matthew Hall - initial API and implementation (bug 195222) + * Matthew Hall - bug 264307 + ******************************************************************************/ + +package org.eclipse.fx.databinding.internal; + +import java.beans.PropertyDescriptor; + +import org.eclipse.core.databinding.observable.Realm; +import org.eclipse.core.databinding.observable.list.IObservableList; +import org.eclipse.core.databinding.observable.map.IObservableMap; +import org.eclipse.core.databinding.observable.set.IObservableSet; +import org.eclipse.core.databinding.observable.value.IObservableValue; +import org.eclipse.core.databinding.property.value.IValueProperty; +import org.eclipse.core.databinding.property.value.ValueProperty; +import org.eclipse.fx.databinding.IJFXBeanValueProperty; +import org.eclipse.fx.databinding.JFXBeanProperties; + + +/** + * @since 3.3 + * + */ +public class FXBeanValuePropertyDecorator extends ValueProperty implements + IJFXBeanValueProperty { + private final IValueProperty delegate; + private final PropertyDescriptor propertyDescriptor; + + /** + * @param delegate + * @param propertyDescriptor + */ + public FXBeanValuePropertyDecorator(IValueProperty delegate, + PropertyDescriptor propertyDescriptor) { + this.delegate = delegate; + this.propertyDescriptor = propertyDescriptor; + } + + public PropertyDescriptor getPropertyDescriptor() { + return propertyDescriptor; + } + + public Object getValueType() { + return delegate.getValueType(); + } + + protected Object doGetValue(Object source) { + return delegate.getValue(source); + } + + protected void doSetValue(Object source, Object value) { + delegate.setValue(source, value); + } + + public IJFXBeanValueProperty value(String propertyName) { + return value(propertyName, null); + } + + public IJFXBeanValueProperty value(String propertyName, Class valueType) { + Class beanClass = (Class) delegate.getValueType(); + return value(JFXBeanProperties.value(beanClass, propertyName, valueType)); + } + + public IJFXBeanValueProperty value(IJFXBeanValueProperty property) { + return new FXBeanValuePropertyDecorator(super.value(property), + property.getPropertyDescriptor()); + } + + /*public IBeanListProperty list(String propertyName) { + return list(propertyName, null); + } + + public IBeanListProperty list(String propertyName, Class elementType) { + Class beanClass = (Class) delegate.getValueType(); + return list(BeanProperties.list(beanClass, propertyName, elementType)); + } + + public IBeanListProperty list(IBeanListProperty property) { + return new BeanListPropertyDecorator(super.list(property), + property.getPropertyDescriptor()); + } + + public IBeanSetProperty set(String propertyName) { + return set(propertyName, null); + } + + public IBeanSetProperty set(String propertyName, Class elementType) { + Class beanClass = (Class) delegate.getValueType(); + return set(BeanProperties.set(beanClass, propertyName, elementType)); + } + + public IBeanSetProperty set(IBeanSetProperty property) { + return new BeanSetPropertyDecorator(super.set(property), + property.getPropertyDescriptor()); + } + + public IBeanMapProperty map(String propertyName) { + return map(propertyName, null, null); + } + + public IBeanMapProperty map(String propertyName, Class keyType, + Class valueType) { + Class beanClass = (Class) delegate.getValueType(); + return map(BeanProperties.map(beanClass, propertyName, keyType, + valueType)); + } + + public IBeanMapProperty map(IBeanMapProperty property) { + return new BeanMapPropertyDecorator(super.map(property), + property.getPropertyDescriptor()); + }*/ + + public IObservableValue observe(Object source) { + return new FXBeanObservableValueDecorator(delegate.observe(source), + propertyDescriptor); + } + + public IObservableValue observe(Realm realm, Object source) { + return new FXBeanObservableValueDecorator( + delegate.observe(realm, source), propertyDescriptor); + } + + public IObservableValue observeDetail(IObservableValue master) { + return new FXBeanObservableValueDecorator(delegate.observeDetail(master), + propertyDescriptor); + } + + /*public IObservableList observeDetail(IObservableList master) { + return new FXBeanObservableListDecorator(delegate.observeDetail(master), + propertyDescriptor); + } + + public IObservableMap observeDetail(IObservableSet master) { + return new FXBeanObservableMapDecorator(delegate.observeDetail(master), + propertyDescriptor); + } + + public IObservableMap observeDetail(IObservableMap master) { + return new FXBeanObservableMapDecorator(delegate.observeDetail(master), + propertyDescriptor); + }*/ + + public String toString() { + return delegate.toString(); + } +} |