Skip to content

Commit b97d137

Browse files
committed
Implement wrapping in table cells
1 parent 76afe99 commit b97d137

3 files changed

Lines changed: 113 additions & 3 deletions

File tree

src/main/kotlin/ladysnake/translationhelper/TranslationHelper.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ import ladysnake.translationhelper.view.TranslatorView
99
import tornadofx.App
1010
import tornadofx.find
1111
import tornadofx.launch
12+
import tornadofx.reloadStylesheetsOnFocus
1213
import java.io.File
1314

1415
class TranslationHelper: App(TranslatorView::class, AppStyle::class) {
1516
init {
17+
reloadStylesheetsOnFocus()
1618
TranslationLoader.registerAdapter(PlainLanguageMapAdapter())
1719
TranslationLoader.registerAdapter(JsonLanguageMapAdapter())
1820
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package ladysnake.translationhelper.view
2+
3+
import javafx.beans.property.ObjectProperty
4+
import javafx.beans.property.SimpleObjectProperty
5+
import javafx.event.EventHandler
6+
import javafx.scene.control.TableCell
7+
import javafx.scene.control.TextArea
8+
import javafx.scene.input.KeyCode
9+
import javafx.scene.input.KeyEvent
10+
import javafx.scene.text.Text
11+
import javafx.util.StringConverter
12+
13+
class TextAreaTableCell<S, T>(converter: StringConverter<T>? = null) : TableCell<S, T>() {
14+
15+
private fun resizeToFitText() {
16+
// Hack: to find out the text's actual height, we use a temporary Text widget
17+
val txt = Text("${this.text}\n")
18+
txt.wrappingWidth = this.tableColumn.width // not using this cell's width, it can be 0 during init
19+
this.prefHeight = txt.layoutBounds.height
20+
}
21+
22+
private var textArea: TextArea? = null
23+
private val converter: ObjectProperty<StringConverter<T>?> = SimpleObjectProperty(this, "converter")
24+
fun converterProperty(): ObjectProperty<StringConverter<T>?> {
25+
return converter
26+
}
27+
28+
fun setConverter(value: StringConverter<T>?) {
29+
converterProperty().set(value)
30+
}
31+
32+
fun getConverter(): StringConverter<T>? {
33+
return converterProperty().get()
34+
}
35+
36+
override fun startEdit() {
37+
if (!isEditable || !tableView.isEditable || !tableColumn.isEditable) {
38+
return
39+
}
40+
super.startEdit()
41+
if (isEditing) {
42+
val textArea = this.textArea ?: this.createTextArea().also { this.textArea = it }
43+
textArea.text = getItemText()
44+
this.text = null
45+
this.graphic = textArea
46+
textArea.selectAll()
47+
textArea.requestFocus()
48+
}
49+
}
50+
51+
private fun getItemText() = getConverter()?.toString(this.item) ?: this.item?.toString() ?: ""
52+
53+
private fun createTextArea(): TextArea {
54+
val converter = getConverter()
55+
val textArea = TextArea(getItemText())
56+
textArea.addEventFilter(KeyEvent.KEY_PRESSED) { t: KeyEvent ->
57+
if (t.code == KeyCode.ENTER && !t.isShiftDown) {
58+
checkNotNull(converter) {
59+
("Attempting to convert text input into Object, but provided "
60+
+ "StringConverter is null. Be sure to set a StringConverter "
61+
+ "in your cell factory.")
62+
}
63+
this.commitEdit(converter.fromString(textArea.text))
64+
t.consume()
65+
}
66+
}
67+
textArea.onKeyReleased = EventHandler { t: KeyEvent ->
68+
if (t.code == KeyCode.ESCAPE) {
69+
this.cancelEdit()
70+
t.consume()
71+
}
72+
}
73+
textArea.isWrapText = true
74+
return textArea
75+
}
76+
77+
override fun cancelEdit() {
78+
super.cancelEdit()
79+
this.text = getItemText()
80+
this.graphic = null
81+
}
82+
83+
override fun updateItem(item: T, empty: Boolean) {
84+
super.updateItem(item, empty)
85+
if (this.isEmpty) {
86+
this.text = null
87+
this.setGraphic(null)
88+
} else {
89+
if (this.isEditing) {
90+
val textArea = textArea
91+
if (textArea != null) {
92+
textArea.text = getItemText()
93+
}
94+
this.text = null
95+
this.setGraphic(textArea)
96+
} else {
97+
this.text = getItemText()
98+
this.setGraphic(null)
99+
}
100+
}
101+
this.resizeToFitText()
102+
}
103+
104+
init {
105+
styleClass.add("text-area-table-cell")
106+
setConverter(converter)
107+
}
108+
}

src/main/kotlin/ladysnake/translationhelper/view/TranslatorView.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import javafx.scene.control.SelectionMode
99
import javafx.scene.control.TableColumn
1010
import javafx.scene.control.TableView
1111
import javafx.scene.control.ToggleButton
12-
import javafx.scene.control.cell.TextFieldTableCell
1312
import javafx.scene.image.Image
1413
import javafx.stage.DirectoryChooser
1514
import javafx.stage.FileChooser
@@ -223,9 +222,10 @@ class TranslatorView : View() {
223222
source.editableProperty.bindBidirectional(selectedProperty())
224223
}
225224
setCellFactory {
226-
TextFieldTableCell<TranslationMap.TranslationRow, String>(DefaultStringConverter())
225+
TextAreaTableCell<TranslationMap.TranslationRow, String>(DefaultStringConverter()).apply {
226+
isWrapText = true
227+
}
227228
}
228229
}
229230
}
230-
231231
}

0 commit comments

Comments
 (0)