Skip to content

Commit 6c336e0

Browse files
Merge pull request #1182 from amazari/rxjava-javafx
Merge pull request #1182
2 parents cb60dd4 + 716de90 commit 6c336e0

File tree

8 files changed

+603
-0
lines changed

8 files changed

+603
-0
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
apply plugin: 'osgi'
2+
3+
sourceCompatibility = JavaVersion.VERSION_1_6
4+
targetCompatibility = JavaVersion.VERSION_1_6
5+
6+
dependencies {
7+
compile project(':rxjava-core')
8+
provided 'junit:junit-dep:4.10'
9+
provided 'org.mockito:mockito-core:1.8.5'
10+
}
11+
12+
javadoc {
13+
options {
14+
doclet = "org.benjchristensen.doclet.DocletExclude"
15+
docletpath = [rootProject.file('./gradle/doclet-exclude.jar')]
16+
stylesheetFile = rootProject.file('./gradle/javadocStyleSheet.css')
17+
windowTitle = "RxJava Javadoc ${project.version}"
18+
}
19+
options.addStringOption('top').value = '<h2 class="title" style="padding-top:40px">RxJava</h2>'
20+
}
21+
22+
jar {
23+
manifest {
24+
name = 'rxjava-javafx'
25+
instruction 'Bundle-Vendor', 'Netflix'
26+
instruction 'Bundle-DocURL', 'https://github.com/Netflix/RxJava'
27+
instruction 'Import-Package', '!org.junit,!junit.framework,!org.mockito.*,*'
28+
instruction 'Fragment-Host', 'com.netflix.rxjava.core'
29+
}
30+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package rx.javafx.sources;
2+
3+
import javafx.event.Event;
4+
import javafx.event.EventHandler;
5+
import javafx.event.EventType;
6+
import javafx.scene.Node;
7+
import rx.Observable;
8+
import rx.Subscriber;
9+
import rx.functions.Action0;
10+
import rx.schedulers.JavaFxScheduler;
11+
import rx.subscriptions.JavaFxSubscriptions;
12+
13+
public class NodeEventSource {
14+
/**
15+
* @see rx.observables.JavaFxObservable#fromNodeEvents
16+
*/
17+
public static <T extends Event> Observable<T> fromNodeEvents(final Node source, final EventType<T> eventType) {
18+
19+
return Observable.create(new Observable.OnSubscribe<T>() {
20+
@Override
21+
public void call(final Subscriber<? super T> subscriber) {
22+
final EventHandler<T> handler = new EventHandler<T>() {
23+
@Override
24+
public void handle(T t) {
25+
subscriber.onNext(t);
26+
}
27+
};
28+
29+
source.addEventHandler(eventType, handler);
30+
31+
subscriber.add(JavaFxSubscriptions.unsubscribeInEventDispatchThread(new Action0() {
32+
@Override
33+
public void call() {
34+
source.removeEventHandler(eventType, handler);
35+
}
36+
}));
37+
}
38+
39+
}).subscribeOn(JavaFxScheduler.getInstance());
40+
}
41+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package rx.javafx.sources;
2+
3+
import javafx.beans.value.ChangeListener;
4+
import javafx.beans.value.ObservableValue;
5+
import rx.Observable;
6+
import rx.Subscriber;
7+
import rx.functions.Action0;
8+
import rx.subscriptions.JavaFxSubscriptions;
9+
10+
public class ObservableValueSource {
11+
12+
/**
13+
* @see rx.observables.JavaFxObservable#fromObservableValue
14+
*/
15+
public static <T> Observable<T> fromObservableValue(final ObservableValue<T> fxObservable) {
16+
return Observable.create(new Observable.OnSubscribe<T>() {
17+
@Override
18+
public void call(final Subscriber<? super T> subscriber) {
19+
subscriber.onNext(fxObservable.getValue());
20+
21+
final ChangeListener<T> listener = new ChangeListener<T>() {
22+
@Override
23+
public void changed(final ObservableValue<? extends T> observableValue, final T prev, final T current) {
24+
subscriber.onNext(current);
25+
}
26+
};
27+
28+
fxObservable.addListener(listener);
29+
30+
subscriber.add(JavaFxSubscriptions.unsubscribeInEventDispatchThread(new Action0() {
31+
@Override
32+
public void call() {
33+
fxObservable.removeListener(listener);
34+
}
35+
}));
36+
37+
}
38+
});
39+
}
40+
41+
42+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* Copyright 2014 Netflix, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package rx.observables;
17+
18+
19+
import javafx.beans.value.ObservableValue;
20+
import javafx.event.Event;
21+
import javafx.event.EventType;
22+
import javafx.scene.Node;
23+
import rx.Observable;
24+
import rx.javafx.sources.NodeEventSource;
25+
import rx.javafx.sources.ObservableValueSource;
26+
27+
28+
public enum JavaFxObservable {
29+
; // no instances
30+
31+
32+
/**
33+
* Creates an observable corresponding to javafx ui events.
34+
*
35+
* @param node The target of the UI events.
36+
* @param eventType The type of the observed UI events
37+
* @return An Observable of UI events, appropriately typed
38+
*/
39+
public static <T extends Event> Observable<T> fromNodeEvents(final Node node, final EventType<T> eventType) {
40+
return NodeEventSource.fromNodeEvents(node, eventType);
41+
}
42+
43+
/**
44+
* Create an rx Observable from a javafx ObservableValue
45+
*
46+
* @param fxObservable the observed ObservableValue
47+
* @param <T> the type of the observed value
48+
* @return an Observable emitting values as the wrapped ObservableValue changes
49+
*/
50+
public static <T> Observable<T> fromObservableValue(final ObservableValue<T> fxObservable) {
51+
return ObservableValueSource.fromObservableValue(fxObservable);
52+
}
53+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/**
2+
* Copyright 2014 Netflix, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package rx.schedulers;
17+
18+
import javafx.animation.KeyFrame;
19+
import javafx.animation.Timeline;
20+
import javafx.application.Platform;
21+
import javafx.event.ActionEvent;
22+
import javafx.event.EventHandler;
23+
import javafx.util.Duration;
24+
import rx.Scheduler;
25+
import rx.Subscription;
26+
import rx.functions.Action0;
27+
import rx.subscriptions.BooleanSubscription;
28+
import rx.subscriptions.CompositeSubscription;
29+
import rx.subscriptions.Subscriptions;
30+
31+
import java.util.concurrent.TimeUnit;
32+
33+
/**
34+
* Executes work on the JavaFx UI thread.
35+
* This scheduler should only be used with actions that execute quickly.
36+
*/
37+
public final class JavaFxScheduler extends Scheduler {
38+
private static final JavaFxScheduler INSTANCE = new JavaFxScheduler();
39+
40+
/* package for unit test */JavaFxScheduler() {
41+
}
42+
43+
public static JavaFxScheduler getInstance() {
44+
return INSTANCE;
45+
}
46+
47+
private static void assertThatTheDelayIsValidForTheJavaFxTimer(long delay) {
48+
if (delay < 0 || delay > Integer.MAX_VALUE) {
49+
throw new IllegalArgumentException(String.format("The JavaFx timer only accepts non-negative delays up to %d milliseconds.", Integer.MAX_VALUE));
50+
}
51+
}
52+
53+
@Override
54+
public Worker createWorker() {
55+
return new InnerJavaFxScheduler();
56+
}
57+
58+
private static class InnerJavaFxScheduler extends Worker {
59+
60+
private final CompositeSubscription innerSubscription = new CompositeSubscription();
61+
62+
@Override
63+
public void unsubscribe() {
64+
innerSubscription.unsubscribe();
65+
}
66+
67+
@Override
68+
public boolean isUnsubscribed() {
69+
return innerSubscription.isUnsubscribed();
70+
}
71+
72+
@Override
73+
public Subscription schedule(final Action0 action, long delayTime, TimeUnit unit) {
74+
long delay = unit.toMillis(delayTime);
75+
assertThatTheDelayIsValidForTheJavaFxTimer(delay);
76+
final BooleanSubscription s = BooleanSubscription.create();
77+
78+
final Timeline timeline = new Timeline(new KeyFrame(Duration.millis(delay), new EventHandler<ActionEvent>() {
79+
80+
@Override
81+
public void handle(ActionEvent event) {
82+
if (innerSubscription.isUnsubscribed() || s.isUnsubscribed()) {
83+
return;
84+
}
85+
action.call();
86+
innerSubscription.remove(s);
87+
}
88+
}));
89+
90+
timeline.setCycleCount(1);
91+
timeline.play();
92+
93+
innerSubscription.add(s);
94+
95+
// wrap for returning so it also removes it from the 'innerSubscription'
96+
return Subscriptions.create(new Action0() {
97+
98+
@Override
99+
public void call() {
100+
timeline.stop();
101+
s.unsubscribe();
102+
innerSubscription.remove(s);
103+
}
104+
105+
});
106+
}
107+
108+
@Override
109+
public Subscription schedule(final Action0 action) {
110+
final BooleanSubscription s = BooleanSubscription.create();
111+
Platform.runLater(new Runnable() {
112+
@Override
113+
public void run() {
114+
if (innerSubscription.isUnsubscribed() || s.isUnsubscribed()) {
115+
return;
116+
}
117+
action.call();
118+
innerSubscription.remove(s);
119+
}
120+
});
121+
122+
innerSubscription.add(s);
123+
// wrap for returning so it also removes it from the 'innerSubscription'
124+
return Subscriptions.create(new Action0() {
125+
126+
@Override
127+
public void call() {
128+
s.unsubscribe();
129+
innerSubscription.remove(s);
130+
}
131+
132+
});
133+
}
134+
135+
}
136+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/**
2+
* Copyright 2014 Netflix, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package rx.subscriptions;
17+
18+
19+
import javafx.application.Platform;
20+
import rx.Scheduler.Worker;
21+
import rx.Subscription;
22+
import rx.functions.Action0;
23+
import rx.schedulers.JavaFxScheduler;
24+
25+
public final class JavaFxSubscriptions {
26+
27+
private JavaFxSubscriptions() {
28+
// no instance
29+
}
30+
31+
/**
32+
* Create an Subscription that always runs <code>unsubscribe</code> in the event dispatch thread.
33+
*
34+
* @param unsubscribe the action to be performed in the ui thread at un-subscription
35+
* @return an Subscription that always runs <code>unsubscribe</code> in the event dispatch thread.
36+
*/
37+
public static Subscription unsubscribeInEventDispatchThread(final Action0 unsubscribe) {
38+
return Subscriptions.create(new Action0() {
39+
@Override
40+
public void call() {
41+
if (Platform.isFxApplicationThread()) {
42+
unsubscribe.call();
43+
} else {
44+
final Worker inner = JavaFxScheduler.getInstance().createWorker();
45+
inner.schedule(new Action0() {
46+
@Override
47+
public void call() {
48+
unsubscribe.call();
49+
inner.unsubscribe();
50+
}
51+
});
52+
}
53+
}
54+
});
55+
}
56+
}

0 commit comments

Comments
 (0)