https://github.com/thomasnield/dirtyfx
Dirty state-tracking properties and collections for JavaFX
https://github.com/thomasnield/dirtyfx
java javafx kotlin tornadofx
Last synced: 2 months ago
JSON representation
Dirty state-tracking properties and collections for JavaFX
- Host: GitHub
- URL: https://github.com/thomasnield/dirtyfx
- Owner: thomasnield
- License: apache-2.0
- Created: 2018-06-06T18:29:45.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2020-03-19T12:53:22.000Z (about 5 years ago)
- Last Synced: 2025-03-22T18:11:24.166Z (3 months ago)
- Topics: java, javafx, kotlin, tornadofx
- Language: Kotlin
- Homepage:
- Size: 582 KB
- Stars: 34
- Watchers: 2
- Forks: 3
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README

### Dirty state-tracking properties and collections for JavaFX
I built this library out of tremendous need to keep track of dirty states in various JavaFX Properties and Collections, as well as rebaseline and reset against the dirty values.
You may likely use this library for CRUD operations, while allowing users the ability to review dirty edits before commiting or reverting them. For instance, you can bind the dirty states to red text formatting [like in this demo application](https://github.com/thomasnield/rxkotlinfx-tornadofx-demo).

Here are the current types:
```
DirtyBooleanProperty
DirtyIntegerProperty
DirtyLongProperty
DirtyObjectProperty
DirtyStringProperty
DirtyObservableList
DirtyObservableMap
DirtyObservableSet
DirtyListProperty
DirtySetProperty
DirtyMapProperty
DirtyReadOnlyWrapper
CompositeDirtyProperty
```Each of these dirty-tracking components have the same behaviors as their vanilla JavaFX counterparts, but have three additional methods/properties:
|Property/Method|Description|
|----|----|
|isDirtyProperty()|Read-only ObservableValue indicating whether this item is dirty|
|isDirty|Delegates to isDirtyProperty()|
|reset()|Sets the value back to the baseline value, removing dirty state|
|rebaseline()|Sets the baseline value to the current value, resetting dirty state|Note this was built in Kotlin, but works with both Java and Kotlin.
### Java Usage
```java
// Initialize with "Hello" being the baseline
DirtyObjectProperty myProperty = new DirtyObjectProperty<>("Hello");// Setting existing value should not change
myProperty.setValue("Hello");
Assert.assertFalse(myProperty.isDirty());// Changing the value will result in a dirty state
myProperty.setValue("World");
Assert.assertTrue(myProperty.isDirty());// Rebaselining will set the current value to be the new baseline
myProperty.rebaseline();
Assert.assertFalse(myProperty.isDirty());// Reset will restore the baseline as the current value, and no longer be dirty
myProperty.setValue("Greetings");
myProperty.reset();
Assert.assertEquals("World", myProperty.getValue());
Assert.assertFalse(myProperty.isDirty());
```### CompositeDirtyProperty
The `CompositeDirtyProperty` is a powerful utility that can manage dirty properties in sweeping fashion. All the `DirtyXXX` types in this library implement `DirtyProperty`, and the `CompositeDirtyProperty` accepts any number of `DirtyProperty` items and aggregates their state.
It can also `rebaseline()` or `reset()` all the items it is tracking.
```java
CompositeDirtyProperty composite = new CompositeDirtyProperty();DirtyObjectProperty property1 = new DirtyObjectProperty<>(3);
DirtyObjectProperty property2 = new DirtyObjectProperty<>(2);
DirtyObservableList list1 = new DirtyObservableList<>(Arrays.asList("Alpha","Beta","Gamma"));
DirtyObservableList list2 = new DirtyObservableList<>(Arrays.asList("Zeta","Theta","Eta"));composite.addAll(property1,property2,list1,list2);
Assert.assertFalse(composite.isDirty());property1.setValue(3);
Assert.assertFalse(composite.isDirty());property1.setValue(4);
Assert.assertTrue(composite.isDirty());composite.reset();
Assert.assertEquals(3, (int) property1.getValue());
Assert.assertFalse(composite.isDirty());list1.add("Delta");
Assert.assertTrue(composite.isDirty());composite.rebaseline();
Assert.assertFalse(composite.isDirty());
Assert.assertArrayEquals(list1.toArray(), new String[] {"Alpha", "Beta", "Gamma", "Delta"});
```### Example - CRUD Interface
Here is a simple CRUD-like user interface built with Kotlin and [TornadoFX](https://github.com/edvin/tornadofx).

```kotlin
import javafx.application.Application
import javafx.beans.property.SimpleObjectProperty
import javafx.collections.FXCollections
import javafx.geometry.Orientation
import javafx.scene.paint.Color
import org.nield.dirtyfx.beans.DirtyObjectProperty
import org.nield.dirtyfx.beans.DirtyStringProperty
import org.nield.dirtyfx.extensions.addTo
import org.nield.dirtyfx.tracking.CompositeDirtyProperty
import tornadofx.*
import java.time.LocalDatefun main(args: Array) {
Application.launch(MyApp::class.java, *args)
}class MyApp: App(MyView::class)
class MyView: View() {
val customers = FXCollections.observableArrayList(
Person("Samantha","Stuart",LocalDate.of(1981,12,4)),
Person("Tom","Marks",LocalDate.of(2001,1,23)),
Person("Stuart","Gills",LocalDate.of(1989,5,23)),
Person("Nicole","Williams",LocalDate.of(1998,8,11))
)val selectedCustomer = SimpleObjectProperty()
override val root = borderpane {
left = toolbar {
orientation = Orientation.VERTICALbutton("RESET") {
setOnAction {
selectedCustomer.get()?.reset()
}
}button("SAVE") {
setOnAction {
selectedCustomer.get()?.save()
}
}
}center = tableview(customers) {
selectedCustomer.bind(selectionModel.selectedItemProperty())
column("FIRST NAME", Person::firstNameProperty) {
makeEditable()
cellDecorator {
rowItem.firstNameProperty.isDirtyProperty().addListener { o, oldValue, newValue ->
textFill = if (newValue) Color.RED else Color.BLACK
}
}
}column("LAST NAME", Person::lastNameProperty) {
makeEditable()
cellDecorator {
rowItem.lastNameProperty.isDirtyProperty().addListener { o, oldValue, newValue ->
textFill = if (newValue) Color.RED else Color.BLACK
}
}
}column("BIRTHDAY", Person::birthdayProperty) {
makeEditable()
cellDecorator {
rowItem.birthdayProperty.isDirtyProperty().addListener { o, oldValue, newValue ->
textFill = if (newValue) Color.RED else Color.BLACK
}
}
}column("IS DIRTY", Person::isDirtyProperty)
isEditable = true
}
}
}class Person(firstName: String, lastName: String, birthday: LocalDate) {
val isDirtyProperty = CompositeDirtyProperty()
val isDirty by isDirtyPropertyval firstNameProperty = DirtyStringProperty(firstName).addTo(isDirtyProperty)
var firstName by firstNamePropertyval lastNameProperty = DirtyStringProperty(lastName).addTo(isDirtyProperty)
var lastName by lastNamePropertyval birthdayProperty = DirtyObjectProperty(birthday).addTo(isDirtyProperty)
var birthday by birthdayPropertyfun reset() = isDirtyProperty.reset()
fun save() = isDirtyProperty.rebaseline()
}
```### Dependencies
**Maven**
```xml
org.nield
dirtyfx
0.1.2```
**Gradle**
```groovy
compile 'org.nield:dirtyfx:0.1.2'
```