Synchronized inputs: check if input has already been called 'done' and accept clicks only if it was not.

InputPayManaBase descendants: showMessage may be safely executed after input is dismissed (select card leads to re-check of requirements and may result in done() call, so showMessage is undesired, but it was already planned)
InputProliferate moved to separate file
Reverted 20840
This commit is contained in:
Maxmtg
2013-04-06 08:15:42 +00:00
parent 53a2ef4ee9
commit 8d4c82d330
18 changed files with 165 additions and 137 deletions

1
.gitattributes vendored
View File

@@ -13902,6 +13902,7 @@ src/main/java/forge/control/input/InputPayManaOfCostPayment.java -text
src/main/java/forge/control/input/InputPayManaSimple.java svneol=native#text/plain
src/main/java/forge/control/input/InputPayManaX.java -text
src/main/java/forge/control/input/InputPayment.java -text
src/main/java/forge/control/input/InputProliferate.java -text
src/main/java/forge/control/input/InputSelectCards.java -text
src/main/java/forge/control/input/InputSelectCardsFromList.java -text
src/main/java/forge/control/input/InputSelectMany.java -text

View File

@@ -1,9 +1,7 @@
package forge.card.ability.effects;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.google.common.base.Predicate;
@@ -16,85 +14,11 @@ import forge.Singletons;
import forge.card.ability.SpellAbilityEffect;
import forge.card.cardfactory.CardFactoryUtil;
import forge.card.spellability.SpellAbility;
import forge.control.input.InputSelectManyBase;
import forge.control.input.InputProliferate;
import forge.game.player.Player;
import forge.game.zone.ZoneType;
import forge.gui.GuiChoose;
public class CountersProliferateEffect extends SpellAbilityEffect {
/**
* TODO: Write javadoc for this type.
*
*/
public static final class InputProliferate extends InputSelectManyBase<GameEntity> {
private static final long serialVersionUID = -1779224307654698954L;
private Map<GameEntity, CounterType> chosenCounters = new HashMap<GameEntity, CounterType>();
public InputProliferate() {
super(1, Integer.MAX_VALUE);
}
@Override
protected String getMessage() {
StringBuilder sb = new StringBuilder("Choose permanents and/or players with counters on them to add one more counter of that type.");
sb.append("\n\nYou've selected so far:\n");
if( selected.isEmpty())
sb.append("(none)");
else
for(GameEntity ge : selected ) {
if( ge instanceof Player )
sb.append("* A poison counter to player ").append(ge).append("\n");
else
sb.append("* ").append(ge).append(" -> ").append(chosenCounters.get(ge)).append("counter\n");
}
return sb.toString();
}
@Override
public void selectCard(final Card card) {
if( !selectEntity(card) )
return;
if( selected.contains(card) ) {
final List<CounterType> choices = new ArrayList<CounterType>();
for (final CounterType ct : CounterType.values()) {
if (card.getCounters(ct) > 0) {
choices.add(ct);
}
}
CounterType toAdd = choices.size() == 1 ? choices.get(0) : GuiChoose.one("Select counter type", choices);
chosenCounters.put(card, toAdd);
}
refresh();
}
@Override
public void selectPlayer(final Player player) {
if( !selectEntity(player) )
return;
refresh();
}
@Override
protected boolean isValidChoice(GameEntity choice) {
if (choice instanceof Player)
return ((Player) choice).getPoisonCounters() > 0 && !choice.hasKeyword("You can't get poison counters");
if (choice instanceof Card)
return ((Card) choice).hasCounters();
return false;
}
public CounterType getCounterFor(GameEntity ge) {
return chosenCounters.get(ge);
}
}
@Override
protected String getStackDescription(SpellAbility sa) {
final StringBuilder sb = new StringBuilder();

View File

@@ -85,7 +85,7 @@ public class CostExile extends CostPartWithList {
for (int i = 0; i < nNeeded; i++) {
if (this.typeList.size() == 0) {
this.cancel();
this.onCancel();
}
final Card c = GuiChoose.oneOrNone("Exile from " + part.getFrom(), this.typeList);
@@ -97,7 +97,7 @@ public class CostExile extends CostPartWithList {
this.done();
}
} else {
this.cancel();
this.onCancel();
break;
}
}
@@ -145,14 +145,14 @@ public class CostExile extends CostPartWithList {
final Player p = GuiChoose.oneOrNone(sb.toString(), payableZone);
if (p == null) {
this.cancel();
this.onCancel();
}
typeList = CardLists.filter(list, CardPredicates.isOwner(p));
for (int i = 0; i < nNeeded; i++) {
if (this.typeList.size() == 0) {
this.cancel();
this.onCancel();
}
final Card c = GuiChoose.oneOrNone("Exile from " + part.getFrom(), this.typeList);
@@ -164,7 +164,7 @@ public class CostExile extends CostPartWithList {
this.done();
}
} else {
this.cancel();
this.onCancel();
break;
}
}
@@ -225,7 +225,7 @@ public class CostExile extends CostPartWithList {
for (int i = 0; i < nNeeded; i++) {
if (this.saList.isEmpty()) {
this.cancel();
this.onCancel();
}
//Have to use the stack descriptions here because some copied spells have no description otherwise
@@ -248,7 +248,7 @@ public class CostExile extends CostPartWithList {
final SpellAbilityStackInstance si = stack.getInstanceFromSpellAbility(toExile);
stack.remove(si);
} else {
this.cancel();
this.onCancel();
break;
}
}
@@ -309,7 +309,7 @@ public class CostExile extends CostPartWithList {
}
@Override
public void selectCard(final Card card) {
protected void onCardSelected(Card card) {
if (this.typeList.contains(card)) {
this.nExiles++;
part.executePayment(sa, card);
@@ -319,7 +319,7 @@ public class CostExile extends CostPartWithList {
this.done();
} else if (this.typeList.size() == 0) {
// happen
this.cancel();
this.onCancel();
} else {
this.showMessage();
}
@@ -357,7 +357,7 @@ public class CostExile extends CostPartWithList {
return;
}
}
cancel();
onCancel();
}
}

View File

@@ -87,7 +87,7 @@ public class CostPutCounter extends CostPartWithList {
}
@Override
public void selectCard(final Card card) {
protected void onCardSelected(Card card) {
if (this.typeList.contains(card)) {
this.nPut++;
costPutCounter.executePayment(sa, card);

View File

@@ -93,8 +93,11 @@ public class CostRemoveCounter extends CostPartWithList {
ButtonUtil.enableOnlyCancel();
}
/* (non-Javadoc)
* @see forge.control.input.InputSyncronizedBase#onCardSelected(forge.Card)
*/
@Override
public void selectCard(final Card card) {
protected void onCardSelected(Card card) {
if (this.typeList.contains(card)) {
if (card.getCounters(costRemoveCounter.getCounter()) > 0) {
this.nRemove++;
@@ -132,7 +135,6 @@ public class CostRemoveCounter extends CostPartWithList {
* @param payment
*/
public InputPayCostRemoveCounterFrom(CostRemoveCounter costRemoveCounter, String type, SpellAbility sa, int nNeeded) {
this.costRemoveCounter = costRemoveCounter;
this.type = type;
this.sa = sa;
@@ -151,14 +153,11 @@ public class CostRemoveCounter extends CostPartWithList {
for (int i = 0; i < nNeeded; i++) {
if (this.typeList.isEmpty()) {
this.cancel();
this.onCancel();
}
final Card o = GuiChoose.oneOrNone("Remove counter(s) from a card in " + costRemoveCounter.getZone(), this.typeList);
if (o != null) {
final Card card = o;
final Card card = GuiChoose.oneOrNone("Remove counter(s) from a card in " + costRemoveCounter.getZone(), this.typeList);
if (card != null) {
if (card.getCounters(costRemoveCounter.getCounter()) > 0) {
this.nRemove++;
costRemoveCounter.executePayment(sa, card);
@@ -174,7 +173,7 @@ public class CostRemoveCounter extends CostPartWithList {
}
}
} else {
this.cancel();
this.onCancel();
break;
}
}

View File

@@ -20,17 +20,13 @@ abstract class InputPayCostBase extends InputSyncronizedBase implements InputPay
private static final long serialVersionUID = -2967434867139585579L;
boolean bPaid = false;
@Override
final public void selectButtonCancel() {
this.cancel();
}
final protected void done() {
bPaid = true;
this.stop();
}
final public void cancel() {
@Override
final protected void onCancel() {
this.stop();
}

View File

@@ -45,9 +45,10 @@ public abstract class InputPayManaBase extends InputSyncronizedBase implements I
this.saPaidFor = saToPayFor;
}
/** {@inheritDoc} */
@Override
public void selectCard(final Card card) {
protected void onCardSelected(Card card) {
if (card.getManaAbility().isEmpty() || card.isInZone(ZoneType.Hand)) {
SDisplayUtil.remind(VMessage.SINGLETON_INSTANCE);
return;
@@ -245,7 +246,6 @@ public abstract class InputPayManaBase extends InputSyncronizedBase implements I
if (!skipExpress) {
// express Mana Choice
final ArrayList<SpellAbility> colorMatches = new ArrayList<SpellAbility>();
for (final SpellAbility am : abilities) {
AbilityManaPart m = am.getManaPart();
if (am.getApi() == ApiType.ManaReflected) {

View File

@@ -108,19 +108,17 @@ public class InputPayManaExecuteCommands extends InputPayManaBase {
/** {@inheritDoc} */
@Override
public final void selectButtonCancel() {
protected final void onCancel() {
Singletons.getControl().getPlayer().getManaPool().refundManaPaid(this.saPaidFor, true);
bPaid = false;
this.stop();
}
/** {@inheritDoc} */
@Override
public final void selectButtonOK() {}
/** {@inheritDoc} */
@Override
public final void showMessage() {
if ( isFinished() ) return;
ButtonUtil.enableOnlyCancel();
final StringBuilder msg = new StringBuilder(this.message + "Pay Mana Cost: " + this.manaCost);
if (this.phyLifeToLose > 0) {

View File

@@ -48,13 +48,15 @@ public class InputPayManaOfCostPayment extends InputPayManaBase {
}
@Override
public void selectButtonCancel() {
protected void onCancel() {
handleConvokedCards(true);
stop();
}
@Override
public void showMessage() {
if ( isFinished() ) return; //
ButtonUtil.enableOnlyCancel();
final String displayMana = manaCost.toString().replace("X", "").trim();

View File

@@ -106,7 +106,7 @@ public class InputPayManaSimple extends InputPayManaBase {
/** {@inheritDoc} */
@Override
public final void selectButtonCancel() {
protected final void onCancel() {
handleConvokedCards(true);
this.resetManaCost();
@@ -119,6 +119,8 @@ public class InputPayManaSimple extends InputPayManaBase {
/** {@inheritDoc} */
@Override
public final void showMessage() {
if( isFinished() ) return;
ButtonUtil.enableOnlyCancel();
final StringBuilder msg = new StringBuilder("Pay Mana Cost: " + this.manaCost.toString());

View File

@@ -39,6 +39,8 @@ public class InputPayManaX extends InputPayManaBase {
@Override
public void showMessage() {
if( isFinished() ) return;
// only cancel if partially paid an X value
// or X is 0, and x can't be 0
if (!isPaid()) {
@@ -57,9 +59,8 @@ public class InputPayManaX extends InputPayManaBase {
showMessage(msg.toString());
}
// selectCard
@Override
public void selectCard(final Card card) {
protected void onCardSelected(Card card) {
// don't allow here the cards that produce only wrong colors
activateManaAbility(card, this.colorX.isEmpty() ? this.manaCost : new ManaCostBeingPaid(this.colorX));
}
@@ -77,12 +78,12 @@ public class InputPayManaX extends InputPayManaBase {
}
@Override
public void selectButtonCancel() {
protected final void onCancel() {
this.stop();
}
@Override
public void selectButtonOK() {
protected final void onOk() {
done();
}

View File

@@ -0,0 +1,84 @@
package forge.control.input;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import forge.Card;
import forge.CounterType;
import forge.GameEntity;
import forge.game.player.Player;
import forge.gui.GuiChoose;
/**
* TODO: Write javadoc for this type.
*
*/
public final class InputProliferate extends InputSelectManyBase<GameEntity> {
private static final long serialVersionUID = -1779224307654698954L;
private Map<GameEntity, CounterType> chosenCounters = new HashMap<GameEntity, CounterType>();
public InputProliferate() {
super(1, Integer.MAX_VALUE);
}
@Override
protected String getMessage() {
StringBuilder sb = new StringBuilder("Choose permanents and/or players with counters on them to add one more counter of that type.");
sb.append("\n\nYou've selected so far:\n");
if( selected.isEmpty())
sb.append("(none)");
else
for(GameEntity ge : selected ) {
if( ge instanceof Player )
sb.append("* A poison counter to player ").append(ge).append("\n");
else
sb.append("* ").append(ge).append(" -> ").append(chosenCounters.get(ge)).append("counter\n");
}
return sb.toString();
}
@Override
protected void onCardSelected(Card card) {
if( !selectEntity(card) )
return;
if( selected.contains(card) ) {
final List<CounterType> choices = new ArrayList<CounterType>();
for (final CounterType ct : CounterType.values()) {
if (card.getCounters(ct) > 0) {
choices.add(ct);
}
}
CounterType toAdd = choices.size() == 1 ? choices.get(0) : GuiChoose.one("Select counter type", choices);
chosenCounters.put(card, toAdd);
}
refresh();
}
@Override
public void selectPlayer(final Player player) {
if( !selectEntity(player) )
return;
refresh();
}
@Override
protected boolean isValidChoice(GameEntity choice) {
if (choice instanceof Player)
return ((Player) choice).getPoisonCounters() > 0 && !choice.hasKeyword("You can't get poison counters");
if (choice instanceof Card)
return ((Card) choice).hasCounters();
return false;
}
public CounterType getCounterFor(GameEntity ge) {
return chosenCounters.get(ge);
}
}

View File

@@ -11,7 +11,7 @@ public abstract class InputSelectCards extends InputSelectManyBase<Card> {
}
@Override
public final void selectCard(final Card c) {
protected void onCardSelected(Card c) {
if ( !selectEntity(c) )
return;

View File

@@ -74,7 +74,7 @@ public abstract class InputSelectManyBase<T extends GameEntity> extends InputSyn
}
@Override
public final void selectButtonCancel() {
protected final void onCancel() {
bCancelled = true;
this.stop();
}
@@ -90,7 +90,7 @@ public abstract class InputSelectManyBase<T extends GameEntity> extends InputSyn
}
@Override
public final void selectButtonOK() {
protected final void onOk() {
this.stop();
}

View File

@@ -89,19 +89,19 @@ public final class InputSelectTargets extends InputSyncronizedBase {
}
@Override
public void selectButtonCancel() {
protected final void onCancel() {
bCancel = true;
this.done();
}
@Override
public void selectButtonOK() {
protected final void onOk() {
bOk = true;
this.done();
}
@Override
public void selectCard(final Card card) {
protected final void onCardSelected(Card card) {
if (!tgt.isUniqueTargets() && targetDepth.containsKey(card)) {
return;
}

View File

@@ -2,6 +2,7 @@ package forge.control.input;
import java.util.concurrent.CountDownLatch;
import forge.Card;
import forge.FThreads;
import forge.error.BugReporter;
import forge.game.player.Player;
@@ -9,6 +10,7 @@ import forge.game.player.Player;
public abstract class InputSyncronizedBase extends InputBase implements InputSynchronized {
private static final long serialVersionUID = 8756177361251703052L;
private boolean finished = false;
private final CountDownLatch cdlDone;
public InputSyncronizedBase(Player player) {
@@ -28,6 +30,32 @@ public abstract class InputSyncronizedBase extends InputBase implements InputSyn
@Override
protected void afterStop() {
finished = true;
cdlDone.countDown();
}
@Override
public final void selectButtonCancel() {
if( finished ) return;
onCancel();
}
@Override
public final void selectButtonOK() {
if( finished ) return;
onOk();
}
@Override
public final void selectCard(Card c) {
if( finished ) return;
onCardSelected(c);
}
protected final boolean isFinished() { return finished; }
protected void onCardSelected(Card c) {}
protected void onCancel() {}
protected void onOk() {}
}

View File

@@ -88,19 +88,15 @@ public class GuiChoose {
}
public static <T> List<T> noneOrMany(final String message, final Collection<T> choices) {
return GuiChoose.getChoices(message, 0, choices.size(), choices, null);
return GuiChoose.getChoices(message, 0, choices.size(), choices);
}
// returned Object will never be null
public static <T> List<T> getChoices(final String message, final int min, final int max, final T[] choices) {
return getChoices(message, min, max, Arrays.asList(choices), null);
}
public static <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices) {
return getChoices(message, min, max, choices, null);
return getChoices(message, min, max, Arrays.asList(choices));
}
public static <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices,final T selected) {
public static <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices) {
if (null == choices || choices.isEmpty()) {
if (0 == min) {
return new ArrayList<T>();
@@ -128,12 +124,7 @@ public class GuiChoose {
}
}
});
if(selected != null)
c.show(selected);
else
c.show();
c.show();
GuiUtils.clearPanelSelections();
return c.getSelectedValues();
}

View File

@@ -560,8 +560,10 @@ public class QuestWinLose extends ControlWinLose {
}
Collections.sort(formats);
final ListChooser<GameFormat> ch = new ListChooser<GameFormat>("Choose bonus booster format", 1, 1, formats);
ch.show(pref);
final GameFormat selected = GuiChoose.getChoices("Choose bonus booster format", 1, 1, formats, pref).get(0); //ch.getSelectedValue();
final GameFormat selected = ch.getSelectedValue();
Singletons.getModel().getQuestPreferences().setPref(QPref.BOOSTER_FORMAT, selected.toString());
cardsWon = qData.getCards().addCards(selected.getFilterPrinted());