Skip to content
This repository was archived by the owner on Sep 28, 2024. It is now read-only.

Jdk10 fix: #1223 #1212 #1209 #1665 #1237

Open
wants to merge 22 commits into
base: jdk10
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
c749edf
:children_crossing: Change MapConversionListener's sourceToTarget ref…
Mar 14, 2020
4309331
Merge pull request #1183 from Thijsiez/improve-mapconversionlistener
edvin Mar 15, 2020
d300dd7
fix #1191
SchweinchenFuntik Mar 29, 2020
9934ffb
Merge pull request #1195 from SchweinchenFuntik/master
edvin Mar 29, 2020
4da1041
fix json.float
Camork Apr 16, 2020
17cebe6
Merge pull request #1218 from Camork/fix-float
edvin Apr 16, 2020
30ae80f
Update dependency version in README
HoldYourWaffle Apr 25, 2020
eea015c
Merge pull request #1225 from HoldYourWaffle/patch-3
ctadlock Apr 26, 2020
60239ae
Merge branches 'jdk10' and 'master' of https://github.com/edvin/torna…
SchweinchenFuntik May 3, 2020
871f753
fix: #1223
SchweinchenFuntik May 3, 2020
195793c
fix: #1212 #1209
SchweinchenFuntik May 4, 2020
9781649
up version kotlin and indicated explicit type
SchweinchenFuntik May 4, 2020
a51a1df
Downgrade FX. Motivation:
SchweinchenFuntik May 18, 2020
63b5aad
fix: #1165
SchweinchenFuntik May 18, 2020
f8c6842
doesn’t compile, I had to fix it.
SchweinchenFuntik May 18, 2020
fce9cfb
doesn’t compile, I had to fix it.
SchweinchenFuntik May 18, 2020
06995d1
Merge branch 'jdk10' of https://github.com/SchweinchenFuntik/tornadof…
SchweinchenFuntik May 18, 2020
7f27830
append locale: uk_UA, ru_UA
SchweinchenFuntik May 19, 2020
3646954
fix: #1236
SchweinchenFuntik May 23, 2020
142208c
uo fx version
SchweinchenFuntik May 28, 2020
5eb3034
fix: #1270, #1217. PR #1104 rolled back the previous fix #964
SchweinchenFuntik Sep 1, 2020
ed25060
rename checkAccessMethod and append doc
SchweinchenFuntik Sep 1, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ You also need a full rebuild of your code after a version upgrade. If you run in
```bash
mvn archetype:generate -DarchetypeGroupId=no.tornado \
-DarchetypeArtifactId=tornadofx-quickstart-archetype \
-DarchetypeVersion=1.7.17
-DarchetypeVersion=1.7.20
```

