22
22
import java .awt .Component ;
23
23
import java .awt .GridLayout ;
24
24
import java .awt .Image ;
25
- import java .util .ArrayList ;
26
25
import java .util .Arrays ;
27
26
import java .util .HashMap ;
28
27
import java .util .List ;
42
41
import javax .swing .table .JTableHeader ;
43
42
import javax .swing .table .TableCellRenderer ;
44
43
import javax .swing .table .TableColumn ;
44
+ import org .jetbrains .annotations .NotNull ;
45
45
46
46
class StatPanel extends JPanel implements GameDataChangeListener {
47
47
private static final long serialVersionUID = 4340684166664492498L ;
@@ -66,7 +66,7 @@ class StatPanel extends JPanel implements GameDataChangeListener {
66
66
protected void initLayout () {
67
67
final boolean hasTech =
68
68
!TechAdvance .getTechAdvances (gameData .getTechnologyFrontier (), null ).isEmpty ();
69
- // do no include a grid box for tech if there is no tech
69
+ // do not include a grid box for tech if there is no tech
70
70
setLayout (new GridLayout ((hasTech ? 2 : 1 ), 1 ));
71
71
add (new JScrollPane (createPlayersTable ()));
72
72
// if no technologies, do not show the tech table
@@ -80,9 +80,9 @@ private JTable createPlayersTable() {
80
80
statsTable .getTableHeader ().setReorderingAllowed (false );
81
81
// By default, right-align columns and their headers.
82
82
((DefaultTableCellRenderer ) statsTable .getTableHeader ().getDefaultRenderer ())
83
- .setHorizontalAlignment (JLabel .RIGHT );
83
+ .setHorizontalAlignment (SwingConstants .RIGHT );
84
84
((DefaultTableCellRenderer ) statsTable .getDefaultRenderer (String .class ))
85
- .setHorizontalAlignment (JLabel .RIGHT );
85
+ .setHorizontalAlignment (SwingConstants .RIGHT );
86
86
final TableColumn leftColumn = statsTable .getColumnModel ().getColumn (0 );
87
87
leftColumn .setPreferredWidth (175 );
88
88
// The left column should be left-aligned. Override the renderers for it to defaults.
@@ -107,9 +107,22 @@ private JTable createTechTable() {
107
107
value .setToolTipText (player );
108
108
column .setHeaderValue (value );
109
109
}
110
+ // show tooltip for technology names
111
+ final TableCellRenderer techNameComponentRenderer = new TechNameComponentRenderer ();
112
+ final TableColumn techNameColumn = techTable .getColumnModel ().getColumn (0 );
113
+ techNameColumn .setHeaderRenderer (techNameComponentRenderer );
114
+ techNameColumn .setCellRenderer (techNameComponentRenderer );
110
115
return techTable ;
111
116
}
112
117
118
+ static final class TechNameComponentRenderer extends DefaultTableCellRenderer {
119
+ @ Override
120
+ public void setValue (Object aValue ) {
121
+ setToolTipText (aValue .toString ());
122
+ super .setValue (aValue );
123
+ }
124
+ }
125
+
113
126
public void setGameData (final GameData data ) {
114
127
gameData .removeDataChangeListener (this );
115
128
gameData = data ;
@@ -179,40 +192,38 @@ class StatTableModel extends AbstractTableModel {
179
192
}
180
193
181
194
void setStatColumns () {
182
- stats = new IStat [] {new PuStat (), new ProductionStat (), new UnitsStat (), new TuvStat ()};
195
+ final List <IStat > statsList =
196
+ Arrays .asList (new PuStat (), new ProductionStat (), new UnitsStat (), new TuvStat ());
183
197
if (gameData .getMap ().getTerritories ().stream ().anyMatch (Matches .territoryIsVictoryCity ())) {
184
- final List <IStat > stats = new ArrayList <>(List .of (StatPanel .this .stats ));
185
- stats .add (new VictoryCityStat ());
186
- StatPanel .this .stats = stats .toArray (new IStat [0 ]);
198
+ statsList .add (new VictoryCityStat ());
187
199
}
188
200
// only add the vps in pacific
189
201
if (Properties .getPacificTheater (gameData .getProperties ())) {
190
- final List <IStat > stats = new ArrayList <>(List .of (StatPanel .this .stats ));
191
- stats .add (new VpStat ());
192
- StatPanel .this .stats = stats .toArray (new IStat [0 ]);
202
+ statsList .add (new VpStat ());
193
203
}
204
+ StatPanel .this .stats = statsList .toArray (new IStat [0 ]);
194
205
}
195
206
196
207
private synchronized void loadData () {
197
208
// copy so that the object doesn't change underneath us
198
- final GameData gameData = StatPanel .this .gameData ;
199
- try (GameData .Unlocker ignored = gameData .acquireReadLock ()) {
200
- final List <GamePlayer > players = gameData .getPlayerList ().getSortedPlayers ();
201
- final List <String > alliances = getAlliancesToShow (gameData .getAllianceTracker ());
209
+ final GameData gameDataSync = StatPanel .this .gameData ;
210
+ try (GameData .Unlocker ignored = gameDataSync .acquireReadLock ()) {
211
+ final List <GamePlayer > players = gameDataSync .getPlayerList ().getSortedPlayers ();
212
+ final List <String > alliances = getAlliancesToShow (gameDataSync .getAllianceTracker ());
202
213
collectedData = new String [players .size () + alliances .size ()][stats .length + 1 ];
203
214
int row = 0 ;
204
215
for (final GamePlayer player : players ) {
205
216
collectedData [row ][0 ] = player .getName ();
206
217
for (int i = 0 ; i < stats .length ; i ++) {
207
- double value = stats [i ].getValue (player , gameData , uiContext .getMapData ());
218
+ double value = stats [i ].getValue (player , gameDataSync , uiContext .getMapData ());
208
219
collectedData [row ][i + 1 ] = IStat .DECIMAL_FORMAT .format (value );
209
220
}
210
221
row ++;
211
222
}
212
223
for (final String alliance : alliances ) {
213
224
collectedData [row ][0 ] = "<html><b>" + alliance ;
214
225
for (int i = 0 ; i < stats .length ; i ++) {
215
- double value = stats [i ].getValue (alliance , gameData , uiContext .getMapData ());
226
+ double value = stats [i ].getValue (alliance , gameDataSync , uiContext .getMapData ());
216
227
collectedData [row ][i + 1 ] = IStat .DECIMAL_FORMAT .format (value );
217
228
}
218
229
row ++;
@@ -228,7 +239,7 @@ private List<String> getAlliancesToShow(AllianceTracker tracker) {
228
239
}
229
240
230
241
/*
231
- * Re-calcs the underlying data in a lazy manner.
242
+ * Re-calculations the underlying data in a lazy manner.
232
243
* Limitation: This is not a thread-safe implementation.
233
244
*/
234
245
@ Override
@@ -287,33 +298,40 @@ class TechTableModel extends AbstractTableModel {
287
298
for (int i = 0 ; i < colList .length ; i ++) {
288
299
colMap .put (colList [i ], i + 1 );
289
300
}
301
+ data = getDataAndInitRowMap ();
302
+ clearAdvances ();
303
+ }
304
+
305
+ private synchronized String [] @ NotNull [] getDataAndInitRowMap () {
306
+ final String [][] dataTable ;
290
307
boolean useTech = false ;
291
308
// copy so that the object doesn't change underneath us
292
- final GameData gameData = StatPanel .this .gameData ;
293
- try (GameData .Unlocker ignored = gameData .acquireReadLock ()) {
294
- final int numTechs = TechAdvance .getTechAdvances (gameData .getTechnologyFrontier ()).size ();
295
- if (gameData .getResourceList ().getResource (Constants .TECH_TOKENS ) != null ) {
309
+ final GameData gameDataSync = StatPanel .this .gameData ;
310
+ try (GameData .Unlocker ignored = gameDataSync .acquireReadLock ()) {
311
+ final int numTechs =
312
+ TechAdvance .getTechAdvances (gameDataSync .getTechnologyFrontier ()).size ();
313
+ if (gameDataSync .getResourceList ().getResource (Constants .TECH_TOKENS ) != null ) {
296
314
useTech = true ;
297
- data = new String [numTechs + 1 ][colList .length + 2 ];
315
+ dataTable = new String [numTechs + 1 ][colList .length + 2 ];
298
316
} else {
299
- data = new String [numTechs ][colList .length + 1 ];
317
+ dataTable = new String [numTechs ][colList .length + 1 ];
300
318
}
301
319
}
302
320
/* Load the technology -> row mapping */
303
321
int row = 0 ;
304
322
if (useTech ) {
305
323
rowMap .put ("Tokens" , row );
306
- data [row ][0 ] = "Tokens" ;
324
+ dataTable [row ][0 ] = "Tokens" ;
307
325
row ++;
308
326
}
309
327
final List <TechAdvance > techAdvances =
310
- TechAdvance .getTechAdvances (gameData .getTechnologyFrontier (), null );
328
+ TechAdvance .getTechAdvances (gameDataSync .getTechnologyFrontier (), null );
311
329
for (final TechAdvance tech : techAdvances ) {
312
330
rowMap .put (tech .getName (), row );
313
- data [row ][0 ] = tech .getName ();
331
+ dataTable [row ][0 ] = tech .getName ();
314
332
row ++;
315
333
}
316
- clearAdvances () ;
334
+ return dataTable ;
317
335
}
318
336
319
337
private void clearAdvances () {
@@ -334,34 +352,34 @@ private void initColList() {
334
352
Arrays .sort (colList );
335
353
}
336
354
337
- void update () {
355
+ synchronized void update () {
338
356
clearAdvances ();
339
357
// copy so that the object doesn't change underneath us
340
- final GameData gameData = StatPanel .this .gameData ;
341
- try (GameData .Unlocker ignored = gameData .acquireReadLock ()) {
342
- for (final GamePlayer pid : gameData .getPlayerList ().getPlayers ()) {
358
+ final GameData gameDataSync = StatPanel .this .gameData ;
359
+ try (GameData .Unlocker ignored = gameDataSync .acquireReadLock ()) {
360
+ for (final GamePlayer pid : gameDataSync .getPlayerList ().getPlayers ()) {
343
361
if (colMap .get (pid .getName ()) == null ) {
344
362
throw new IllegalStateException (
345
363
"Unexpected player in GameData.getPlayerList()" + pid .getName ());
346
364
}
347
365
final int col = colMap .get (pid .getName ());
348
366
int row = 0 ;
349
- if (gameData .getResourceList ().getResource (Constants .TECH_TOKENS ) != null ) {
367
+ if (gameDataSync .getResourceList ().getResource (Constants .TECH_TOKENS ) != null ) {
350
368
final int tokens = pid .getResources ().getQuantity (Constants .TECH_TOKENS );
351
369
data [row ][col ] = Integer .toString (tokens );
352
370
}
353
371
final List <TechAdvance > advancesAll =
354
- TechAdvance .getTechAdvances (gameData .getTechnologyFrontier ());
372
+ TechAdvance .getTechAdvances (gameDataSync .getTechnologyFrontier ());
355
373
final List <TechAdvance > has =
356
- TechAdvance .getTechAdvances (gameData .getTechnologyFrontier (), pid );
374
+ TechAdvance .getTechAdvances (gameDataSync .getTechnologyFrontier (), pid );
357
375
for (final TechAdvance advance : advancesAll ) {
358
376
if (!has .contains (advance )) {
359
377
row = rowMap .get (advance .getName ());
360
378
data [row ][col ] = "-" ;
361
379
}
362
380
}
363
381
for (final TechAdvance advance :
364
- TechTracker .getCurrentTechAdvances (pid , gameData .getTechnologyFrontier ())) {
382
+ TechTracker .getCurrentTechAdvances (pid , gameDataSync .getTechnologyFrontier ())) {
365
383
row = rowMap .get (advance .getName ());
366
384
data [row ][col ] = "X" ;
367
385
}
@@ -378,7 +396,7 @@ public String getColumnName(final int col) {
378
396
}
379
397
380
398
/*
381
- * Recalcs the underlying data in a lazy manner.
399
+ * Recalculations the underlying data in a lazy manner.
382
400
* Limitation: This is not a thread-safe implementation.
383
401
*/
384
402
@ Override
0 commit comments