Skip to content

Commit 998aefa

Browse files
author
nicolaiparlog
committed
Merge branch 'develop'
2 parents 892d3f9 + 722fcec commit 998aefa

File tree

81 files changed

+7022
-762
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+7022
-762
lines changed

README.md

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ This somewhat vague sentiment does not translate to quality! The code is clean,
88

99
These features are present in the latest release:
1010

11+
* [ControlPropertyListener](https://github.com/CodeFX-org/LibFX/wiki/ControlPropertyListener): creating listeners for the property map of JavaFX controls
12+
* [ListenerHandle](https://github.com/CodeFX-org/LibFX/wiki/ListenerHandle): encapsulating an observable and a listener for easier add/remove of the listener
1113
* [Nestings](https://github.com/CodeFX-org/LibFX/wiki/Nestings): using all the power of JavaFX' properties for nested object aggregations
14+
* [SerializableOptional](https://github.com/CodeFX-org/LibFX/wiki/SerializableOptional): serializable wrapper for `Optional`
15+
* [WebViewHyperlinkListener](https://github.com/CodeFX-org/LibFX/wiki/WebViewHyperlinkListener): add hyperlink listeners to JavaFX' `WebView`
16+
1217

1318
## Documentation
1419

@@ -22,7 +27,25 @@ License details can be found in the *LICENSE* file in the project's root folder.
2227

2328
## Releases
2429

25-
Releases are published [here](https://github.com/CodeFX-org/LibFX/releases). The release notes also contain the Maven coordinates for each version available in Maven Central.
30+
Releases are published [on GitHub](https://github.com/CodeFX-org/LibFX/releases). The release notes also contain a link to the artifact in Maven Central and its coordinates.
31+
32+
The current version is [0.2.0](http://search.maven.org/#artifactdetails|org.codefx.libfx|LibFX|0.2.0|jar):
33+
34+
**Maven**:
35+
36+
``` XML
37+
<dependency>
38+
<groupId>org.codefx.libfx</groupId>
39+
<artifactId>LibFX</artifactId>
40+
<version>0.2.0</version>
41+
</dependency>
42+
```
43+
44+
**Gradle**:
45+
46+
```
47+
compile 'org.codefx.libfx:LibFX:0.2.0'
48+
```
2649

2750
## Development
2851

@@ -42,7 +65,7 @@ The library has its home on [GitHub](https://github.com/CodeFX-org/LibFX) where
4265

4366
I have a blog at [codefx.org](http://blog.codefx.org) where I might occasionally blog about **LibFX**. Those posts are filed under [their own tag](http://blog.codefx.org/tag/libfx/).
4467

45-
I use Eclipse and my project settings (like compiler warnings, formatter and save actions) can be found in the repository folder **.settings**. I do this to make it easier for contributors to cope with my obsession for warning free and consistently formatted code.
68+
I use Eclipse and my project settings (like compiler warnings, formatter and save actions) can be found in the repository folder **.settings**. I know this is a little unusual but it makes it easier for contributors to cope with my obsession for warning free and consistently formatted code.
4669

4770
## Contact
4871

@@ -51,4 +74,5 @@ CodeFX
5174

5275
Web: http://codefx.org <br>
5376
54-
Key: http://keys.gnupg.net/pks/lookup?op=vindex&search=0xA47A795BA5BF8326 <br>
77+
Twitter: https://twitter.com/nipafx<br>
78+
PGP-Key: http://keys.gnupg.net/pks/lookup?op=vindex&search=0xA47A795BA5BF8326 <br>

pom.xml

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>org.codefx.libfx</groupId>
88
<artifactId>LibFX</artifactId>
9-
<version>0.1.1</version>
9+
<version>0.2.0</version>
1010
<packaging>jar</packaging>
1111

1212
<!-- PROJECT META INFORMATION -->
@@ -67,17 +67,25 @@
6767

6868
<dependencies>
6969
<dependency>
70+
<!-- JUNIT for automated tests -->
7071
<groupId>junit</groupId>
7172
<artifactId>junit</artifactId>
7273
<version>4.11</version>
7374
<scope>test</scope>
7475
</dependency>
7576
<dependency>
77+
<!-- MOCKITO to mock instances for automated tests -->
7678
<groupId>org.mockito</groupId>
7779
<artifactId>mockito-all</artifactId>
7880
<version>1.9.5</version>
7981
<scope>test</scope>
8082
</dependency>
83+
<dependency>
84+
<!-- NEKOHTML to parse HTML to DOM Documents for tests -->
85+
<groupId>net.sourceforge.nekohtml</groupId>
86+
<artifactId>nekohtml</artifactId>
87+
<version>1.9.21</version>
88+
</dependency>
8189
</dependencies>
8290

8391
<build>
@@ -95,7 +103,7 @@
95103
<!-- specify using Java 8 -->
96104
<groupId>org.apache.maven.plugins</groupId>
97105
<artifactId>maven-compiler-plugin</artifactId>
98-
<version>3.1</version>
106+
<version>3.2</version>
99107
<configuration>
100108
<source>1.8</source>
101109
<target>1.8</target>
@@ -105,7 +113,7 @@
105113
<!-- create sources.jar -->
106114
<groupId>org.apache.maven.plugins</groupId>
107115
<artifactId>maven-source-plugin</artifactId>
108-
<version>2.3</version>
116+
<version>2.4</version>
109117
<executions>
110118
<execution>
111119
<id>attach-sources</id>
@@ -119,7 +127,7 @@
119127
<!-- create javadoc.jar -->
120128
<groupId>org.apache.maven.plugins</groupId>
121129
<artifactId>maven-javadoc-plugin</artifactId>
122-
<version>2.9.1</version>
130+
<version>2.10.1</version>
123131
<executions>
124132
<execution>
125133
<id>attach-javadocs</id>
@@ -128,6 +136,25 @@
128136
</goals>
129137
</execution>
130138
</executions>
139+
<configuration>
140+
<!-- force links to Java 8 documentation (should happen automatically
141+
but doesn't) -->
142+
<javaApiLinks>
143+
<property>
144+
<name>api_1.8</name>
145+
<value>https://docs.oracle.com/javase/8/docs/api/</value>
146+
</property>
147+
</javaApiLinks>
148+
<!-- add license notice -->
149+
<bottom>
150+
<![CDATA[
151+
This documentation is licensed under
152+
<a href="https://creativecommons.org/licenses/by/4.0/" title="CC-BY 4.0">CC-BY 4.0</a>,
153+
attributed to Nicolai Parlog from
154+
<a href="http://codefx.org" title="CodeFX">CodeFX</a>.
155+
]]>
156+
</bottom>
157+
</configuration>
131158
</plugin>
132159
<plugin>
133160
<!-- sign all jars and pom -->
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
package org.codefx.libfx.control;
2+
3+
import java.util.function.Consumer;
4+
5+
import javafx.collections.FXCollections;
6+
import javafx.collections.ObservableMap;
7+
8+
import org.codefx.libfx.control.properties.ControlProperties;
9+
import org.codefx.libfx.control.properties.ControlPropertyListenerHandle;
10+
11+
/**
12+
* Demonstrates how to use the {@link ControlPropertyListenerHandle} and its builder.
13+
*/
14+
@SuppressWarnings("static-method")
15+
public class ControlPropertyListenerDemo {
16+
17+
// #region CONSTRUCTION & MAIN
18+
19+
/**
20+
* Creates a new demo.
21+
*/
22+
private ControlPropertyListenerDemo() {
23+
// nothing to do
24+
}
25+
26+
/**
27+
* Runs this demo.
28+
*
29+
* @param args
30+
* command line arguments (will not be used)
31+
*/
32+
public static void main(String[] args) {
33+
ControlPropertyListenerDemo demo = new ControlPropertyListenerDemo();
34+
35+
demo.simpleCase();
36+
demo.attachAndDetach();
37+
38+
demo.timeNoTypeCheck();
39+
demo.timeWithTypeCheck();
40+
41+
demo.castVsTypeChecking();
42+
}
43+
44+
// #end CONSTRUCTION & MAIN
45+
46+
// #region DEMOS
47+
48+
/**
49+
* Demonstrates the simple case, in which a value processor is added for some key.
50+
*/
51+
private void simpleCase() {
52+
ObservableMap<Object, Object> properties = FXCollections.observableHashMap();
53+
54+
// build and attach the listener
55+
ControlProperties.<String> on(properties)
56+
.forKey("Key")
57+
.processValue(value -> System.out.println(" -> " + value))
58+
.buildAttached();
59+
60+
// set values of the correct type for the correct key
61+
System.out.print("Set \"Value\" for the correct key for the first time: ");
62+
properties.put("Key", "Value");
63+
System.out.print("Set \"Value\" for the correct key for the second time: ");
64+
properties.put("Key", "Value");
65+
66+
// set values of the wrong type:
67+
System.out.println("Set an Integer for the correct key: ... (nothing will happen)");
68+
properties.put("Key", 5);
69+
70+
// set values for the wrong key
71+
System.out.println("Set \"Value\" for another key: ... (nothing will happen)");
72+
properties.put("OtherKey", "Value");
73+
74+
System.out.println();
75+
}
76+
77+
/**
78+
* Demonstrates how a listener can be attached and detached.
79+
*/
80+
private void attachAndDetach() {
81+
ObservableMap<Object, Object> properties = FXCollections.observableHashMap();
82+
83+
// build the listener (but don't attach it yet) and assign it to a variable
84+
ControlPropertyListenerHandle listener = ControlProperties.<String> on(properties)
85+
.forKey("Key")
86+
.processValue(value -> System.out.println(" -> " + value))
87+
.buildDetached();
88+
89+
// set a value when the listener is not yet attached
90+
System.out.println(
91+
"Set \"ExistingValue\" before attaching the listener: ... (nothing will happen)");
92+
properties.put("Key", "ExistingValue");
93+
94+
// now attach the listener
95+
System.out.print("When the listener is set, \"ExistingValue\" is processed and removed: ");
96+
listener.attach();
97+
98+
System.out.print("Set \"Value\": ");
99+
properties.put("Key", "Value");
100+
101+
// detach the listener
102+
listener.detach();
103+
System.out.println("Set \"UnnoticedValue\" when the listener is detached: ... (nothing will happen)");
104+
105+
System.out.println();
106+
}
107+
108+
/**
109+
* Measures the time it takes to get a lot of {@link ClassCastException}.
110+
*/
111+
private void timeNoTypeCheck() {
112+
ObservableMap<Object, Object> properties = FXCollections.observableHashMap();
113+
114+
Consumer<String> unreached = value -> {
115+
throw new RuntimeException("Should not be executed!");
116+
};
117+
118+
// build and a attach a listener which does no type check before cast
119+
ControlProperties.<String> on(properties)
120+
.forKey("Key")
121+
.processValue(unreached)
122+
.buildAttached();
123+
124+
// add a couple of values of the wrong type to average the time that takes
125+
Integer valueOfWrongType = 5;
126+
int runs = (int) 1e5;
127+
long startTimeInNS = System.nanoTime();
128+
129+
for (int i = 0; i < runs; i++)
130+
properties.put("Key", valueOfWrongType);
131+
132+
long endTimeInNS = System.nanoTime();
133+
long timePerRunInNS = (endTimeInNS - startTimeInNS) / runs;
134+
System.out.println("For unchecked casts, adding a value of the wrong type takes ~" + timePerRunInNS + " ns.");
135+
136+
System.out.println();
137+
}
138+
139+
/**
140+
* Demonstrates how type checking increases performance if values of an incorrect type are added frequently.
141+
*/
142+
private void timeWithTypeCheck() {
143+
ObservableMap<Object, Object> properties = FXCollections.observableHashMap();
144+
145+
Consumer<String> unreached = value -> {
146+
throw new RuntimeException("Should not be executed!");
147+
};
148+
149+
// build and a attach a listener which does a type check before cast
150+
ControlProperties.<String> on(properties)
151+
.forKey("Key")
152+
.forValueType(String.class)
153+
.processValue(unreached)
154+
.buildAttached();
155+
156+
// add a couple of values of the wrong type to average the time that takes
157+
Integer valueOfWrongType = 5;
158+
int runs = (int) 1e5;
159+
long startTimeInNS = System.nanoTime();
160+
161+
for (int i = 0; i < runs; i++)
162+
properties.put("Key", valueOfWrongType);
163+
164+
long endTimeInNS = System.nanoTime();
165+
long timePerRunInNS = (endTimeInNS - startTimeInNS) / runs;
166+
System.out.println("For checked casts, adding a value of the wrong type takes ~" + timePerRunInNS + " ns.");
167+
168+
System.out.println();
169+
}
170+
171+
// #end DEMOS
172+
173+
/**
174+
* TODO (nipa): I don't get it. The simple test below clearly shows that raising an exception takes about 6.000 ns.
175+
* So why the hell does {@link #timeNoTypeCheck()} run way faster than that?!
176+
* <p>
177+
* Some days later: I ran this again and discovered that the time difference is now very measurable and looks
178+
* correct. Perhaps some JVM optimization because I ran it so often?
179+
*/
180+
private void castVsTypeChecking() {
181+
int runs = (int) 1e5;
182+
Object integer = 3;
183+
184+
// CAST
185+
long start = System.nanoTime();
186+
for (int i = 0; i < runs; i++)
187+
try {
188+
String string = (String) integer;
189+
System.out.println(string);
190+
} catch (ClassCastException e) {
191+
// do nothing
192+
}
193+
long end = System.nanoTime();
194+
System.out.println("Each unchecked cast took ~" + (end - start) / runs + " ns.");
195+
196+
// TYPE CHECK
197+
start = System.nanoTime();
198+
for (int i = 0; i < runs; i++)
199+
if (String.class.isInstance(integer)) {
200+
String bar = (String) integer;
201+
System.out.println(bar);
202+
}
203+
end = System.nanoTime();
204+
System.out.println("Each type check took ~" + (end - start) / runs + " ns.");
205+
}
206+
}

0 commit comments

Comments
 (0)