### Add TornadoFX to your project
Expand All @@ -79,14 +79,14 @@ mvn archetype:generate -DarchetypeGroupId=no.tornado \
<dependency>
<groupId>no.tornado</groupId>
<artifactId>tornadofx</artifactId>
<version>1.7.17</version>
<version>1.7.20</version>
</dependency>
```

### Gradle

```groovy
implementation 'no.tornado:tornadofx:1.7.17'
implementation 'no.tornado:tornadofx:1.7.20'
```

### Snapshots are published to Sonatype
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@

<properties>
<javafx.version>13</javafx.version>
<kotlin.version>1.3.61</kotlin.version>
<kotlin.version>1.3.72</kotlin.version>
<dokka.version>0.10.0</dokka.version>

<org.glassfish.javax.json.version>1.1.2</org.glassfish.javax.json.version>
Expand Down
55 changes: 44 additions & 11 deletions src/main/java/tornadofx/Collections.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ package tornadofx
import javafx.beans.Observable
import javafx.beans.WeakListener
import javafx.collections.*
import javafx.collections.transformation.FilteredList
import javafx.collections.transformation.SortedList
import tornadofx.FX.IgnoreParentBuilder.No
import tornadofx.FX.IgnoreParentBuilder.Once
import java.lang.ref.WeakReference
Expand Down Expand Up @@ -49,7 +51,7 @@ fun <T> observableListOf(collection: Collection<T>): ObservableList<T> = FXColle
/**
* Returns an empty new [ObservableList] with the given [extractor]. This list reports element updates.
*/
fun <T> observableListOf(extractor: (T)->Array<Observable>): ObservableList<T> = FXCollections.observableArrayList(extractor)
fun <T> observableListOf(extractor: (T) -> Array<Observable>): ObservableList<T> = FXCollections.observableArrayList(extractor)

/**
* Returns an empty new [ObservableSet]
Expand Down Expand Up @@ -372,15 +374,34 @@ fun <SourceType, TargetType> MutableList<TargetType>.bind(sourceList: Observable
}
}
val listener = ListConversionListener(this, ignoringParentConverter)
(this as? ObservableList<TargetType>)?.setAll(sourceList.map(ignoringParentConverter)) ?: run {
(this as? ObservableList<TargetType>)?.setAll(sourceList.map(ignoringParentConverter)) ?: run {
clear()
addAll(sourceList.map(ignoringParentConverter))
}
sourceList.removeListener(listener)
sourceList.addListener(listener)

when (sourceList) {
is FilteredList<SourceType> -> sourceList.source.addListener(invalidateList(sourceList))
is SortedList<SourceType> -> sourceList.source.addListener(invalidateList(sourceList))
is SortedFilteredList<SourceType> -> sourceList.sortedItems.source.addListener(invalidateList(sourceList))
}

return listener
}

fun <T> invalidateList(sourceList: ObservableList<T>): ListChangeListener<T> = object : ListChangeListener<T>, WeakListener {
private val ref: WeakReference<ObservableList<T>> = WeakReference(sourceList)

override fun onChanged(change: ListChangeListener.Change<out T>) {
val list = ref.get()
if (list == null) change.list.removeListener(this)
else while (change.next()) list.invalidate()
}

override fun wasGarbageCollected() = ref.get() == null
}

/**
* Bind this list to the given observable list by converting them into the correct type via the given converter.
* Changes to the observable list are synced.
Expand Down Expand Up @@ -425,13 +446,13 @@ fun <SourceTypeKey, SourceTypeValue, TargetType> MutableList<TargetType>.bind(
val listener = MapConversionListener(this, ignoringParentConverter)
if (this is ObservableList<*>) {
sourceMap.forEach { source ->
val converted = ignoringParentConverter(source.key,source.value)
listener.sourceToTarget[source] = converted
val converted = ignoringParentConverter(source.key, source.value)
listener.sourceToTarget[source.key] = converted
}
(this as ObservableList<TargetType>).setAll(listener.sourceToTarget.values)
} else {
clear()
addAll(sourceMap.map{ignoringParentConverter(it.key, it.value) })
addAll(sourceMap.map { ignoringParentConverter(it.key, it.value) })
}
sourceMap.removeListener(listener)
sourceMap.addListener(listener)
Expand Down Expand Up @@ -494,19 +515,23 @@ class MapConversionListener<SourceTypeKey, SourceTypeValue, TargetType>(
targetList: MutableList<TargetType>,
val converter: (SourceTypeKey, SourceTypeValue) -> TargetType
) : MapChangeListener<SourceTypeKey, SourceTypeValue>, WeakListener {

internal val targetRef: WeakReference<MutableList<TargetType>> = WeakReference(targetList)
internal val sourceToTarget = HashMap<Map.Entry<SourceTypeKey, SourceTypeValue>, TargetType>()
internal val sourceToTarget = HashMap<SourceTypeKey, TargetType>()

override fun onChanged(change: MapChangeListener.Change<out SourceTypeKey, out SourceTypeValue>) {
val list = targetRef.get()
if (list == null) {
change.map.removeListener(this)
sourceToTarget.clear()
} else {
if (change.wasRemoved()) {
list.remove(converter(change.key, change.valueRemoved))
list.remove(sourceToTarget[change.key])
sourceToTarget.remove(change.key)
}
if (change.wasAdded()) {
list.add(converter(change.key, change.valueAdded))
val converted = converter(change.key, change.valueAdded)
sourceToTarget[change.key] = converted
list.add(converted)
}
}
}
Expand Down Expand Up @@ -576,8 +601,16 @@ class SetConversionListener<SourceType, TargetType>(targetList: MutableList<Targ
}

fun <T> ObservableList<T>.invalidate() {
if (isNotEmpty()) this[0] = this[0]
// bug compiler: Error:(606, 31) Kotlin: Cannot access 'predicate': it is private in 'FilteredList'
@Suppress("UsePropertyAccessSyntax")
if (isNotEmpty()) when (this) {
is FilteredList<T> -> setPredicate(getPredicate())
is SortedList<T> -> setComparator(getComparator())
// invalidate FilteredList ?
is SortedFilteredList -> sortedItems.comparator = sortedItems.comparator
else -> this[0] = this[0]
}
}

@Deprecated("Use `observableListOf()` instead.", ReplaceWith("observableListOf(entries)", "tornadofx.observableListOf"))
fun <T> observableList(vararg entries: T) : ObservableList<T> = FXCollections.observableArrayList<T>(entries.toList())
fun <T> observableList(vararg entries: T): ObservableList<T> = FXCollections.observableArrayList<T>(entries.toList())
95 changes: 95 additions & 0 deletions src/main/java/tornadofx/Component.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import javafx.application.HostServices
import javafx.beans.binding.BooleanExpression
import javafx.beans.property.*
import javafx.beans.value.ChangeListener
import javafx.beans.value.ObservableValue
import javafx.collections.FXCollections
import javafx.concurrent.Task
import javafx.event.EventDispatchChain
Expand Down Expand Up @@ -1318,6 +1319,100 @@ fun <U : UIComponent> U.whenUndockedOnce(listener: (U) -> Unit) {
whenUndocked(wrapped)
}

/**
* This extension function will automatically bind to the managedProperty of the given node
* and will make sure that it is managed, if the given [expr] returning an observable boolean value equals true.
*
* @see https://docs.oracle.com/javase/8/javafx/api/javafx/scene/Node.html#managedProperty
*/
fun <T : UIComponent> T.managedWhen(expr: () -> ObservableValue<Boolean>): T = managedWhen(expr())

/**
* This extension function will automatically bind to the managedProperty of the given node
* and will make sure that it is managed, if the given [predicate] an observable boolean value equals true.
*
* @see https://docs.oracle.com/javase/8/javafx/api/javafx/scene/Node.html#managedProperty)
*/
fun <T : UIComponent> T.managedWhen(predicate: ObservableValue<Boolean>): T = apply {
root.managedWhen(predicate)
}

/**
* This extension function will automatically bind to the visibleProperty of the given node
* and will make sure that it is visible, if the given [predicate] an observable boolean value equals true.
*
* @see https://docs.oracle.com/javase/8/javafx/api/javafx/scene/Node.html#visibleProperty
*/
fun <T : UIComponent> T.visibleWhen(predicate: ObservableValue<Boolean>): T = apply {
root.visibleWhen(predicate)
}

/**
* This extension function will automatically bind to the visibleProperty of the given node
* and will make sure that it is visible, if the given [expr] returning an observable boolean value equals true.
*
* @see https://docs.oracle.com/javase/8/javafx/api/javafx/scene/Node.html#visibleProperty
*/
fun <T : UIComponent> T.visibleWhen(expr: () -> ObservableValue<Boolean>): T = visibleWhen(expr())

/**
* This extension function will make sure to hide the given node,
* if the given [expr] returning an observable boolean value equals true.
*/
fun <T : UIComponent> T.hiddenWhen(expr: () -> ObservableValue<Boolean>): T = hiddenWhen(expr())

/**
* This extension function will make sure to hide the given node,
* if the given [predicate] an observable boolean value equals true.
*/
fun <T : UIComponent> T.hiddenWhen(predicate: ObservableValue<Boolean>) = apply {
root.hiddenWhen(predicate)
}

/**
* This extension function will automatically bind to the disableProperty of the given node
* and will disable it, if the given [expr] returning an observable boolean value equals true.
*
* @see https://docs.oracle.com/javase/8/javafx/api/javafx/scene/Node.html#disable
*/
fun <T : UIComponent> T.disableWhen(expr: () -> ObservableValue<Boolean>): T = disableWhen(expr())

/**
* This extension function will automatically bind to the disableProperty of the given node
* and will disable it, if the given [predicate] observable boolean value equals true.
*
* @see https://docs.oracle.com/javase/8/javafx/api/javafx/scene/Node.html#disableProperty
*/
fun <T : UIComponent> T.disableWhen(predicate: ObservableValue<Boolean>) = apply {
root.disableWhen(predicate)
}

/**
* This extension function will make sure that the given UI component is enabled when ever,
* the given [expr] returning an observable boolean value equals true.
*/
fun <T : UIComponent> T.enableWhen(expr: () -> ObservableValue<Boolean>): T = enableWhen(expr())

/**
* This extension function will make sure that the given UI component is enabled when ever,
* the given [predicate] observable boolean value equals true.
*/
fun <T : UIComponent> T.enableWhen(predicate: ObservableValue<Boolean>) = apply {
root.enableWhen(predicate)
}

/**
* This extension function will make sure that the given UI component will only be visible in the scene graph,
* if the given [expr] returning an observable boolean value equals true.
*/
fun <T : UIComponent> T.removeWhen(predicate: ObservableValue<Boolean>) = root.removeWhen(predicate)

/**
* This extension function will make sure that the given UI component will only be visible in the scene graph,
* if the given [predicate] observable boolean value equals true.
*/
fun <T : UIComponent> T.removeWhen(expr: () -> ObservableValue<Boolean>): T = apply { root.removeWhen(expr()) }

abstract class Fragment @JvmOverloads constructor(title: String? = null, icon: Node? = null) : UIComponent(title, icon)

abstract class View @JvmOverloads constructor(title: String? = null, icon: Node? = null) : UIComponent(title, icon), ScopedInstance
Expand Down
9 changes: 3 additions & 6 deletions src/main/java/tornadofx/FX.kt
Original file line number Diff line number Diff line change
Expand Up @@ -679,12 +679,9 @@ fun EventTarget.getChildList(): MutableList<Node>? = when (this) {

@Suppress("UNCHECKED_CAST", "PLATFORM_CLASS_MAPPED_TO_KOTLIN")
private fun Parent.getChildrenReflectively(): MutableList<Node>? {
val getter = this.javaClass.findMethodByName("getChildren")
if (getter != null && java.util.List::class.java.isAssignableFrom(getter.returnType)) {
getter.isAccessible = true
return getter.invoke(this) as MutableList<Node>
}
return null
return javaClass.findMethodByName("getChildren")
?.takeIf { java.util.List::class.java.isAssignableFrom(it.returnType) && canOrSetAccessMethod(it) }
?.invoke(this) as MutableList<Node>
}

var Window.aboutToBeShown: Boolean
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/tornadofx/ItemControls.kt
Original file line number Diff line number Diff line change
Expand Up @@ -860,7 +860,7 @@ fun <T> TableView<T>.selectOnDrag() {
var startColumn = columns.first()

// Record start position and clear selection unless Control is down
addEventFilter(MouseEvent.MOUSE_PRESSED) {
addEventHandler(MouseEvent.MOUSE_PRESSED) {
startRow = 0

(it.pickResult.intersectedNode as? TableCell<*, *>)?.apply {
Expand All @@ -876,7 +876,7 @@ fun <T> TableView<T>.selectOnDrag() {
}

// Select items while dragging
addEventFilter(MouseEvent.MOUSE_DRAGGED) {
addEventHandler(MouseEvent.MOUSE_DRAGGED) {
(it.pickResult.intersectedNode as? TableCell<*, *>)?.apply {
if (items.size > index) {
if (selectionModel.isCellSelectionEnabled) {
Expand Down Expand Up @@ -936,12 +936,12 @@ class TableViewEditModel<S>(val tableView: TableView<S>) {

// Add columns and track changes to columns
tableView.columns.forEach(::addEventHandlerForColumn)
tableView.columns.addListener({ change: ListChangeListener.Change<out TableColumn<S, *>> ->
tableView.columns.addListener { change: ListChangeListener.Change<out TableColumn<S, *>> ->
while (change.next()) {
if (change.wasAdded())
change.addedSubList.forEach(::addEventHandlerForColumn)
}
})
}

// Remove dirty state for items removed from the TableView
val listenForRemovals = ListChangeListener<S> {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/tornadofx/Json.kt
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ fun JsonObject.getDouble(vararg key: String): Double = double(*key)!!
fun JsonObject.jsonNumber(vararg key: String): JsonNumber? = firstNonNull(*key) { getJsonNumber(it) }
fun JsonObject.getJsonNumber(vararg key: String): JsonNumber = jsonNumber(*key)!!

fun JsonObject.float(vararg key: String): Float? = firstNonNull(*key) { getFloat(it) }
fun JsonObject.float(vararg key: String): Float? = firstNonNull(*key) { double(it) }?.toFloat()
fun JsonObject.getFloat(vararg key: String): Float = float(*key)!!

fun JsonObject.bigdecimal(vararg key: String): BigDecimal? = jsonNumber(*key)?.bigDecimalValue()
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/tornadofx/Lib.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import javafx.scene.input.DataFormat
import javafx.scene.media.Media
import javafx.scene.media.MediaPlayer
import java.io.File
import java.lang.reflect.Method
import java.util.function.Predicate

/**
Expand Down Expand Up @@ -438,4 +439,13 @@ fun <T, R, C : MutableCollection<in R>> Sequence<T>.mapEachTo(destination: C, ac
*/
fun <T, R, C : MutableCollection<in R>> Array<T>.mapEachTo(destination: C, action: T.() -> R) = mapTo(destination, action)

fun Media.play() = MediaPlayer(this).play()
fun Media.play() = MediaPlayer(this).play()


/**
* Checks if a method is available for this, or tries to set access
*
* @return true if access for this this is or has been set
*/
// Java 9+
internal fun Any.canOrSetAccessMethod(method: Method): Boolean = method.canAccess(this) || method.trySetAccessible()
7 changes: 4 additions & 3 deletions src/main/java/tornadofx/Nodes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -925,10 +925,11 @@ fun Node.replaceWith(
return true
} else if (parent is Pane) {
val parent = parent as Pane
val attach = if (parent is BorderPane) {
val attach: (Node) -> Unit = if (parent is BorderPane) {
when (this) {
parent.top -> {
{ it: Node -> parent.top = it }
@Suppress("RedundantLambdaArrow") // bug compiler
{ it: Node -> parent.top = it }
}
parent.right -> {
{ parent.right = it }
Expand All @@ -943,7 +944,7 @@ fun Node.replaceWith(
{ parent.center = it }
}
else -> {
{ throw IllegalStateException("Child of BorderPane not found in BorderPane") }
{ it: Node -> throw IllegalStateException("Child of BorderPane not found in BorderPane") }
}
}
} else {
Expand Down
Loading