-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
81 changed files
with
7,022 additions
and
762 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,12 @@ This somewhat vague sentiment does not translate to quality! The code is clean, | |
|
||
These features are present in the latest release: | ||
|
||
* [ControlPropertyListener](https://github.com/CodeFX-org/LibFX/wiki/ControlPropertyListener): creating listeners for the property map of JavaFX controls | ||
* [ListenerHandle](https://github.com/CodeFX-org/LibFX/wiki/ListenerHandle): encapsulating an observable and a listener for easier add/remove of the listener | ||
* [Nestings](https://github.com/CodeFX-org/LibFX/wiki/Nestings): using all the power of JavaFX' properties for nested object aggregations | ||
* [SerializableOptional](https://github.com/CodeFX-org/LibFX/wiki/SerializableOptional): serializable wrapper for `Optional` | ||
* [WebViewHyperlinkListener](https://github.com/CodeFX-org/LibFX/wiki/WebViewHyperlinkListener): add hyperlink listeners to JavaFX' `WebView` | ||
|
||
|
||
## Documentation | ||
|
||
|
@@ -22,7 +27,25 @@ License details can be found in the *LICENSE* file in the project's root folder. | |
|
||
## Releases | ||
|
||
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. | ||
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. | ||
|
||
The current version is [0.2.0](http://search.maven.org/#artifactdetails|org.codefx.libfx|LibFX|0.2.0|jar): | ||
|
||
**Maven**: | ||
|
||
``` XML | ||
<dependency> | ||
<groupId>org.codefx.libfx</groupId> | ||
<artifactId>LibFX</artifactId> | ||
<version>0.2.0</version> | ||
</dependency> | ||
``` | ||
|
||
**Gradle**: | ||
|
||
``` | ||
compile 'org.codefx.libfx:LibFX:0.2.0' | ||
``` | ||
|
||
## Development | ||
|
||
|
@@ -42,7 +65,7 @@ The library has its home on [GitHub](https://github.com/CodeFX-org/LibFX) where | |
|
||
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/). | ||
|
||
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. | ||
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. | ||
|
||
## Contact | ||
|
||
|
@@ -51,4 +74,5 @@ CodeFX | |
|
||
Web: http://codefx.org <br> | ||
Mail: [email protected] <br> | ||
Key: http://keys.gnupg.net/pks/lookup?op=vindex&search=0xA47A795BA5BF8326 <br> | ||
Twitter: https://twitter.com/nipafx<br> | ||
PGP-Key: http://keys.gnupg.net/pks/lookup?op=vindex&search=0xA47A795BA5BF8326 <br> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
206 changes: 206 additions & 0 deletions
206
src/demo/java/org/codefx/libfx/control/ControlPropertyListenerDemo.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
package org.codefx.libfx.control; | ||
|
||
import java.util.function.Consumer; | ||
|
||
import javafx.collections.FXCollections; | ||
import javafx.collections.ObservableMap; | ||
|
||
import org.codefx.libfx.control.properties.ControlProperties; | ||
import org.codefx.libfx.control.properties.ControlPropertyListenerHandle; | ||
|
||
/** | ||
* Demonstrates how to use the {@link ControlPropertyListenerHandle} and its builder. | ||
*/ | ||
@SuppressWarnings("static-method") | ||
public class ControlPropertyListenerDemo { | ||
|
||
// #region CONSTRUCTION & MAIN | ||
|
||
/** | ||
* Creates a new demo. | ||
*/ | ||
private ControlPropertyListenerDemo() { | ||
// nothing to do | ||
} | ||
|
||
/** | ||
* Runs this demo. | ||
* | ||
* @param args | ||
* command line arguments (will not be used) | ||
*/ | ||
public static void main(String[] args) { | ||
ControlPropertyListenerDemo demo = new ControlPropertyListenerDemo(); | ||
|
||
demo.simpleCase(); | ||
demo.attachAndDetach(); | ||
|
||
demo.timeNoTypeCheck(); | ||
demo.timeWithTypeCheck(); | ||
|
||
demo.castVsTypeChecking(); | ||
} | ||
|
||
// #end CONSTRUCTION & MAIN | ||
|
||
// #region DEMOS | ||
|
||
/** | ||
* Demonstrates the simple case, in which a value processor is added for some key. | ||
*/ | ||
private void simpleCase() { | ||
ObservableMap<Object, Object> properties = FXCollections.observableHashMap(); | ||
|
||
// build and attach the listener | ||
ControlProperties.<String> on(properties) | ||
.forKey("Key") | ||
.processValue(value -> System.out.println(" -> " + value)) | ||
.buildAttached(); | ||
|
||
// set values of the correct type for the correct key | ||
System.out.print("Set \"Value\" for the correct key for the first time: "); | ||
properties.put("Key", "Value"); | ||
System.out.print("Set \"Value\" for the correct key for the second time: "); | ||
properties.put("Key", "Value"); | ||
|
||
// set values of the wrong type: | ||
System.out.println("Set an Integer for the correct key: ... (nothing will happen)"); | ||
properties.put("Key", 5); | ||
|
||
// set values for the wrong key | ||
System.out.println("Set \"Value\" for another key: ... (nothing will happen)"); | ||
properties.put("OtherKey", "Value"); | ||
|
||
System.out.println(); | ||
} | ||
|
||
/** | ||
* Demonstrates how a listener can be attached and detached. | ||
*/ | ||
private void attachAndDetach() { | ||
ObservableMap<Object, Object> properties = FXCollections.observableHashMap(); | ||
|
||
// build the listener (but don't attach it yet) and assign it to a variable | ||
ControlPropertyListenerHandle listener = ControlProperties.<String> on(properties) | ||
.forKey("Key") | ||
.processValue(value -> System.out.println(" -> " + value)) | ||
.buildDetached(); | ||
|
||
// set a value when the listener is not yet attached | ||
System.out.println( | ||
"Set \"ExistingValue\" before attaching the listener: ... (nothing will happen)"); | ||
properties.put("Key", "ExistingValue"); | ||
|
||
// now attach the listener | ||
System.out.print("When the listener is set, \"ExistingValue\" is processed and removed: "); | ||
listener.attach(); | ||
|
||
System.out.print("Set \"Value\": "); | ||
properties.put("Key", "Value"); | ||
|
||
// detach the listener | ||
listener.detach(); | ||
System.out.println("Set \"UnnoticedValue\" when the listener is detached: ... (nothing will happen)"); | ||
|
||
System.out.println(); | ||
} | ||
|
||
/** | ||
* Measures the time it takes to get a lot of {@link ClassCastException}. | ||
*/ | ||
private void timeNoTypeCheck() { | ||
ObservableMap<Object, Object> properties = FXCollections.observableHashMap(); | ||
|
||
Consumer<String> unreached = value -> { | ||
throw new RuntimeException("Should not be executed!"); | ||
}; | ||
|
||
// build and a attach a listener which does no type check before cast | ||
ControlProperties.<String> on(properties) | ||
.forKey("Key") | ||
.processValue(unreached) | ||
.buildAttached(); | ||
|
||
// add a couple of values of the wrong type to average the time that takes | ||
Integer valueOfWrongType = 5; | ||
int runs = (int) 1e5; | ||
long startTimeInNS = System.nanoTime(); | ||
|
||
for (int i = 0; i < runs; i++) | ||
properties.put("Key", valueOfWrongType); | ||
|
||
long endTimeInNS = System.nanoTime(); | ||
long timePerRunInNS = (endTimeInNS - startTimeInNS) / runs; | ||
System.out.println("For unchecked casts, adding a value of the wrong type takes ~" + timePerRunInNS + " ns."); | ||
|
||
System.out.println(); | ||
} | ||
|
||
/** | ||
* Demonstrates how type checking increases performance if values of an incorrect type are added frequently. | ||
*/ | ||
private void timeWithTypeCheck() { | ||
ObservableMap<Object, Object> properties = FXCollections.observableHashMap(); | ||
|
||
Consumer<String> unreached = value -> { | ||
throw new RuntimeException("Should not be executed!"); | ||
}; | ||
|
||
// build and a attach a listener which does a type check before cast | ||
ControlProperties.<String> on(properties) | ||
.forKey("Key") | ||
.forValueType(String.class) | ||
.processValue(unreached) | ||
.buildAttached(); | ||
|
||
// add a couple of values of the wrong type to average the time that takes | ||
Integer valueOfWrongType = 5; | ||
int runs = (int) 1e5; | ||
long startTimeInNS = System.nanoTime(); | ||
|
||
for (int i = 0; i < runs; i++) | ||
properties.put("Key", valueOfWrongType); | ||
|
||
long endTimeInNS = System.nanoTime(); | ||
long timePerRunInNS = (endTimeInNS - startTimeInNS) / runs; | ||
System.out.println("For checked casts, adding a value of the wrong type takes ~" + timePerRunInNS + " ns."); | ||
|
||
System.out.println(); | ||
} | ||
|
||
// #end DEMOS | ||
|
||
/** | ||
* TODO (nipa): I don't get it. The simple test below clearly shows that raising an exception takes about 6.000 ns. | ||
* So why the hell does {@link #timeNoTypeCheck()} run way faster than that?! | ||
* <p> | ||
* Some days later: I ran this again and discovered that the time difference is now very measurable and looks | ||
* correct. Perhaps some JVM optimization because I ran it so often? | ||
*/ | ||
private void castVsTypeChecking() { | ||
int runs = (int) 1e5; | ||
Object integer = 3; | ||
|
||
// CAST | ||
long start = System.nanoTime(); | ||
for (int i = 0; i < runs; i++) | ||
try { | ||
String string = (String) integer; | ||
System.out.println(string); | ||
} catch (ClassCastException e) { | ||
// do nothing | ||
} | ||
long end = System.nanoTime(); | ||
System.out.println("Each unchecked cast took ~" + (end - start) / runs + " ns."); | ||
|
||
// TYPE CHECK | ||
start = System.nanoTime(); | ||
for (int i = 0; i < runs; i++) | ||
if (String.class.isInstance(integer)) { | ||
String bar = (String) integer; | ||
System.out.println(bar); | ||
} | ||
end = System.nanoTime(); | ||
System.out.println("Each type check took ~" + (end - start) / runs + " ns."); | ||
} | ||
} |
Oops, something went wrong.