Skip to content

Commit fab2b57

Browse files
authored
Merge pull request #9 from bitkid/sascha/8-feature-request
Sascha/8 feature request
2 parents 21c3af6 + 35d2cb3 commit fab2b57

File tree

4 files changed

+104
-61
lines changed

4 files changed

+104
-61
lines changed

Diff for: src/main/kotlin/com/bitkid/itsfranking/ITSFData.kt

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ data class ITSFPlayer(
1919
fun hasSeniorRankings(): Boolean {
2020
return rankings[Categories.seniorDoubles] != null || rankings[Categories.seniorSingles] != null || rankings[Categories.classicSenior] != null
2121
}
22+
23+
fun pointsFor(category: Category) = rankings[category]?.points ?: 0
2224
}
2325

2426
data class PlayerNameWithResults(val playerName: String, val results: List<ITSFPlayer>)

Diff for: src/main/kotlin/com/bitkid/itsfranking/ITSFRankingApp.kt

+71-52
Original file line numberDiff line numberDiff line change
@@ -38,49 +38,64 @@ object ITSFRankingApp {
3838

3939
val version = getVersionFromJarFile()
4040

41-
4241
private val playerNameField = JTextField(50)
4342
private val itsfNoField = JTextField(50)
4443

45-
private val jTable = JTable(emptyModel()).apply {
44+
private val searchResultTable = JTable(emptySearchResultModel()).apply {
4645
cellSelectionEnabled = true
46+
autoCreateRowSorter = true
4747
}
4848

49-
private val jTableList = JTable(emptyListResultModelSingles()).apply {
49+
private val csvListTable = JTable(emptyCsvListModelSingles()).apply {
5050
cellSelectionEnabled = true
51+
autoCreateRowSorter = true
5152
}
5253

53-
private val jTableRanking = JTable(emptyRankingModel()).apply {
54+
private val rankingTable = JTable(emptyRankingModel()).apply {
5455
cellSelectionEnabled = true
56+
autoCreateRowSorter = true
5557
}
5658

5759
private val tabbedPane = JTabbedPane()
58-
59-
60-
private fun emptyModel() = ResultTableModel(listOf("itsf no.", "name", "country") + Categories.all.map { it.targetAudience })
61-
62-
private fun emptyRankingModel() = ResultTableModel(listOf("itsf no.", "name", "country", "rank", "points"))
63-
64-
private fun emptyListResultModelSingles() = ResultTableModel(listOf("player", "itsf name", "country", "points", "status"), true)
65-
private fun emptyListResultModelDoubles() =
66-
ResultTableModel(listOf("player1", "itsf name 1", "player2", "itsf name 2", "p1 country", "p1 points", "p1 status", "p2 country", "p2 points", "p2 status"), true)
60+
private fun emptySearchResultModel() = ResultTableModel(listOf("itsf no.", "name", "country") + Categories.all.map { it.targetAudience })
61+
private fun emptyRankingModel() = ResultTableModel(listOf("rank", "name", "country", "itsf no.", "points"))
62+
private fun emptyCsvListModelSingles() = ResultTableModel(listOf("player", "itsf name", "country", "points", "rank", "status"), true)
63+
private fun emptyCsvListModelDoubles() = DoublesListModel(
64+
listOf(
65+
"player1",
66+
"itsf name 1",
67+
"player2",
68+
"itsf name 2",
69+
"combined",
70+
"p1 country",
71+
"p1 points",
72+
"p1 rank",
73+
"p1 status",
74+
"p2 country",
75+
"p2 points",
76+
"p2 rank",
77+
"p2 status"
78+
)
79+
)
6780

6881
private fun showRanking(category: String) {
69-
if (checkRankingLoaded()) {
82+
if (checkITSFDataLoaded()) {
7083
val cat = Categories.all.single { it.targetAudience == category }
7184
val players = itsfPlayers.getSortedRanking(cat)
7285
val m = emptyRankingModel()
7386
players.forEach {
7487
val itsfRank = it.rankings.getValue(cat)
75-
val props = listOf(it.licenseNumber, it.name, it.country, itsfRank.rank.toString(), itsfRank.points.toString())
88+
listOf("rank", "name", "country", "itsf no.", "points")
89+
val props = listOf(itsfRank.rank, it.name, it.country, it.licenseNumber, itsfRank.points)
7690
m.addRow(props)
7791
}
78-
jTableRanking.model = m
92+
rankingTable.rowSorter = null
93+
rankingTable.model = m
7994
tabbedPane.selectedIndex = 2
8095
}
8196
}
8297

83-
private fun checkRankingLoaded(): Boolean {
98+
private fun checkITSFDataLoaded(): Boolean {
8499
if (!this::itsfPlayers.isInitialized) {
85100
JOptionPane.showMessageDialog(jFrame, "Load rankings first!", "Info", JOptionPane.INFORMATION_MESSAGE)
86101
return false
@@ -89,95 +104,99 @@ object ITSFRankingApp {
89104
}
90105

91106
private fun modelWithPlayers(players: Collection<ITSFPlayer>): ResultTableModel {
92-
val model = emptyModel()
93-
players.forEach { addPlayerToModel(model, it) }
107+
val model = emptySearchResultModel()
108+
players.forEach { addPlayerToSearchResultModel(model, it) }
94109
return model
95110
}
96111

97-
private suspend fun loadRanking(s: String) {
112+
private suspend fun loadITSFDATA(s: String) {
98113
// val rankings = ITSFPlayerDatabaseReader(topXPlayers = 2000).readTestRankings()
99114
val rankings = ITSFPlayerDatabaseReader(topXPlayers = 2000, tour = s).readRankings()
100115
itsfPlayers = ITSFPlayers(rankings)
101116
}
102117

103-
private fun searchLicenseNumber() {
104-
if (checkRankingLoaded()) {
118+
private fun searchForLicenseNumber() {
119+
if (checkITSFDataLoaded()) {
105120
val text = itsfNoField.text
106121
if (!text.isNullOrBlank()) {
107122
val player = itsfPlayers.getPlayer(text)
123+
searchResultTable.rowSorter = null
108124
if (player == null)
109-
jTable.model = emptyModel()
125+
searchResultTable.model = emptySearchResultModel()
110126
else
111-
jTable.model = modelWithPlayers(listOf(player))
127+
searchResultTable.model = modelWithPlayers(listOf(player))
112128
tabbedPane.selectedIndex = 0
113129
}
114130
}
115131
}
116132

117-
private fun searchByName() {
118-
if (checkRankingLoaded()) {
133+
private fun searchForName() {
134+
if (checkITSFDataLoaded()) {
119135
val text = playerNameField.text
120136
if (!text.isNullOrBlank()) {
121137
val player = itsfPlayers.find(text, true)
122-
jTable.model = modelWithPlayers(player)
138+
searchResultTable.rowSorter = null
139+
searchResultTable.model = modelWithPlayers(player)
123140
tabbedPane.selectedIndex = 0
124141
}
125142
}
126143
}
127144

128145

129-
private fun loadFile(file: File, charset: Charset, category: Category) {
146+
private fun loadCsvFile(file: File, charset: Charset, category: Category) {
130147
val listMatcher = ListMatcher(itsfPlayers)
131148
val model = if (category.type == CompetitionType.SINGLES) {
132-
val model = emptyListResultModelSingles()
149+
val model = emptyCsvListModelSingles()
133150
listMatcher.matchPlayer(file, charset, category).forEach {
134151
when (it.results.size) {
135-
0 -> model.addRow(listOf(it.playerName, null, null, null, "NOT_FOUND"))
152+
0 -> model.addRow(listOf(it.playerName, null, null, null, null, "NOT_FOUND"))
136153
1 -> {
137154
val player = it.results.single()
138-
model.addRow(listOf(it.playerName, player.name, player.country, player.rankings[category]?.points?.toString() ?: "0", "OK"))
155+
model.addRow(listOf(it.playerName, player.name, player.country, player.rankings[category]?.points ?: 0, player.rankings[category]?.rank, "OK"))
139156
}
140-
141-
else -> model.addRow(listOf(it.playerName, null, null, null, "MULTIPLE_MATCHES"))
157+
else -> model.addRow(listOf(it.playerName, null, null, null, null, "MULTIPLE_MATCHES"))
142158
}
143159
}
144160
model
145161
} else {
146-
val model = emptyListResultModelDoubles()
162+
val model = emptyCsvListModelDoubles()
147163
listMatcher.matchTeam(file, charset, category).forEach { pwr ->
148-
val list = mutableListOf<String?>(pwr.player1.playerName, pwr.player2.playerName)
164+
val list = mutableListOf<Any?>(pwr.player1.playerName, pwr.player2.playerName)
149165
val p1 = addPlayerToRow(list, category, pwr.player1)
150166
val p2 = addPlayerToRow(list, category, pwr.player2)
167+
val p1Points = p1?.pointsFor(category) ?: 0
168+
val p2Points = p2?.pointsFor(category) ?: 0
151169
list.add(1, p1?.name)
152170
list.add(3, p2?.name)
171+
list.add(4, p1Points + p2Points)
153172
model.addRow(list)
154173
}
155174
model
156175
}
157-
jTableList.model = model
176+
csvListTable.rowSorter = null
177+
csvListTable.model = model
158178
tabbedPane.selectedIndex = 1
159179
}
160180

161-
private fun addPlayerToRow(list: MutableList<String?>, category: Category, playerNameWithResults: PlayerNameWithResults): ITSFPlayer? {
181+
private fun addPlayerToRow(list: MutableList<Any?>, category: Category, playerNameWithResults: PlayerNameWithResults): ITSFPlayer? {
162182
return when (playerNameWithResults.results.size) {
163183
0 -> {
164-
list.addAll(listOf(null, null, "NOT_FOUND"))
184+
list.addAll(listOf(null, null, null, "NOT_FOUND"))
165185
null
166186
}
167187
1 -> {
168188
val player = playerNameWithResults.results.single()
169-
list.addAll(listOf(player.country, player.rankings[category]?.points?.toString() ?: "0", "OK"))
189+
list.addAll(listOf(player.country, player.rankings[category]?.points ?: 0, player.rankings[category]?.rank, "OK"))
170190
player
171191
}
172-
173192
else -> {
174-
list.addAll(listOf(null, null, "MULTIPLE_MATCHES"))
193+
list.addAll(listOf(null, null, null, "MULTIPLE_MATCHES"))
175194
null
176195
}
177196
}
178197
}
179198

180-
private fun addPlayerToModel(model: ResultTableModel, it: ITSFPlayer) {
199+
private fun addPlayerToSearchResultModel(model: ResultTableModel, it: ITSFPlayer) {
181200
val ranks = Categories.all.map { c ->
182201
val r = it.rankings[c]
183202
if (r == null)
@@ -190,22 +209,22 @@ object ITSFRankingApp {
190209
}
191210

192211

193-
private fun createPanel(frame: JFrame): JPanel {
212+
private fun createMainPanel(frame: JFrame): JPanel {
194213
jFrame = frame
195214
val panel = JPanel(MigLayout("wrap 2"))
196215

197216
panel.add(JLabel("Load ITSF Rankings"))
198-
panel.add(LoadITSFDataPanel { loadRanking(it) }, "growx")
217+
panel.add(LoadITSFDataPanel { loadITSFDATA(it) }, "growx")
199218

200219
val searchAction: Action = object : AbstractAction() {
201220
override fun actionPerformed(e: ActionEvent) {
202-
searchByName()
221+
searchForName()
203222
}
204223
}
205224

206225
val searchLicenseAction: Action = object : AbstractAction() {
207226
override fun actionPerformed(e: ActionEvent) {
208-
searchLicenseNumber()
227+
searchForLicenseNumber()
209228
}
210229
}
211230

@@ -225,13 +244,13 @@ object ITSFRankingApp {
225244
panel.add(JButton("Search").apply { addActionListener(searchLicenseAction) }, "growx")
226245

227246
panel.add(JLabel("Upload player list"))
228-
panel.add(LoadCsvPanel(::loadFile, ::checkRankingLoaded), "growx")
247+
panel.add(LoadCsvPanel(::loadCsvFile, ::checkITSFDataLoaded), "growx")
229248

230-
panel.add(JLabel("Results"))
249+
panel.add(JLabel("Data"))
231250

232-
tabbedPane.addTab("Search results", JScrollPane(jTable))
233-
tabbedPane.addTab("Player list", JScrollPane(jTableList))
234-
tabbedPane.addTab("Rankings", JScrollPane(jTableRanking))
251+
tabbedPane.addTab("Search results", JScrollPane(searchResultTable))
252+
tabbedPane.addTab("Player list", JScrollPane(csvListTable))
253+
tabbedPane.addTab("Rankings", JScrollPane(rankingTable))
235254
panel.add(tabbedPane, "growx, height :400:")
236255

237256
return panel
@@ -246,7 +265,7 @@ object ITSFRankingApp {
246265
ex.printStackTrace()
247266
}
248267
val frame = JFrame("ITSF Rankings ($version)")
249-
frame.contentPane.add(createPanel(frame))
268+
frame.contentPane.add(createMainPanel(frame))
250269
frame.pack()
251270
frame.isResizable = false
252271
frame.defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE

Diff for: src/main/kotlin/com/bitkid/itsfranking/ui/LoadCsvPanel.kt

+13-8
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@ import com.bitkid.itsfranking.Categories
44
import com.bitkid.itsfranking.Category
55
import com.bitkid.itsfranking.ITSFRankingApp
66
import com.bitkid.itsfranking.showLoadingDialog
7-
import kotlinx.coroutines.DelicateCoroutinesApi
8-
import kotlinx.coroutines.Dispatchers
9-
import kotlinx.coroutines.GlobalScope
10-
import kotlinx.coroutines.launch
7+
import kotlinx.coroutines.*
8+
import kotlinx.coroutines.swing.Swing
119
import net.miginfocom.swing.MigLayout
1210
import java.io.File
1311
import java.nio.charset.Charset
@@ -34,11 +32,18 @@ class LoadCsvPanel(private val load: (File, Charset, Category) -> Unit, private
3432
val r = fileChooser.showOpenDialog(ITSFRankingApp.jFrame)
3533
if (r == JFileChooser.APPROVE_OPTION) {
3634
val dialog = showLoadingDialog()
37-
currentDirectory = fileChooser.selectedFile.parentFile
38-
GlobalScope.launch(Dispatchers.IO) {
35+
val currentFile = fileChooser.selectedFile
36+
currentDirectory = currentFile.parentFile
37+
val job = GlobalScope.async(Dispatchers.IO) {
38+
load(
39+
currentFile,
40+
Charset.forName(charsetSelect.selectedItem!!.toString()),
41+
Categories.all.single { it.name == category.selectedItem!! }
42+
)
43+
}
44+
GlobalScope.launch(Dispatchers.Swing) {
3945
try {
40-
val file = fileChooser.selectedFile
41-
load(file, Charset.forName(charsetSelect.selectedItem!!.toString()), Categories.all.single { it.name == category.selectedItem!! })
46+
job.await()
4247
} catch (e: Exception) {
4348
dialog.dispose()
4449
JOptionPane.showMessageDialog(

Diff for: src/main/kotlin/com/bitkid/itsfranking/ui/ResultTableModel.kt

+18-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,27 @@ package com.bitkid.itsfranking.ui
33
import java.util.*
44
import javax.swing.table.DefaultTableModel
55

6-
class ResultTableModel(columns: List<String>, private val editable: Boolean = false) : DefaultTableModel(Vector(columns), 0) {
6+
open class ResultTableModel(columns: List<String>, private val editable: Boolean = false) : DefaultTableModel(Vector(columns), 0) {
77
override fun isCellEditable(row: Int, column: Int): Boolean {
88
return editable
99
}
10+
11+
override fun getColumnClass(c: Int): Class<*> {
12+
val javaClass = getValueAt(0, c).javaClass
13+
return javaClass
14+
}
15+
}
16+
17+
class DoublesListModel(columns: List<String>) : ResultTableModel(columns, true) {
18+
override fun setValueAt(aValue: Any?, row: Int, column: Int) {
19+
super.setValueAt(aValue, row, column)
20+
val current = (aValue as? Int) ?: 0
21+
if (column == 6) {
22+
super.setValueAt(((getValueAt(row, 10) as? Int) ?: 0) + current, row, 4)
23+
} else if (column == 10) {
24+
super.setValueAt(((getValueAt(row, 6) as? Int) ?: 0) + current, row, 4)
25+
}
26+
}
1027
}
1128

1229
fun ResultTableModel.addRow(data: List<*>) {

0 commit comments

Comments
 (0)