25
25
import java .util .ArrayList ;
26
26
import java .util .Arrays ;
27
27
import java .util .Collection ;
28
+ import java .util .Collections ;
28
29
import java .util .List ;
29
30
import java .util .Map ;
30
31
import java .util .function .Predicate ;
34
35
import javax .swing .JPanel ;
35
36
import javax .swing .JScrollPane ;
36
37
import javax .swing .SwingUtilities ;
38
+ import org .jetbrains .annotations .NotNull ;
37
39
import org .triplea .java .collections .CollectionUtils ;
38
40
import org .triplea .swing .SwingComponents ;
39
41
40
42
class PlacePanel extends AbstractMovePanel implements GameDataChangeListener {
41
43
private static final long serialVersionUID = -4411301492537704785L ;
42
44
private final JLabel leftToPlaceLabel = createIndentedLabel ();
43
- private PlaceData placeData ;
45
+ private transient PlaceData placeData ;
44
46
45
47
private final SimpleUnitPanel unitsToPlacePanel ;
46
48
47
49
private GamePlayer lastPlayer ;
48
50
private boolean postProductionStep ;
49
51
50
- private final MapSelectionListener placeMapSelectionListener =
52
+ private final transient MapSelectionListener placeMapSelectionListener =
51
53
new DefaultMapSelectionListener () {
54
+
55
+ private PlaceableUnits getUnitsToPlace (final Territory territory ) {
56
+ try (GameData .Unlocker ignored = getData ().acquireReadLock ()) {
57
+ // not our territory
58
+ if (!territory .isWater () && !territory .isOwnedBy (getCurrentPlayer ())) {
59
+ if (GameStepPropertiesHelper .isBid (getData ())) {
60
+ final PlayerAttachment pa = PlayerAttachment .get (territory .getOwner ());
61
+ if ((pa == null || !pa .getGiveUnitControl ().contains (getCurrentPlayer ()))
62
+ && !territory .anyUnitsMatch (Matches .unitIsOwnedBy (getCurrentPlayer ()))) {
63
+ return new PlaceableUnits ();
64
+ }
65
+ } else {
66
+ return new PlaceableUnits ();
67
+ }
68
+ }
69
+ // get the units that can be placed on this territory.
70
+ Collection <Unit > units = getCurrentPlayer ().getUnits ();
71
+ if (territory .isWater ()) {
72
+ GameProperties properties = getData ().getProperties ();
73
+ if (!(Properties .getProduceFightersOnCarriers (properties )
74
+ || Properties .getProduceNewFightersOnOldCarriers (properties )
75
+ || Properties .getLhtrCarrierProductionRules (properties )
76
+ || GameStepPropertiesHelper .isBid (getData ()))) {
77
+ units = CollectionUtils .getMatches (units , Matches .unitIsSea ());
78
+ } else {
79
+ final Predicate <Unit > unitIsSeaOrCanLandOnCarrier =
80
+ Matches .unitIsSea ().or (Matches .unitCanLandOnCarrier ());
81
+ units = CollectionUtils .getMatches (units , unitIsSeaOrCanLandOnCarrier );
82
+ }
83
+ } else {
84
+ units = CollectionUtils .getMatches (units , Matches .unitIsNotSea ());
85
+ }
86
+ if (units .isEmpty ()) {
87
+ return new PlaceableUnits ();
88
+ }
89
+ final IAbstractPlaceDelegate placeDel =
90
+ (IAbstractPlaceDelegate ) getPlayerBridge ().getRemoteDelegate ();
91
+ final PlaceableUnits production = placeDel .getPlaceableUnits (units , territory );
92
+ if (production .isError ()) {
93
+ JOptionPane .showMessageDialog (
94
+ getTopLevelAncestor (),
95
+ production .getErrorMessage () + "\n \n " ,
96
+ "Cannot produce units" ,
97
+ JOptionPane .INFORMATION_MESSAGE );
98
+ }
99
+ return production ;
100
+ }
101
+ }
102
+
52
103
@ Override
53
104
public void territorySelected (final Territory territory , final MouseDetails e ) {
54
105
if (!isActive () || (e .getButton () != MouseEvent .BUTTON1 )) {
@@ -66,21 +117,7 @@ public void territorySelected(final Territory territory, final MouseDetails e) {
66
117
if (maxUnits >= 0 ) {
67
118
chooser .setMaxAndShowMaxButton (maxUnits );
68
119
}
69
- final Dimension screenResolution = Toolkit .getDefaultToolkit ().getScreenSize ();
70
- final int availHeight = screenResolution .height - 120 ;
71
- final int availWidth = screenResolution .width - 40 ;
72
- final JScrollPane scroll = new JScrollPane (chooser );
73
- scroll .setBorder (BorderFactory .createEmptyBorder ());
74
- scroll .setPreferredSize (
75
- new Dimension (
76
- (scroll .getPreferredSize ().width > availWidth
77
- ? availWidth
78
- : (scroll .getPreferredSize ().width
79
- + (scroll .getPreferredSize ().height > availHeight ? 20 : 0 ))),
80
- (scroll .getPreferredSize ().height > availHeight
81
- ? availHeight
82
- : (scroll .getPreferredSize ().height
83
- + (scroll .getPreferredSize ().width > availWidth ? 26 : 0 )))));
120
+ final JScrollPane scroll = getScrollPaneFromChooser (chooser );
84
121
final int option =
85
122
JOptionPane .showOptionDialog (
86
123
getTopLevelAncestor (),
@@ -92,15 +129,43 @@ public void territorySelected(final Territory territory, final MouseDetails e) {
92
129
null ,
93
130
null );
94
131
if (option == JOptionPane .OK_OPTION ) {
95
- final Collection <Unit > choosen = chooser .getSelected ();
96
- placeData = new PlaceData (choosen , territory );
132
+ final Collection <Unit > selectedUnits = chooser .getSelected ();
133
+ placeData = new PlaceData (selectedUnits , territory );
97
134
updateUnits ();
98
- if (choosen .containsAll (units )) {
135
+ if (selectedUnits .containsAll (units )) {
99
136
leftToPlaceLabel .setText ("" );
100
137
}
101
138
release ();
102
139
}
103
140
}
141
+
142
+ @ NotNull
143
+ private JScrollPane getScrollPaneFromChooser (final UnitChooser chooser ) {
144
+ final Dimension screenResolution = Toolkit .getDefaultToolkit ().getScreenSize ();
145
+ final int availHeight = screenResolution .height - 120 ;
146
+ final int availWidth = screenResolution .width - 40 ;
147
+ final JScrollPane scroll = new JScrollPane (chooser );
148
+ scroll .setBorder (BorderFactory .createEmptyBorder ());
149
+ scroll .setPreferredSize (
150
+ new Dimension (
151
+ (scroll .getPreferredSize ().width > availWidth
152
+ ? availWidth
153
+ : getPreferredWith (scroll , availHeight )),
154
+ (scroll .getPreferredSize ().height > availHeight
155
+ ? availHeight
156
+ : getPreferredHeight (scroll , availWidth ))));
157
+ return scroll ;
158
+ }
159
+
160
+ private int getPreferredHeight (final JScrollPane scroll , final int availWidth ) {
161
+ return scroll .getPreferredSize ().height
162
+ + (scroll .getPreferredSize ().width > availWidth ? 26 : 0 );
163
+ }
164
+
165
+ private int getPreferredWith (final JScrollPane scroll , final int availHeight ) {
166
+ return scroll .getPreferredSize ().width
167
+ + (scroll .getPreferredSize ().height > availHeight ? 20 : 0 );
168
+ }
104
169
};
105
170
106
171
PlacePanel (final GameData data , final MapPanel map , final TripleAFrame frame ) {
@@ -147,42 +212,39 @@ private void updateStep() {
147
212
}
148
213
149
214
if (showUnitsToPlace ) {
150
- // Small hack: copy the unit list before passing it to a new thread.
151
- // This is to prevent ConcurrentModification. If the 'unitsToPlace' list is modified
152
- // later in this thread, before "SwingUtilities.invokeLater" can execute and complete,
153
- // then we will get a ConcurrentModification exception.
154
- // Ideally we would not modify the 'unitsToPlace' collection again except when
155
- // the swing thread signals that the user has taken action.. Short of that, we create a copy
156
- // here.
157
- final Collection <Unit > unitsToPlaceCopy = new ArrayList <>(unitsToPlace );
158
- SwingUtilities .invokeLater (
159
- () -> {
160
- unitsToPlacePanel .setUnits (unitsToPlaceCopy );
161
- SwingComponents .redraw (unitsToPlacePanel );
162
- });
215
+ updateUnitsInUnitsToPlacePanel (unitsToPlace );
163
216
} else {
164
217
SwingUtilities .invokeLater (unitsToPlacePanel ::removeAll );
165
218
}
166
219
}
167
220
221
+ private void updateUnitsInUnitsToPlacePanel (final Collection <Unit > newUnitsToPlace ) {
222
+ // Small hack: copy the unit list before passing it to a new thread.
223
+ // This is to prevent ConcurrentModification. If the 'unitsToPlace' list is modified
224
+ // later in this thread, before "SwingUtilities.invokeLater" can execute and complete,
225
+ // then we will get a ConcurrentModification exception.
226
+ // Ideally we would not modify the 'unitsToPlace' collection again except when
227
+ // the swing thread signals that the user has taken action.
228
+ // Short of that, we create a copy here.
229
+ final Collection <Unit > unitsToPlaceCopy =
230
+ Collections .unmodifiableCollection (new ArrayList <>(newUnitsToPlace ));
231
+ SwingUtilities .invokeLater (
232
+ () -> {
233
+ unitsToPlacePanel .setUnits (unitsToPlaceCopy );
234
+ SwingComponents .redraw (unitsToPlacePanel );
235
+ });
236
+ }
237
+
168
238
@ Override
169
239
public void gameDataChanged (final Change change ) {
170
- final Collection <Unit > unitsToPlace ;
171
240
final GameData data = getData ();
172
241
try (GameData .Unlocker ignored = data .acquireReadLock ()) {
173
242
final GamePlayer player = data .getSequence ().getStep ().getPlayerId ();
174
- if (player == null ) {
175
- return ;
243
+ if (player != null ) {
244
+ final Collection <Unit > unitsToPlace = player .getUnits ();
245
+ updateUnitsInUnitsToPlacePanel (unitsToPlace );
176
246
}
177
- unitsToPlace = player .getUnits ();
178
247
}
179
-
180
- SwingUtilities .invokeLater (
181
- () -> {
182
- unitsToPlacePanel .setUnits (unitsToPlace );
183
- unitsToPlacePanel .revalidate ();
184
- unitsToPlacePanel .repaint ();
185
- });
186
248
}
187
249
188
250
@ Override
@@ -210,54 +272,6 @@ PlaceData waitForPlace(final boolean bid, final PlayerBridge playerBridge) {
210
272
return placeData ;
211
273
}
212
274
213
- private PlaceableUnits getUnitsToPlace (final Territory territory ) {
214
- try (GameData .Unlocker ignored = getData ().acquireReadLock ()) {
215
- // not our territory
216
- if (!territory .isWater () && !territory .isOwnedBy (getCurrentPlayer ())) {
217
- if (GameStepPropertiesHelper .isBid (getData ())) {
218
- final PlayerAttachment pa = PlayerAttachment .get (territory .getOwner ());
219
- if ((pa == null || !pa .getGiveUnitControl ().contains (getCurrentPlayer ()))
220
- && !territory .anyUnitsMatch (Matches .unitIsOwnedBy (getCurrentPlayer ()))) {
221
- return new PlaceableUnits ();
222
- }
223
- } else {
224
- return new PlaceableUnits ();
225
- }
226
- }
227
- // get the units that can be placed on this territory.
228
- Collection <Unit > units = getCurrentPlayer ().getUnits ();
229
- if (territory .isWater ()) {
230
- GameProperties properties = getData ().getProperties ();
231
- if (!(Properties .getProduceFightersOnCarriers (properties )
232
- || Properties .getProduceNewFightersOnOldCarriers (properties )
233
- || Properties .getLhtrCarrierProductionRules (properties )
234
- || GameStepPropertiesHelper .isBid (getData ()))) {
235
- units = CollectionUtils .getMatches (units , Matches .unitIsSea ());
236
- } else {
237
- final Predicate <Unit > unitIsSeaOrCanLandOnCarrier =
238
- Matches .unitIsSea ().or (Matches .unitCanLandOnCarrier ());
239
- units = CollectionUtils .getMatches (units , unitIsSeaOrCanLandOnCarrier );
240
- }
241
- } else {
242
- units = CollectionUtils .getMatches (units , Matches .unitIsNotSea ());
243
- }
244
- if (units .isEmpty ()) {
245
- return new PlaceableUnits ();
246
- }
247
- final IAbstractPlaceDelegate placeDel =
248
- (IAbstractPlaceDelegate ) getPlayerBridge ().getRemoteDelegate ();
249
- final PlaceableUnits production = placeDel .getPlaceableUnits (units , territory );
250
- if (production .isError ()) {
251
- JOptionPane .showMessageDialog (
252
- getTopLevelAncestor (),
253
- production .getErrorMessage () + "\n \n " ,
254
- "Cannot produce units" ,
255
- JOptionPane .INFORMATION_MESSAGE );
256
- }
257
- return production ;
258
- }
259
- }
260
-
261
275
@ Override
262
276
public String toString () {
263
277
return "PlacePanel" ;
@@ -315,6 +329,6 @@ protected final List<Component> getAdditionalButtons() {
315
329
}
316
330
317
331
private void updateUnits () {
318
- unitsToPlacePanel . setUnits (getCurrentPlayer ().getUnits ());
332
+ updateUnitsInUnitsToPlacePanel (getCurrentPlayer ().getUnits ());
319
333
}
320
334
}
0 commit comments