*Merged from trunk up to r22981

This commit is contained in:
Hellfish
2013-08-21 06:17:56 +00:00
72 changed files with 2075 additions and 691 deletions

16
.gitattributes vendored
View File

@@ -5371,6 +5371,7 @@ res/cardsfolder/i/ikiral_outrider.txt svneol=native#text/plain
res/cardsfolder/i/ill_gotten_gains.txt svneol=native#text/plain
res/cardsfolder/i/illness_in_the_ranks.txt -text
res/cardsfolder/i/illuminate.txt -text
res/cardsfolder/i/illuminated_folio.txt -text
res/cardsfolder/i/illuminated_wings.txt svneol=native#text/plain
res/cardsfolder/i/illumination.txt svneol=native#text/plain
res/cardsfolder/i/illusion_reality.txt -text
@@ -14990,6 +14991,11 @@ src/main/java/forge/gui/match/views/VPicture.java -text
src/main/java/forge/gui/match/views/VPlayers.java -text
src/main/java/forge/gui/match/views/VStack.java -text
src/main/java/forge/gui/match/views/package-info.java svneol=native#text/plain
src/main/java/forge/gui/menubar/FMenuBar.java -text
src/main/java/forge/gui/menubar/IMenuProvider.java -text
src/main/java/forge/gui/menubar/MenuUtil.java -text
src/main/java/forge/gui/menus/ForgeMenu.java -text
src/main/java/forge/gui/menus/HelpMenu.java -text
src/main/java/forge/gui/package-info.java svneol=native#text/plain
src/main/java/forge/gui/toolbox/CardFaceSymbols.java svneol=native#text/plain
src/main/java/forge/gui/toolbox/FAbsolutePositioner.java -text
@@ -15008,10 +15014,13 @@ src/main/java/forge/gui/toolbox/FSkin.java -text
src/main/java/forge/gui/toolbox/FTabbedPane.java -text
src/main/java/forge/gui/toolbox/FTextArea.java -text
src/main/java/forge/gui/toolbox/FTextField.java -text
src/main/java/forge/gui/toolbox/LayoutHelper.java -text
src/main/java/forge/gui/toolbox/SaveOpenDialog.java -text
src/main/java/forge/gui/toolbox/imaging/FImagePanel.java -text
src/main/java/forge/gui/toolbox/imaging/FImageUtil.java -text
src/main/java/forge/gui/toolbox/imaging/ImageUtil.java -text
src/main/java/forge/gui/toolbox/itemmanager/CardManager.java -text
src/main/java/forge/gui/toolbox/itemmanager/InventoryItemManager.java -text
src/main/java/forge/gui/toolbox/itemmanager/ItemManager.java -text
src/main/java/forge/gui/toolbox/itemmanager/ItemManagerContainer.java -text
src/main/java/forge/gui/toolbox/itemmanager/ItemManagerModel.java -text
@@ -15023,12 +15032,13 @@ src/main/java/forge/gui/toolbox/itemmanager/filters/CardColorFilter.java -text
src/main/java/forge/gui/toolbox/itemmanager/filters/CardFormatFilter.java -text
src/main/java/forge/gui/toolbox/itemmanager/filters/CardPowerFilter.java -text
src/main/java/forge/gui/toolbox/itemmanager/filters/CardQuestWorldFilter.java -text
src/main/java/forge/gui/toolbox/itemmanager/filters/CardSearchFilter.java -text
src/main/java/forge/gui/toolbox/itemmanager/filters/CardSetFilter.java -text
src/main/java/forge/gui/toolbox/itemmanager/filters/CardToughnessFilter.java -text
src/main/java/forge/gui/toolbox/itemmanager/filters/CardTypeFilter.java -text
src/main/java/forge/gui/toolbox/itemmanager/filters/ItemFilter.java -text
src/main/java/forge/gui/toolbox/itemmanager/filters/ListLabelFilter.java -text
src/main/java/forge/gui/toolbox/itemmanager/filters/TextFieldFilter.java -text
src/main/java/forge/gui/toolbox/itemmanager/filters/TextSearchFilter.java -text
src/main/java/forge/gui/toolbox/itemmanager/filters/ToggleButtonsFilter.java -text
src/main/java/forge/gui/toolbox/itemmanager/filters/ValueRangeFilter.java -text
src/main/java/forge/gui/toolbox/itemmanager/package-info.java -text
@@ -15103,6 +15113,7 @@ src/main/java/forge/net/protocol/toserver/IPacketSrv.java -text
src/main/java/forge/net/protocol/toserver/IncorrectPacketSrv.java -text
src/main/java/forge/net/protocol/toserver/package-info.java -text
src/main/java/forge/package-info.java svneol=native#text/plain
src/main/java/forge/properties/ForgeLookAndFeel.java -text
src/main/java/forge/properties/ForgePreferences.java svneol=native#text/plain
src/main/java/forge/properties/NewConstants.java svneol=native#text/plain
src/main/java/forge/properties/Preferences.java svneol=native#text/plain
@@ -15183,6 +15194,7 @@ src/main/java/forge/util/MyRandom.java svneol=native#text/plain
src/main/java/forge/util/PredicateString.java -text
src/main/java/forge/util/ReflectionUtil.java -text
src/main/java/forge/util/TextUtil.java -text
src/main/java/forge/util/TypeUtil.java -text
src/main/java/forge/util/XmlUtil.java -text
src/main/java/forge/util/maps/CollectionSuppliers.java -text
src/main/java/forge/util/maps/EnumMapOfLists.java -text
@@ -15197,6 +15209,8 @@ src/main/java/forge/util/package-info.java -text
src/main/java/forge/util/storage/IStorage.java -text
src/main/java/forge/util/storage/StorageBase.java -text
src/main/java/forge/util/storage/StorageImmediatelySerialized.java svneol=native#text/plain
src/main/java/forge/util/storage/StorageNestedFolders.java -text
src/main/java/forge/util/storage/StorageReaderBase.java -text
src/main/java/forge/util/storage/StorageReaderFile.java -text
src/main/java/forge/util/storage/StorageReaderFileSections.java -text
src/main/java/forge/util/storage/StorageReaderFolder.java -text

View File

@@ -3,23 +3,13 @@ ManaCost:5 W W
Types:Creature Angel
PT:6/6
K:Flying
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ Tolstoy | Static$ True | TriggerDescription$ As CARDNAME enters the battlefield, each player chooses war or peace. Creatures controlled by players who chose war get +3/+0. Creatures controlled by players who chose peace get +0/+3.
SVar:Tolstoy:AB$ GenericChoice | Cost$ 0 | Defined$ You | Choices$ WarChoice,PeaceChoice | SubAbility$ OppChoice
SVar:OppChoice:DB$ GenericChoice | Cost$ 0 | Defined$ Opponent | Choices$ Attacking,Defensive
SVar:WarChoice:DB$ Effect | Name$ Archangel War Effect | ChoiceDescription$ War | Duration$ UntilHostLeavesPlay | RememberEffect$ True
SVar:PeaceChoice:DB$ Effect | Name$ Archangel Peace Effect | ChoiceDescription$ Peace | Duration$ UntilHostLeavesPlay | RememberEffect$ True
SVar:Attacking:DB$ Effect | Name$ Archangel War Effect | ChoiceDescription$ War | EffectOwner$ Opponent | Duration$ UntilHostLeavesPlay | RememberEffect$ True
SVar:Defensive:DB$ Effect | Name$ Archangel Peace Effect | ChoiceDescription$ Peace | EffectOwner$ Opponent | Duration$ UntilHostLeavesPlay | RememberEffect$ True
S:Mode$ Continuous | AffectedZone$ Battlefield | Affected$ Creature.YouCtrl | AddPower$ 3 | CheckSVar$ WarYou | SVarCompare$ GE1 | References$ WarYou
S:Mode$ Continuous | AffectedZone$ Battlefield | Affected$ Creature.YouCtrl | AddToughness$ 3 | CheckSVar$ PeaceYou | SVarCompare$ GE1 | References$ PeaceYou
S:Mode$ Continuous | AffectedZone$ Battlefield | Affected$ Creature.YouDontCtrl | AddPower$ 3 | CheckSVar$ WarOpp | SVarCompare$ GE1 | References$ WarOpp
S:Mode$ Continuous | AffectedZone$ Battlefield | Affected$ Creature.YouDontCtrl | AddToughness$ 3 | CheckSVar$ PeaceOpp | SVarCompare$ GE1 | References$ PeaceOpp
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Defined$ Self | Execute$ DBCleanup | Static$ True
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:WarYou:Count$ValidCommand Card.namedArchangel War Effect+YouCtrl+IsRemembered
SVar:PeaceYou:Count$ValidCommand Card.namedArchangel Peace Effect+YouCtrl+IsRemembered
SVar:WarOpp:Count$ValidCommand Card.namedArchangel War Effect+YouDontCtrl+IsRemembered
SVar:PeaceOpp:Count$ValidCommand Card.namedArchangel Peace Effect+YouDontCtrl+IsRemembered
K:ETBReplacement:Other:ChooseEach
SVar:ChooseEach:DB$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ DBChoice | SpellDescription$ As CARDNAME enters the battlefield, each player chooses war or peace. Creatures controlled by players who chose war get +3/+0. Creatures controlled by players who chose peace get +0/+3.
SVar:DBChoice:DB$ GenericChoice | Cost$ 0 | Defined$ Player.IsRemembered | Choices$ WarChoice,PeaceChoice
SVar:WarChoice:DB$ Effect | Name$ Archangel War Effect | StaticAbilities$ WarPump | ChoiceDescription$ War | EffectOwner$ Player.IsRemembered | Duration$ UntilHostLeavesPlay
SVar:PeaceChoice:DB$ Effect | Name$ Archangel Peace Effect | StaticAbilities$ PeacePump | ChoiceDescription$ Peace | EffectOwner$ Player.IsRemembered | Duration$ UntilHostLeavesPlay
SVar:WarPump:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Creature.YouCtrl | AddPower$ 3 | Description$ Creatures you control get +3/+0.
SVar:PeacePump:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Creature.YouCtrl | AddToughness$ 3 | Description$ Creatures you control get +0/+3.
SVar:RemAIDeck:True
SVar:Picture:http://www.wizards.com/global/images/magic/general/archangel_of_strife.jpg
Oracle:Flying\nAs Archangel of Strife enters the battlefield, each player chooses war or peace.\nCreatures controlled by players who chose war get +3/+0.\nCreatures controlled by players who chose peace get +0/+3.

View File

@@ -1,7 +1,7 @@
Name:Exhume
ManaCost:1 B
Types:Sorcery
A:SP$ ChangeZone | Cost$ 1 B | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.YouCtrl | ChangeNum$ 1 | Hidden$ True | SubAbility$ DBChangeZoneOpp | SpellDescription$ Each player puts a creature card from his or her graveyard onto the battlefield.
SVar:DBChangeZoneOpp:DB$ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.YouDontCtrl | DefinedPlayer$ Opponent | ChangeNum$ 1 | Hidden$ True
A:SP$ RepeatEach | Cost$ 1 B | RepeatSubAbility$ DBChangeZone | RepeatPlayers$ Player | SpellDescription$ Each player puts a creature card from his or her graveyard onto the battlefield.
SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.RememberedPlayerCtrl | DefinedPlayer$ Player.IsRemembered | Chooser$ Player.IsRemembered | ChangeNum$ 1 | Hidden$ True
SVar:Picture:http://www.wizards.com/global/images/magic/general/exhume.jpg
Oracle:Each player puts a creature card from his or her graveyard onto the battlefield.

View File

@@ -3,6 +3,6 @@ ManaCost:R
Types:Creature Goblin
PT:1/1
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigChange | TriggerDescription$ Whenever CARDNAME deals damage to a player, you may put a Goblin permanent card from your hand onto the battlefield.
SVar:TrigChange:AB$ChangeZone | Cost$ 0 | Origin$ Hand | Destination$ Battlefield | ChangeType$ Permanent.Goblin | ChangeNum$ 1
SVar:TrigChange:AB$ ChangeZone | Cost$ 0 | Origin$ Hand | Destination$ Battlefield | ChangeType$ Permanent.Goblin | ChangeNum$ 1
SVar:Picture:http://www.wizards.com/global/images/magic/general/goblin_lackey.jpg
Oracle:Whenever Goblin Lackey deals damage to a player, you may put a Goblin permanent card from your hand onto the battlefield.

View File

@@ -0,0 +1,7 @@
Name:Illuminated Folio
ManaCost:5
Types:Artifact
A:AB$ Draw | Cost$ 1 T Reveal<2/SameColor> | NumCards$ 1 | SpellDescription$ Draw a card.
SVar:RemAIDeck:True
SVar:Picture:http://www.wizards.com/global/images/magic/general/illuminated_folio.jpg
Oracle:{1}, {T}, Reveal two cards from your hand that share a color: Draw a card.

View File

@@ -1,10 +1,8 @@
Name:Mana Breach
ManaCost:2 U
Types:Enchantment
T:Mode$ SpellCast | ValidCard$ Card | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigBounceYou | TriggerDescription$ Whenever a player casts a spell, that player returns a land he or she controls to its owner's hand.
T:Mode$ SpellCast | ValidCard$ Card | ValidActivatingPlayer$ Opponent | TriggerZones$ Battlefield | Execute$ TrigBounceOpp | Secondary$ True | TriggerDescription$ Whenever a player casts a spell, that player returns a land he or she controls to its owner's hand.
SVar:TrigBounceYou:AB$ ChangeZone | Cost$ 0 | Origin$ Battlefield | Destination$ Hand | ChangeNum$ 1 | ChangeType$ Land.YouCtrl | Mandatory$ True | DefinedPlayer$ You | Hidden$ True
SVar:TrigBounceOpp:AB$ ChangeZone | Cost$ 0 | Origin$ Battlefield | Destination$ Hand | ChangeNum$ 1 | ChangeType$ Land.YouDontCtrl | Mandatory$ True | DefinedPlayer$ Opponent | Hidden$ True
T:Mode$ SpellCast | ValidCard$ Card | ValidActivatingPlayer$ Player | TriggerZones$ Battlefield | Execute$ TrigBounce | TriggerDescription$ Whenever a player casts a spell, that player returns a land he or she controls to its owner's hand.
SVar:TrigBounce:AB$ ChangeZone | Cost$ 0 | Origin$ Battlefield | Destination$ Hand | ChangeNum$ 1 | ChangeType$ Land | Mandatory$ True | DefinedPlayer$ TriggeredActivator | Chooser$ TriggeredActivator | Hidden$ True
SVar:RemRandomDeck:True
SVar:Picture:http://www.wizards.com/global/images/magic/general/mana_breach.jpg
Oracle:Whenever a player casts a spell, that player returns a land he or she controls to its owner's hand.

View File

@@ -1,12 +1,11 @@
Name:Memory Jar
ManaCost:5
Types:Artifact
A:AB$ ChangeZoneAll | Cost$ T Sac<1/CARDNAME> | ChangeType$ Card | Origin$ Hand | Destination$ Exile | ExileFaceDown$ True | RememberChanged$ True | SubAbility$ YouDraw | SpellDescription$ Each player exiles all cards from his or her hand face down and draws seven cards. At the beginning of the next end step, each player discards his or her hand and returns to his or her hand each card he or she exiled this way.
SVar:YouDraw:DB$ Draw | Defined$ You | NumCards$ 7 | SubAbility$ OppDraw
SVar:OppDraw:DB$ Draw | Defined$ Opponent | NumCards$ 7 | SubAbility$ DelayedReturn
SVar:DelayedReturn:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ YouDiscard | TriggerDescription$ Both players discard their hands. Return exiled cards to their owners' hands.
SVar:YouDiscard: AB$ Discard | Cost$ 0 | Defined$ You | Mode$ Hand | SubAbility$ OppDiscard
SVar:OppDiscard: DB$ Discard | Defined$ Opponent | Mode$ Hand | SubAbility$ ReturnAll
A:AB$ ChangeZoneAll | Cost$ T Sac<1/CARDNAME> | ChangeType$ Card | Origin$ Hand | Destination$ Exile | ExileFaceDown$ True | RememberChanged$ True | SubAbility$ DrawEach | SpellDescription$ Each player exiles all cards from his or her hand face down and draws seven cards. At the beginning of the next end step, each player discards his or her hand and returns to his or her hand each card he or she exiled this way.
SVar:DrawEach:DB$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ DBDraw | SubAbility$ DelayedReturn
SVar:DBDraw:DB$ Draw | Defined$ Player.IsRemembered | NumCards$ 7
SVar:DelayedReturn:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ DiscardEach | TriggerDescription$ Both players discard their hands. Return exiled cards to their owners' hands.
SVar:DiscardEach:AB$ Discard | Cost$ 0 | Defined$ Each | Mode$ Hand | SubAbility$ ReturnAll
SVar:ReturnAll:DB$ ChangeZone | Origin$ Exile | Destination$ Hand | Defined$ Remembered | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:RemAIDeck:True

View File

@@ -1,10 +1,8 @@
Name:Overburden
ManaCost:1 U
Types:Enchantment
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.nonToken+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigBounceYou | TriggerDescription$ Whenever a player puts a nontoken creature onto the battlefield, that player returns a land he or she controls to its owner's hand.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.nonToken+YouDontCtrl | TriggerZones$ Battlefield | Execute$ TrigBounceOpp | Secondary$ True | TriggerDescription$ Whenever a player puts a nontoken creature onto the battlefield, that player returns a land he or she controls to its owner's hand.
SVar:TrigBounceYou:AB$ ChangeZone | Cost$ 0 | Origin$ Battlefield | Destination$ Hand | ChangeType$ Land.YouCtrl | ChangeNum$ 1 | Mandatory$ True | DefinedPlayer$ You | Hidden$ True
SVar:TrigBounceOpp:AB$ ChangeZone | Cost$ 0 | Origin$ Battlefield | Destination$ Hand | ChangeType$ Land.YouDontCtrl | ChangeNum$ 1 | Mandatory$ True | DefinedPlayer$ Opponent | Hidden$ True
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.nonToken | TriggerZones$ Battlefield | Execute$ TrigBounce | TriggerDescription$ Whenever a player puts a nontoken creature onto the battlefield, that player returns a land he or she controls to its owner's hand.
SVar:TrigBounce:AB$ ChangeZone | Cost$ 0 | Origin$ Battlefield | Destination$ Hand | ChangeType$ Land | ChangeNum$ 1 | Mandatory$ True | DefinedPlayer$ TriggeredCardController | Chooser$ TriggeredCardController | Hidden$ True
SVar:RemRandomDeck:True
SVar:Picture:http://www.wizards.com/global/images/magic/general/overburden.jpg
Oracle:Whenever a player puts a nontoken creature onto the battlefield, that player returns a land he or she controls to its owner's hand.

View File

@@ -5,5 +5,6 @@ PT:2/4
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | IsPresent$ Gate.YouCtrl | PresentCompare$ GE2 | Execute$ TrigGainControl | TriggerDescription$ When CARDNAME enters the battlefield, if you control two or more Gates, gain control of target creature an opponent controls until end of turn. Untap that creature. That creature gains haste until end of turn.
SVar:TrigGainControl:AB$ GainControl | Cost$ 0 | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls | Untap$ True | LoseControl$ EOT | SubAbility$ DBPump
SVar:DBPump:DB$ Pump | Defined$ Targeted | KW$ Haste
SVar:PlayMain1:TRUE
SVar:Picture:http://www.wizards.com/global/images/magic/general/smelt_ward_gatekeepers.jpg
Oracle:When Smelt-Ward Gatekeepers enters the battlefield, if you control two or more Gates, gain control of target creature an opponent controls until end of turn. Untap that creature. It gains haste until end of turn.

View File

@@ -4,6 +4,6 @@ Types:Creature Human Assassin
PT:1/1
K:Fear
T:Mode$ AttackerUnblocked | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigPoison | TriggerDescription$ Whenever CARDNAME attacks and isn't blocked, defending player gets a poison counter. (A player with ten or more poison counters loses the game.)
SVar:TrigPoison:AB$Poison | Cost$ 0 | Defined$ DefendingPlayer | Num$ 1
SVar:TrigPoison:AB$ Poison | Cost$ 0 | Defined$ DefendingPlayer | Num$ 1
SVar:Picture:http://www.wizards.com/global/images/magic/general/suqata_assassin.jpg
Oracle:Fear (This creature can't be blocked except by artifact creatures and/or black creatures.)\nWhenever Suq'Ata Assassin attacks and isn't blocked, defending player gets a poison counter. (A player with ten or more poison counters loses the game.)

View File

@@ -4,6 +4,6 @@ Types:Creature Insect
PT:0/1
K:Flying
T:Mode$ AttackerUnblocked | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigPoison | TriggerDescription$ Whenever CARDNAME attacks and isn't blocked, defending player gets a poison counter. (A player with ten or more poison counters loses the game.)
SVar:TrigPoison:AB$Poison | Cost$ 0 | Defined$ DefendingPlayer | Num$ 1
SVar:TrigPoison:AB$ Poison | Cost$ 0 | Defined$ DefendingPlayer | Num$ 1
SVar:Picture:http://www.wizards.com/global/images/magic/general/swamp_mosquito.jpg
Oracle:Flying\nWhenever Swamp Mosquito attacks and isn't blocked, defending player gets a poison counter. (A player with ten or more poison counters loses the game.)

View File

@@ -4,7 +4,7 @@ Types:Creature Human Rebel
PT:1/1
K:Shadow
T:Mode$ AttackerUnblocked | ValidCard$ Card.Self | Execute$ TrigDamage | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME attacks and isn't blocked, you may have it deal 1 damage to target creature. If you do, prevent all combat damage CARDNAME would deal this turn.
SVar:TrigDamage:AB$DealDamage | Cost$ 0 | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ 1 | SubAbility$ DBPump
SVar:TrigDamage:AB$ DealDamage | Cost$ 0 | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ 1 | SubAbility$ DBPump
SVar:DBPump:DB$Pump | KW$ HIDDEN Prevent all combat damage that would be dealt by CARDNAME.
SVar:Picture:http://www.wizards.com/global/images/magic/general/zealot_il_vec.jpg
Oracle:Shadow (This creature can block or be blocked by only creatures with shadow.)\nWhenever Zealot il-Vec attacks and isn't blocked, you may have it deal 1 damage to target creature. If you do, prevent all combat damage Zealot il-Vec would deal this turn.

View File

@@ -109,6 +109,15 @@ public final class CardPredicates {
};
}
public static final Predicate<Card> sharesColorWith(final Card color) {
return new Predicate<Card>() {
@Override
public boolean apply(Card c) {
return c.sharesColorWith(color);
}
};
}
public static final Predicate<Card> possibleBlockers(final Card attacker) {
return new Predicate<Card>() {
@Override

View File

@@ -28,6 +28,7 @@ import com.google.common.collect.Lists;
import forge.util.IItemReader;
import forge.util.storage.StorageBase;
import forge.util.storage.StorageReaderBase;
public final class EditionCollection extends StorageBase<CardEdition> {
@@ -107,7 +108,7 @@ public final class EditionCollection extends StorageBase<CardEdition> {
*/
public IItemReader<SealedProductTemplate> getBoosterGenerator() {
// TODO Auto-generated method stub
return new IItemReader<SealedProductTemplate>() {
return new StorageReaderBase<SealedProductTemplate>(null) {
@Override
public Map<String, SealedProductTemplate> readAll() {

View File

@@ -188,11 +188,6 @@ public class EffectEffect extends SpellAbilityEffect {
eff.setChosenColor(hostCard.getChosenColor());
}
// Remember created effect
if (sa.hasParam("RememberEffect")) {
game.getCardState(hostCard).addRemembered(eff);
}
// Duration
final String duration = sa.getParam("Duration");
if ((duration == null) || !duration.equals("Permanent")) {

View File

@@ -192,30 +192,42 @@ public class CostDiscard extends CostPartWithList {
}
return executePayment(ability, Aggregates.random(handList, c));
}
if (discardType.contains("+WithSameName")) {
String type = discardType.replace("+WithSameName", "");
handList = CardLists.getValidCards(handList, type.split(";"), activator, ability.getSourceCard());
final List<Card> landList2 = handList;
handList = CardLists.filter(handList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
for (Card card : landList2) {
if (!card.equals(c) && card.getName().equals(c.getName())) {
return true;
}
}
return false;
}
});
if (c == 0) return true;
List<Card> discarded = new ArrayList<Card>();
while (c > 0) {
InputSelectCards inp = new InputSelectCardsFromList(1, 1, handList);
inp.setMessage("Select one of the cards with the same name to discard. Already chosen: " + discarded);
inp.setCancelAllowed(true);
Singletons.getControl().getInputQueue().setInputAndWait(inp);
if (inp.hasCancelled())
return false;
final Card first = inp.getSelected().get(0);
discarded.add(first);
handList = CardLists.filter(handList, CardPredicates.nameEquals(first.getName()));
handList.remove(first);
c--;
}
return executePayment(ability, discarded);
} else {
String type = new String(discardType);
boolean sameName = false;
if (type.contains("+WithSameName")) {
sameName = true;
type = type.replace("+WithSameName", "");
}
final String[] validType = type.split(";");
handList = CardLists.getValidCards(handList, validType, activator, ability.getSourceCard());
final List<Card> landList2 = handList;
if (sameName) {
handList = CardLists.filter(handList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
for (Card card : landList2) {
if (!card.equals(c) && card.getName().equals(c.getName())) {
return true;
}
}
return false;
}
});
}
if (c == null) {
final String sVar = ability.getSVar(amount);

View File

@@ -20,10 +20,12 @@ package forge.card.cost;
import java.util.ArrayList;
import java.util.List;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import forge.Card;
import forge.CardLists;
import forge.CardPredicates;
import forge.Singletons;
import forge.card.ability.AbilityUtils;
import forge.card.spellability.SpellAbility;
@@ -83,6 +85,22 @@ public class CostReveal extends CostPartWithList {
}
} else if (this.getType().equals("Hand")) {
return true;
} else if (this.getType().equals("SameColor")) {
if (amount == null) {
return false;
} else {
for (final Card card : handList) {
if (CardLists.filter(handList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.sharesColorWith(card);
}
}).size() >= amount) {
return true;
}
}
return false;
}
} else {
if (ability.isSpell()) {
handList.remove(source); // can't pay for itself
@@ -117,6 +135,10 @@ public class CostReveal extends CostPartWithList {
if (this.getType().equals("Hand"))
return new PaymentDecision(new ArrayList<Card>(ai.getCardsIn(ZoneType.Hand)));
if (this.getType().equals("SameColor")) {
return null;
}
hand = CardLists.getValidCards(hand, type.split(";"), ai, source);
Integer c = this.convertAmount();
if (c == null) {
@@ -152,6 +174,37 @@ public class CostReveal extends CostPartWithList {
for(Card c : activator.getCardsIn(ZoneType.Hand))
executePayment(ability, c);
return true;
} else if (this.getType().equals("SameColor")) {
Integer num = this.convertAmount();
List<Card> handList = activator.getCardsIn(ZoneType.Hand);
final List<Card> handList2 = handList;
handList = CardLists.filter(handList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
for (Card card : handList2) {
if (!card.equals(c) && card.sharesColorWith(c)) {
return true;
}
}
return false;
}
});
if (num == 0) return true;
List<Card> revealed = new ArrayList<Card>();
while (num > 0) {
InputSelectCards inp = new InputSelectCardsFromList(1, 1, handList);
inp.setMessage("Select one of cards to reveal. Already chosen:" + revealed);
inp.setCancelAllowed(true);
Singletons.getControl().getInputQueue().setInputAndWait(inp);
if (inp.hasCancelled())
return false;
final Card first = inp.getSelected().get(0);
revealed.add(first);
handList = CardLists.filter(handList, CardPredicates.sharesColorWith(first));
handList.remove(first);
num--;
}
return executePayment(ability, revealed);
} else {
Integer num = this.convertAmount();
@@ -193,6 +246,8 @@ public class CostReveal extends CostPartWithList {
sb.append(this.getType());
} else if (this.getType().equals("Hand")) {
return ("Reveal you hand");
} else if (this.getType().equals("SameColor")) {
return ("Reveal " + i + " cards from your hand that share a color");
} else {
final StringBuilder desc = new StringBuilder();

View File

@@ -161,6 +161,10 @@ public class CostTapType extends CostPartWithList {
public final boolean payHuman(final SpellAbility ability, final Game game) {
List<Card> typeList = new ArrayList<Card>(ability.getActivatingPlayer().getCardsIn(ZoneType.Battlefield));
String type = this.getType();
final String amount = this.getAmount();
final Card source = ability.getSourceCard();
Integer c = this.convertAmount();
boolean sameType = false;
if (type.contains("sharesCreatureTypeWith")) {
sameType = true;
@@ -168,6 +172,16 @@ public class CostTapType extends CostPartWithList {
}
typeList = CardLists.getValidCards(typeList, type.split(";"), ability.getActivatingPlayer(), ability.getSourceCard());
typeList = CardLists.filter(typeList, Presets.UNTAPPED);
if (c == null) {
final String sVar = ability.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")) {
c = Cost.chooseXValue(source, ability, typeList.size());
} else {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
}
if (sameType) {
final List<Card> List2 = typeList;
typeList = CardLists.filter(typeList, new Predicate<Card>() {
@@ -181,22 +195,29 @@ public class CostTapType extends CostPartWithList {
return false;
}
});
}
final String amount = this.getAmount();
final Card source = ability.getSourceCard();
Integer c = this.convertAmount();
if (c == null) {
final String sVar = ability.getSVar(amount);
// Generalize this
if (sVar.equals("XChoice")) {
c = Cost.chooseXValue(source, ability, typeList.size());
} else {
c = AbilityUtils.calculateAmount(source, amount, ability);
if (c == 0) return true;
List<Card> tapped = new ArrayList<Card>();
while (c > 0) {
InputSelectCards inp = new InputSelectCardsFromList(1, 1, typeList);
inp.setMessage("Select one of the cards to tap. Already chosen: " + tapped);
inp.setCancelAllowed(true);
Singletons.getControl().getInputQueue().setInputAndWait(inp);
if (inp.hasCancelled())
return false;
final Card first = inp.getSelected().get(0);
tapped.add(first);
typeList = CardLists.filter(typeList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.sharesCreatureTypeWith(first);
}
});
typeList.remove(first);
c--;
}
return executePayment(ability, tapped);
}
InputSelectCards inp = new InputSelectCardsFromList(c, c, typeList);
inp.setMessage("Select a " + getDescriptiveType() + " to tap (%d left)");
Singletons.getControl().getInputQueue().setInputAndWait(inp);

View File

@@ -29,7 +29,6 @@ import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JLayeredPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import forge.Card;
@@ -61,8 +60,11 @@ import forge.gui.match.controllers.CMessage;
import forge.gui.match.controllers.CStack;
import forge.gui.match.nonsingleton.VField;
import forge.gui.match.views.VAntes;
import forge.gui.menubar.FMenuBar;
import forge.gui.menubar.MenuUtil;
import forge.gui.toolbox.FSkin;
import forge.net.FServer;
import forge.properties.ForgeLookAndFeel;
import forge.properties.ForgePreferences.FPref;
import forge.properties.NewConstants;
import forge.quest.QuestController;
@@ -82,6 +84,7 @@ import forge.view.FView;
public enum FControl {
instance;
private FMenuBar menuBar;
private List<Shortcut> shortcuts;
private JLayeredPane display;
private Screens state = Screens.UNKNOWN;
@@ -167,12 +170,12 @@ public enum FControl {
// Preloads skin components (using progress bar).
FSkin.loadFull();
//This must be done here or at least between the skin being loaded and any FTabbedPanes being created.
//Why,Swing? Why is this not a property of JTabbbedPane?
UIManager.put("TabbedPane.selected", FSkin.getColor(FSkin.Colors.CLR_ACTIVE));
UIManager.put("TabbedPane.contentOpaque", FSkin.getColor(FSkin.Colors.CLR_THEME));
UIManager.put("TabbedPane.unselectedBackground", FSkin.getColor(FSkin.Colors.CLR_THEME2));
setComboBoxLookAndFeel();
// This must be done here or at least between the skin being loaded
// and any GUI controls being created.
FSkin.setProgessBarMessage("Setting look and feel...");
setForgeLookAndFeel();
createMenuBar();
this.shortcuts = KeyboardShortcuts.attachKeyboardShortcuts();
this.display = FView.SINGLETON_INSTANCE.getLpnDocument();
@@ -208,19 +211,14 @@ public enum FControl {
public void run() { Singletons.getView().initialize(); } });
}
/**
* @see <a href="http://tips4java.wordpress.com/2008/10/09/uimanager-defaults/">UIManager Defaults</a>
*/
private void setComboBoxLookAndFeel() {
if (Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_THEMED_COMBOBOX)) {
UIManager.put("ComboBox.background", FSkin.getColor(FSkin.Colors.CLR_THEME2));
UIManager.put("ComboBox.foreground", FSkin.getColor(FSkin.Colors.CLR_TEXT));
UIManager.put("ComboBox.selectionBackground", FSkin.getColor(FSkin.Colors.CLR_ACTIVE));
UIManager.put("ComboBox.selectionForeground", FSkin.getColor(FSkin.Colors.CLR_TEXT));
UIManager.put("ComboBox.disabledBackground", FSkin.getColor(FSkin.Colors.CLR_THEME2));
UIManager.put("ComboBox.disabledForeground", FSkin.getColor(FSkin.Colors.CLR_THEME2).darker());
UIManager.put("Button.select", FSkin.getColor(FSkin.Colors.CLR_ACTIVE));
UIManager.put("ComboBox.font", FSkin.getFont(UIManager.getFont("ComboBox.font").getSize()));
private void setForgeLookAndFeel() {
ForgeLookAndFeel laf = new ForgeLookAndFeel();
laf.setForgeLookAndFeel(Singletons.getView().getFrame());
}
private void createMenuBar() {
if (MenuUtil.isMenuBarVisible()) {
this.menuBar = new FMenuBar(Singletons.getView().getFrame());
}
}

View File

@@ -49,7 +49,7 @@ public class CardCollections {
public CardCollections() {
StopWatch sw = new StopWatch();
sw.start();
this.constructed = new StorageImmediatelySerialized<Deck>(new DeckSerializer(new File(NewConstants.DECK_CONSTRUCTED_DIR), true));
this.constructed = new StorageImmediatelySerialized<Deck>(new DeckSerializer(new File(NewConstants.DECK_CONSTRUCTED_DIR), true), true);
this.draft = new StorageImmediatelySerialized<DeckGroup>(new DeckGroupSerializer(new File(NewConstants.DECK_DRAFT_DIR)));
this.sealed = new StorageImmediatelySerialized<DeckGroup>(new DeckGroupSerializer(new File(NewConstants.DECK_SEALED_DIR)));
this.cube = new StorageImmediatelySerialized<Deck>(new DeckSerializer(new File(NewConstants.DECK_CUBE_DIR)));

View File

@@ -77,6 +77,13 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
getOrCreate(DeckSection.Main);
}
/* (non-Javadoc)
* @see forge.item.InventoryItem#getItemType()
*/
@Override
public String getItemType() {
return "Deck";
}
@Override
public int hashCode() {

View File

@@ -19,11 +19,13 @@ package forge.deck;
import java.io.Serializable;
import forge.item.InventoryItem;
/**
* TODO: Write javadoc for this type.
*
*/
public abstract class DeckBase implements Serializable, Comparable<DeckBase> {
public abstract class DeckBase implements Serializable, Comparable<DeckBase>, InventoryItem {
private static final long serialVersionUID = -7538150536939660052L;
// gameType is from Constant.GameType, like GameType.Regular

View File

@@ -135,4 +135,13 @@ public class DeckGroup extends DeckBase {
}
};
/* (non-Javadoc)
* @see forge.item.InventoryItem#getItemType()
*/
@Override
public String getItemType() {
// TODO Auto-generated method stub
return "Set of limited mode decks";
}
}

View File

@@ -105,7 +105,16 @@ public class DeckgenUtil {
* @return {@link forge.deck.Deck}
*/
public static Deck getConstructedDeck(final String selection) {
return Singletons.getModel().getDecks().getConstructed().get(selection);
IStorage<Deck> path = Singletons.getModel().getDecks().getConstructed();
String name = selection;
int idxSlash = name.indexOf('/');
while( idxSlash > 0 ) {
String sf = name.substring(0, idxSlash).trim();
path = path.getFolders().get(sf);
name = name.substring(idxSlash+1).trim();
idxSlash = name.indexOf('/');
};
return path.get(name);
}
public static Deck getPreconDeck(String selection) {

View File

@@ -23,6 +23,8 @@ import java.util.List;
import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.ImmutableList;
import forge.deck.Deck;
import forge.deck.DeckGroup;
import forge.util.FileUtil;
@@ -111,7 +113,7 @@ public class DeckGroupSerializer extends StorageReaderFolder<DeckGroup> implemen
* @return the file
*/
public File makeFileFor(final DeckGroup decks) {
return new File(this.getDirectory(), decks.getBestFileName());
return new File(this.directory, decks.getBestFileName());
}
/*
@@ -134,4 +136,10 @@ public class DeckGroupSerializer extends StorageReaderFolder<DeckGroup> implemen
};
}
@Override
public Iterable<File> getSubFolders() {
// Sealed decks are kept in separate folders, no further drilling possible
return ImmutableList.of();
}
}

View File

@@ -40,6 +40,7 @@ import forge.properties.NewConstants;
import forge.util.FileSection;
import forge.util.FileSectionManual;
import forge.util.FileUtil;
import forge.util.IItemReader;
import forge.util.IItemSerializer;
import forge.util.storage.StorageReaderFolder;
import freemarker.template.Configuration;
@@ -194,7 +195,7 @@ public class DeckSerializer extends StorageReaderFolder<Deck> implements IItemSe
}
public File makeFileFor(final Deck deck) {
return new File(this.getDirectory(), deck.getBestFileName() + FILE_EXTENSION);
return new File(this.directory, deck.getBestFileName() + FILE_EXTENSION);
}
@Override
@@ -245,4 +246,14 @@ public class DeckSerializer extends StorageReaderFolder<Deck> implements IItemSe
return null;
}
/* (non-Javadoc)
* @see forge.util.storage.StorageReaderBase#getReaderForFolder(java.io.File)
*/
@Override
public IItemReader<Deck> getReaderForFolder(File subfolder) {
if ( !subfolder.getParentFile().equals(directory) )
throw new UnsupportedOperationException("Only child folders of " + directory + " may be processed");
return new DeckSerializer(subfolder, false);
}
}

View File

@@ -18,6 +18,7 @@
package forge.game.ai;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import com.google.common.base.Predicate;
@@ -28,6 +29,9 @@ import forge.CardLists;
import forge.CardPredicates;
import forge.CounterType;
import forge.GameEntity;
import forge.card.TriggerReplacementBase;
import forge.card.trigger.Trigger;
import forge.card.trigger.TriggerType;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.player.Player;
@@ -197,7 +201,7 @@ public class AiBlockController {
// 1.Blockers that can destroy the attacker but won't get
// destroyed
killingBlockers = getKillingBlockers(combat, attacker, safeBlockers);
if (killingBlockers.size() > 0) {
if (!killingBlockers.isEmpty()) {
blocker = ComputerUtilCard.getWorstCreatureAI(killingBlockers);
} else if (!attacker.hasKeyword("You may have CARDNAME assign its combat damage as though it weren't blocked.")) {
blocker = ComputerUtilCard.getWorstCreatureAI(safeBlockers);
@@ -215,11 +219,34 @@ public class AiBlockController {
}
}
// 4.Blockers that can destroy the attacker and are worth less
if (blocker == null && killingBlockers.size() > 0) {
if (blocker == null && !killingBlockers.isEmpty()) {
final Card worst = ComputerUtilCard.getWorstCreatureAI(killingBlockers);
int value = ComputerUtilCard.evaluateCreature(attacker);
if ((ComputerUtilCard.evaluateCreature(worst) + diff) < ComputerUtilCard
.evaluateCreature(attacker)) {
// check for triggers when unblocked
for (Trigger trigger : attacker.getTriggers()) {
final HashMap<String, String> trigParams = trigger.getMapParams();
TriggerType mode = trigger.getMode();
if (!trigger.requirementsCheck(attacker.getGame())) {
continue;
}
if (mode == TriggerType.DamageDone) {
if (TriggerReplacementBase.matchesValid(attacker, trigParams.get("ValidSource").split(","), attacker)
&& attacker.getNetCombatDamage() > 0
&& (!trigParams.containsKey("ValidTarget")
|| TriggerReplacementBase.matchesValid(combat.getDefenderByAttacker(attacker), trigParams.get("ValidTarget").split(","), attacker))) {
value += 50;
}
} else if (mode == TriggerType.AttackerUnblocked) {
if (TriggerReplacementBase.matchesValid(attacker, trigParams.get("ValidCard").split(","), attacker)) {
value += 50;
}
}
}
if ((ComputerUtilCard.evaluateCreature(worst) + diff) < value) {
blocker = worst;
}
}
@@ -378,14 +405,13 @@ public class AiBlockController {
List<Card> possibleBlockers = getPossibleBlockers(combat, attacker, blockersLeft, true);
killingBlockers = getKillingBlockers(combat, attacker, possibleBlockers);
if ((killingBlockers.size() > 0) && ComputerUtilCombat.lifeInDanger(ai, combat)) {
if (!killingBlockers.isEmpty() && ComputerUtilCombat.lifeInDanger(ai, combat)) {
final Card blocker = ComputerUtilCard.getWorstCreatureAI(killingBlockers);
combat.addBlocker(attacker, blocker);
currentAttackers.remove(attacker);
}
}
attackersLeft = (new ArrayList<Card>(currentAttackers));
}
// Chump Blocks (should only be made if life is in danger)

View File

@@ -82,6 +82,15 @@ public class CustomLimited extends DeckBase {
return this.getName();
}
/* (non-Javadoc)
* @see forge.item.InventoryItem#getItemType()
*/
@Override
public String getItemType() {
// TODO Auto-generated method stub
return "Limited game setup";
}
/**
* Parses the.
*

View File

@@ -38,6 +38,7 @@ import forge.gui.deckeditor.views.VDeckgen;
import forge.gui.framework.DragCell;
import forge.gui.framework.EDocID;
import forge.gui.toolbox.FLabel;
import forge.gui.toolbox.itemmanager.CardManager;
import forge.gui.toolbox.itemmanager.ItemManager;
import forge.gui.toolbox.itemmanager.SItemManagerIO;
import forge.gui.toolbox.itemmanager.SItemManagerUtil;
@@ -86,8 +87,10 @@ public final class CEditorCommander extends ACEditorBase<PaperCard, Deck> {
commanderPool = ItemPool.createFrom(CardDb.instance().getAllCards(Predicates.compose(Predicates.and(CardRulesPredicates.Presets.IS_CREATURE,CardRulesPredicates.Presets.IS_LEGENDARY), PaperCard.FN_GET_RULES)),PaperCard.class);
normalPool = ItemPool.createFrom(CardDb.instance().getAllCards(), PaperCard.class);
final ItemManager<PaperCard> catalogManager = new ItemManager<PaperCard>(PaperCard.class, VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), true);
final ItemManager<PaperCard> deckManager = new ItemManager<PaperCard>(PaperCard.class, VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), true);
boolean wantUnique = SItemManagerIO.getPref(EditorPreference.display_unique_only);
final CardManager catalogManager = new CardManager(VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), wantUnique);
final CardManager deckManager = new CardManager(VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), wantUnique);
VCardCatalog.SINGLETON_INSTANCE.setItemManager(catalogManager);
VCurrentDeck.SINGLETON_INSTANCE.setItemManager(deckManager);

View File

@@ -35,7 +35,7 @@ import forge.gui.deckeditor.views.VCardCatalog;
import forge.gui.deckeditor.views.VCurrentDeck;
import forge.gui.framework.EDocID;
import forge.gui.toolbox.FLabel;
import forge.gui.toolbox.itemmanager.ItemManager;
import forge.gui.toolbox.itemmanager.CardManager;
import forge.gui.toolbox.itemmanager.SItemManagerIO;
import forge.gui.toolbox.itemmanager.SItemManagerUtil;
import forge.gui.toolbox.itemmanager.SItemManagerIO.EditorPreference;
@@ -92,8 +92,8 @@ public final class CEditorConstructed extends ACEditorBase<PaperCard, Deck> {
boolean wantUnique = SItemManagerIO.getPref(EditorPreference.display_unique_only);
final ItemManager<PaperCard> catalogManager = new ItemManager<PaperCard>(PaperCard.class, VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), wantUnique);
final ItemManager<PaperCard> deckManager = new ItemManager<PaperCard>(PaperCard.class, VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), wantUnique);
final CardManager catalogManager = new CardManager(VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), wantUnique);
final CardManager deckManager = new CardManager(VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), wantUnique);
VCardCatalog.SINGLETON_INSTANCE.setItemManager(catalogManager);
VCurrentDeck.SINGLETON_INSTANCE.setItemManager(deckManager);

View File

@@ -37,7 +37,7 @@ import forge.gui.deckeditor.views.VCurrentDeck;
import forge.gui.deckeditor.views.VDeckgen;
import forge.gui.framework.DragCell;
import forge.gui.home.sanctioned.CSubmenuDraft;
import forge.gui.toolbox.itemmanager.ItemManager;
import forge.gui.toolbox.itemmanager.CardManager;
import forge.gui.toolbox.itemmanager.table.SColumnUtil;
import forge.item.PaperCard;
import forge.item.InventoryItem;
@@ -64,8 +64,8 @@ public class CEditorDraftingProcess extends ACEditorBase<PaperCard, DeckGroup> {
* Updates the deck editor UI as necessary draft selection mode.
*/
public CEditorDraftingProcess() {
final ItemManager<PaperCard> catalogManager = new ItemManager<PaperCard>(PaperCard.class, VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), false);
final ItemManager<PaperCard> deckManager = new ItemManager<PaperCard>(PaperCard.class, VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), false);
final CardManager catalogManager = new CardManager(VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), false);
final CardManager deckManager = new CardManager(VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), false);
VCardCatalog.SINGLETON_INSTANCE.setItemManager(catalogManager);
VCurrentDeck.SINGLETON_INSTANCE.setItemManager(deckManager);

View File

@@ -30,7 +30,7 @@ import forge.gui.deckeditor.views.VDeckgen;
import forge.gui.framework.DragCell;
import forge.gui.home.sanctioned.CSubmenuDraft;
import forge.gui.home.sanctioned.CSubmenuSealed;
import forge.gui.toolbox.itemmanager.ItemManager;
import forge.gui.toolbox.itemmanager.CardManager;
import forge.gui.toolbox.itemmanager.SItemManagerUtil;
import forge.gui.toolbox.itemmanager.table.SColumnUtil;
import forge.item.PaperCard;
@@ -59,8 +59,8 @@ public final class CEditorLimited extends ACEditorBase<PaperCard, DeckGroup> {
* @param deckMap0 &emsp; {@link forge.deck.DeckGroup}<{@link forge.util.storage.IStorage}>
*/
public CEditorLimited(final IStorage<DeckGroup> deckMap0) {
final ItemManager<PaperCard> catalogManager = new ItemManager<PaperCard>(PaperCard.class, VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), false);
final ItemManager<PaperCard> deckManager = new ItemManager<PaperCard>(PaperCard.class, VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), false);
final CardManager catalogManager = new CardManager(VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), false);
final CardManager deckManager = new CardManager(VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), false);
VCardCatalog.SINGLETON_INSTANCE.setItemManager(catalogManager);
VCurrentDeck.SINGLETON_INSTANCE.setItemManager(deckManager);

View File

@@ -38,7 +38,7 @@ import forge.gui.deckeditor.views.VDeckgen;
import forge.gui.framework.DragCell;
import forge.gui.home.quest.CSubmenuQuestDecks;
import forge.gui.toolbox.FLabel;
import forge.gui.toolbox.itemmanager.ItemManager;
import forge.gui.toolbox.itemmanager.CardManager;
import forge.gui.toolbox.itemmanager.SItemManagerUtil;
import forge.gui.toolbox.itemmanager.table.TableColumnInfo;
import forge.gui.toolbox.itemmanager.table.SColumnUtil;
@@ -95,8 +95,8 @@ public final class CEditorQuest extends ACEditorBase<PaperCard, Deck> {
public CEditorQuest(final QuestController questData0) {
this.questData = questData0;
final ItemManager<PaperCard> catalogManager = new ItemManager<PaperCard>(PaperCard.class, VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), false);
final ItemManager<PaperCard> deckManager = new ItemManager<PaperCard>(PaperCard.class, VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), false);
final CardManager catalogManager = new CardManager(VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), false);
final CardManager deckManager = new CardManager(VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), false);
catalogManager.setAlwaysNonUnique(true);
deckManager.setAlwaysNonUnique(true);

View File

@@ -48,7 +48,7 @@ import forge.gui.framework.DragCell;
import forge.gui.home.quest.CSubmenuQuestDecks;
import forge.gui.toolbox.FLabel;
import forge.gui.toolbox.FSkin;
import forge.gui.toolbox.itemmanager.ItemManager;
import forge.gui.toolbox.itemmanager.InventoryItemManager;
import forge.gui.toolbox.itemmanager.SItemManagerUtil;
import forge.gui.toolbox.itemmanager.table.TableColumnInfo;
import forge.gui.toolbox.itemmanager.table.SColumnUtil;
@@ -127,8 +127,8 @@ public final class CEditorQuestCardShop extends ACEditorBase<InventoryItem, Deck
public CEditorQuestCardShop(final QuestController qd) {
this.questData = qd;
final ItemManager<InventoryItem> catalogManager = new ItemManager<InventoryItem>(InventoryItem.class, VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), false);
final ItemManager<InventoryItem> deckManager = new ItemManager<InventoryItem>(InventoryItem.class, VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), false);
final InventoryItemManager catalogManager = new InventoryItemManager(VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), false);
final InventoryItemManager deckManager = new InventoryItemManager(VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), false);
catalogManager.setAlwaysNonUnique(true);
deckManager.setAlwaysNonUnique(true);

View File

@@ -34,7 +34,7 @@ import forge.gui.deckeditor.views.VCurrentDeck;
import forge.gui.deckeditor.views.VDeckgen;
import forge.gui.framework.DragCell;
import forge.gui.framework.EDocID;
import forge.gui.toolbox.itemmanager.ItemManager;
import forge.gui.toolbox.itemmanager.CardManager;
import forge.gui.toolbox.itemmanager.SItemManagerUtil;
import forge.gui.toolbox.itemmanager.table.TableColumnInfo;
import forge.gui.toolbox.itemmanager.table.SColumnUtil;
@@ -74,8 +74,8 @@ public final class CEditorVariant extends ACEditorBase<PaperCard, Deck> {
cardPoolCondition = poolCondition;
exitToScreen = exitTo;
final ItemManager<PaperCard> catalogManager = new ItemManager<PaperCard>(PaperCard.class, VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), true);
final ItemManager<PaperCard> deckManager = new ItemManager<PaperCard>(PaperCard.class, VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), true);
final CardManager catalogManager = new CardManager(VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), true);
final CardManager deckManager = new CardManager(VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), true);
VCardCatalog.SINGLETON_INSTANCE.setItemManager(catalogManager);
VCurrentDeck.SINGLETON_INSTANCE.setItemManager(deckManager);

View File

@@ -118,6 +118,7 @@ public final class SResizingUtil {
final JPanel pnlInsets = FView.SINGLETON_INSTANCE.getPnlInsets();
Rectangle mainBounds = FView.SINGLETON_INSTANCE.getFrame().getContentPane().getBounds();
mainBounds.y = 0; // Play nicely with MenuBar if visible or not.
FAbsolutePositioner.SINGLETON_INSTANCE.containerResized(mainBounds);
FOverlay.SINGLETON_INSTANCE.getPanel().setBounds(mainBounds);
FNetOverlay.SINGLETON_INSTANCE.containerResized(mainBounds);

View File

@@ -0,0 +1,51 @@
package forge.gui.menubar;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import forge.gui.menus.ForgeMenu;
import forge.gui.menus.HelpMenu;
@SuppressWarnings("serial")
public class FMenuBar extends JMenuBar {
public FMenuBar(JFrame f) {
f.setJMenuBar(this);
setPreferredSize(new Dimension(f.getWidth(), 26));
setupMenuBar(null);
}
public void setupMenuBar(IMenuProvider provider) {
removeAll();
add(ForgeMenu.getMenu());
addProviderMenus(provider);
add(HelpMenu.getMenu());
repaint();
}
private void addProviderMenus(IMenuProvider provider) {
if (provider != null && provider.getMenus() != null) {
for (JMenu m : provider.getMenus()) {
m.setBorderPainted(false);
add(m);
}
}
}
/**
* Enables or disables the MenuBar.
* <p>
* Note: Disabling a component does not disable its children.
*/
public void setMenuBarEnabled(boolean isEnabled) {
setEnabled(isEnabled);
for (Component c : getComponents()) {
c.setEnabled(isEnabled);
}
}
}

View File

@@ -0,0 +1,19 @@
package forge.gui.menubar;
import java.util.List;
import javax.swing.JMenu;
/**
* By implementing this interface a class can add menus to the menu bar
* by calling the {@code MenuBarManager.SetupMenuBar()} method.
*
*/
public interface IMenuProvider {
/**
* Returns a list of JMenu objects for display in MenuBar.
*/
List<JMenu> getMenus();
}

View File

@@ -0,0 +1,61 @@
package forge.gui.menubar;
import java.awt.Toolkit;
import java.io.IOException;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import forge.Singletons;
import forge.gui.toolbox.FSkin;
import forge.gui.toolbox.FSkin.SkinProp;
import forge.gui.toolbox.imaging.ImageUtil;
import forge.properties.ForgePreferences;
import forge.properties.ForgePreferences.FPref;
public final class MenuUtil {
private MenuUtil() { }
private static ForgePreferences prefs = Singletons.getModel().getPreferences();
// Get appropriate OS standard accelerator key for menu shortcuts.
private static final int DEFAULT_MenuShortcutKeyMask =
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
public static boolean isMenuBarVisible() {
return !prefs.getPrefBoolean(FPref.UI_HIDE_MENUBAR);
}
public static void openUrlInBrowser(String url) {
try {
java.awt.Desktop.getDesktop().browse(java.net.URI.create(url));
} catch (IOException e) {
// Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log.
e.printStackTrace();
}
}
public static ImageIcon getMenuIcon(SkinProp ico) {
return ImageUtil.getMenuIcon(FSkin.getIcon(ico));
}
public static KeyStroke getAcceleratorKey(int key) {
return KeyStroke.getKeyStroke(key, DEFAULT_MenuShortcutKeyMask);
}
public static boolean getUserConfirmation(String prompt, String dialogTitle) {
Object[] options = {"Yes", "No"};
int reply = JOptionPane.showOptionDialog(
null,
prompt,
dialogTitle,
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[1]);
return (reply == JOptionPane.YES_OPTION);
}
}

View File

@@ -0,0 +1,70 @@
package forge.gui.menus;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import forge.Singletons;
import forge.control.RestartUtil;
import forge.control.FControl.Screens;
import forge.gui.menubar.MenuUtil;
public final class ForgeMenu {
private ForgeMenu() { }
public static JMenu getMenu() {
JMenu menu = new JMenu("Forge");
menu.setMnemonic(KeyEvent.VK_F);
menu.add(getMenuItem_Restart());
menu.add(getMenuItem_Exit());
return menu;
}
private static JMenuItem getMenuItem_Exit() {
JMenuItem menuItem = new JMenuItem("Exit");
menuItem.addActionListener(getExitAction());
return menuItem;
}
private static ActionListener getExitAction() {
return new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (!isHomeScreenActive()) {
String userPrompt = "Please confirm you want to close Forge.\n\n";
if (!MenuUtil.getUserConfirmation(userPrompt, "Exit Forge")) {
return;
}
}
System.exit(0);
}
};
}
private static JMenuItem getMenuItem_Restart() {
JMenuItem menuItem = new JMenuItem("Restart");
menuItem.addActionListener(getRestartAction());
return menuItem;
}
private static ActionListener getRestartAction() {
return new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (!isHomeScreenActive()) {
String userPrompt = "Please confirm you want to restart Forge.\n\n";
if (!MenuUtil.getUserConfirmation(userPrompt, "Restart Forge")) {
return;
}
}
RestartUtil.restartApplication(null);
}
};
}
private static boolean isHomeScreenActive() {
return Singletons.getControl().getState() == Screens.HOME_SCREEN;
}
}

View File

@@ -0,0 +1,124 @@
package forge.gui.menus;
import java.awt.Desktop;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import forge.gui.menubar.MenuUtil;
import forge.util.FileUtil;
public final class HelpMenu {
private HelpMenu() { }
public static JMenu getMenu() {
JMenu menu = new JMenu("Help");
menu.setMnemonic(KeyEvent.VK_H);
menu.add(getMenu_GettingStarted());
menu.add(getMenu_Articles());
menu.add(getMenu_Troubleshooting());
menu.addSeparator();
menu.add(getMenuItem_ReleaseNotes());
menu.add(getMenuItem_License());
return menu;
}
private static JMenu getMenu_Troubleshooting() {
JMenu mnu = new JMenu("Troubleshooting");
mnu.add(getMenuItem_UrlLink("How to Provide a Useful Bug Report", "http://www.slightlymagic.net/forum/viewtopic.php?f=26&t=9621"));
mnu.addSeparator();
mnu.add(getMenuItem_ReadMeFile());
return mnu;
}
private static JMenu getMenu_Articles() {
JMenu mnu = new JMenu("Articles");
mnu.add(getMenuItem_UrlLink("HOW-TO: Customize your Sealed Deck games with fantasy blocks", "http://www.slightlymagic.net/forum/viewtopic.php?f=26&t=8164"));
mnu.add(getMenuItem_UrlLink("Quest Mode: Guide to Formats, Worlds, and everything", "http://www.slightlymagic.net/forum/viewtopic.php?f=26&t=9258"));
return mnu;
}
private static JMenu getMenu_GettingStarted() {
JMenu mnu = new JMenu("Getting Started");
mnu.add(getMenuItem_UrlLink("Forge Wiki", "http://www.slightlymagic.net/wiki/Forge"));
mnu.add(getMenuItem_UrlLink("What is Forge?", "http://www.slightlymagic.net/forum/viewtopic.php?f=26&t=468"));
return mnu;
}
private static JMenuItem getMenuItem_ReadMeFile() {
JMenuItem menuItem = new JMenuItem("README.txt");
menuItem.addActionListener(getOpenFileAction(getFile("README.txt")));
return menuItem;
}
private static JMenuItem getMenuItem_License() {
JMenuItem menuItem = new JMenuItem("Forge License");
menuItem.addActionListener(getOpenFileAction(getFile("LICENSE.txt")));
return menuItem;
}
private static JMenuItem getMenuItem_ReleaseNotes() {
JMenuItem menuItem = new JMenuItem("Release Notes");
menuItem.addActionListener(getOpenFileAction(getFile("CHANGES.txt")));
return menuItem;
}
private static ActionListener getOpenFileAction(final File file) {
return new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
openFile(file);
} catch (IOException e1) {
// Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log.
e1.printStackTrace();
}
}
};
}
protected static File getFile(String filename) {
// !! Linux is case-sensitive so file name and extension need to match exactly !!
File file = null;
String filePath = FileUtil.pathCombine(System.getProperty("user.dir"), filename);
if (FileUtil.doesFileExist(filePath)) {
file = new File(filePath);
}
return file;
}
/**
* @see http://stackoverflow.com/questions/6273221/open-a-text-file-in-the-default-text-editor-via-java
*/
private static void openFile(File file) throws IOException {
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
String cmd = "rundll32 url.dll,FileProtocolHandler " + file.getCanonicalPath();
Runtime.getRuntime().exec(cmd);
}
else {
Desktop.getDesktop().open(file);
}
}
private static JMenuItem getMenuItem_UrlLink(String caption, String url) {
JMenuItem menuItem = new JMenuItem(caption);
menuItem.addActionListener(getLaunchUrlAction(url));
return menuItem;
}
private static ActionListener getLaunchUrlAction(final String url) {
return new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
MenuUtil.openUrlInBrowser(url);
}
};
}
}

View File

@@ -0,0 +1,116 @@
package forge.gui.toolbox;
import javax.swing.JComponent;
/**
* Helper class for doing custom layout
*
*/
public final class LayoutHelper {
private final int parentWidth, parentHeight;
private int x, y, lineBottom;
public LayoutHelper(JComponent parent) {
parentWidth = parent.getWidth();
parentHeight = parent.getHeight();
}
/**
* Layout component to fill remaining space of parent
* @param comp
*/
public void fill(final JComponent comp) {
if (x >= parentWidth) {
newLine();
}
include(comp, parentWidth - x, parentHeight - y);
}
/**
* Layout component to fill remaining space of current line
* @param comp
* @param height
*/
public void fillLine(final JComponent comp, int height) {
if (x >= parentWidth) {
newLine();
}
include(comp, parentWidth - x, height);
}
/**
* Include component in layout with a percentage width and fixed height
* @param comp
* @param widthPercent
* @param height
*/
public void include(final JComponent comp, float widthPercent, int height) {
include(comp, Math.round(parentWidth * widthPercent), height);
}
/**
* Include component in layout with a fixed width and percentage height
* @param comp
* @param width
* @param heightPercent
*/
public void include(final JComponent comp, int width, float heightPercent) {
include(comp, width, Math.round(parentHeight * heightPercent));
}
/**
* Include component in layout with a percentage width and height
* @param comp
* @param widthPercent
* @param heightPercent
*/
public void include(final JComponent comp, float widthPercent, float heightPercent) {
include(comp, Math.round(parentWidth * widthPercent), Math.round(parentHeight * heightPercent));
}
/**
* Include component in layout with a fixed width and height
* @param comp
* @param width
* @param height
*/
public void include(final JComponent comp, int width, int height) {
if (width <= 0 || height <= 0) { return; }
if (x + width > parentWidth) {
newLine();
if (width > parentWidth) {
width = parentWidth;
}
}
if (y + height > parentHeight) {
y = parentHeight - height;
if (y >= parentHeight) { return; }
}
comp.setBounds(x, y, width, height);
x += width + 3;
if (y + height > lineBottom) {
lineBottom = y + height;
}
}
/**
* Offset current layout helper position
* @param dx
* @param dy
*/
public void offset(int dx, int dy) {
x += dx;
y += dy;
}
/**
* Start new line of layout
*/
public void newLine() {
if (lineBottom == y) { return; }
x = 0;
y = lineBottom + 3;
lineBottom = y;
}
}

View File

@@ -19,6 +19,9 @@
package forge.gui.toolbox.imaging;
import java.awt.Dimension;
import java.awt.Image;
import javax.swing.ImageIcon;
/**
* Useful general imaging routines.
@@ -29,6 +32,12 @@ import java.awt.Dimension;
public final class ImageUtil {
private ImageUtil() {}
public static ImageIcon getMenuIcon(ImageIcon sourceIcon) {
Image img = sourceIcon.getImage();
Image newimg = img.getScaledInstance(16, 16, java.awt.Image.SCALE_SMOOTH);
return new ImageIcon(newimg);
}
/**
* Gets the nearest rotation for a requested rotation.
* <p>

View File

@@ -0,0 +1,113 @@
package forge.gui.toolbox.itemmanager;
import java.util.List;
import java.util.Map;
import javax.swing.JMenu;
import javax.swing.JPopupMenu;
import forge.Singletons;
import forge.game.GameFormat;
import forge.gui.GuiUtils;
import forge.gui.home.quest.DialogChooseSets;
import forge.gui.toolbox.FLabel;
import forge.gui.toolbox.itemmanager.SItemManagerUtil.StatTypes;
import forge.gui.toolbox.itemmanager.filters.CardCMCFilter;
import forge.gui.toolbox.itemmanager.filters.CardColorFilter;
import forge.gui.toolbox.itemmanager.filters.CardFormatFilter;
import forge.gui.toolbox.itemmanager.filters.CardPowerFilter;
import forge.gui.toolbox.itemmanager.filters.CardQuestWorldFilter;
import forge.gui.toolbox.itemmanager.filters.CardSearchFilter;
import forge.gui.toolbox.itemmanager.filters.CardSetFilter;
import forge.gui.toolbox.itemmanager.filters.CardToughnessFilter;
import forge.gui.toolbox.itemmanager.filters.CardTypeFilter;
import forge.gui.toolbox.itemmanager.filters.ItemFilter;
import forge.item.PaperCard;
import forge.quest.QuestWorld;
/**
* ItemManager for cards
*
*/
@SuppressWarnings("serial")
public final class CardManager extends ItemManager<PaperCard> {
public CardManager(Map<StatTypes, FLabel> statLabels0, boolean wantUnique0) {
super(PaperCard.class, statLabels0, wantUnique0);
this.addFilter(new CardColorFilter(this));
this.addFilter(new CardTypeFilter(this));
}
@Override
protected ItemFilter<PaperCard> createSearchFilter(String text) {
return new CardSearchFilter(this, text);
}
@Override
protected void buildFilterMenu(JPopupMenu menu) {
JMenu fmt = new JMenu("Format");
for (final GameFormat f : Singletons.getModel().getFormats()) {
GuiUtils.addMenuItem(fmt, f.getName(), null, new Runnable() {
@Override
public void run() {
addFilter(new CardFormatFilter(CardManager.this, f));
}
}, CardFormatFilter.canAddFormat(f, getFilter(CardFormatFilter.class)));
}
menu.add(fmt);
GuiUtils.addMenuItem(menu, "Sets...", null, new Runnable() {
@Override
public void run() {
CardSetFilter existingFilter = getFilter(CardSetFilter.class);
if (existingFilter != null) {
existingFilter.edit();
}
else {
final DialogChooseSets dialog = new DialogChooseSets(null, null, true);
dialog.setOkCallback(new Runnable() {
@Override
public void run() {
List<String> sets = dialog.getSelectedSets();
if (!sets.isEmpty()) {
addFilter(new CardSetFilter(CardManager.this, sets));
}
}
});
}
}
});
JMenu range = new JMenu("Value range");
GuiUtils.addMenuItem(range, "CMC", null, new Runnable() {
@Override
public void run() {
addFilter(new CardCMCFilter(CardManager.this));
}
}, getFilter(CardCMCFilter.class) == null);
GuiUtils.addMenuItem(range, "Power", null, new Runnable() {
@Override
public void run() {
addFilter(new CardPowerFilter(CardManager.this));
}
}, getFilter(CardPowerFilter.class) == null);
GuiUtils.addMenuItem(range, "Toughness", null, new Runnable() {
@Override
public void run() {
addFilter(new CardToughnessFilter(CardManager.this));
}
}, getFilter(CardToughnessFilter.class) == null);
menu.add(range);
JMenu world = new JMenu("Quest world");
for (final QuestWorld w : Singletons.getModel().getWorlds()) {
GuiUtils.addMenuItem(world, w.getName(), null, new Runnable() {
@Override
public void run() {
addFilter(new CardQuestWorldFilter(CardManager.this, w));
}
}, CardQuestWorldFilter.canAddQuestWorld(w, getFilter(CardQuestWorldFilter.class)));
}
menu.add(world);
}
}

View File

@@ -0,0 +1,32 @@
package forge.gui.toolbox.itemmanager;
import java.util.Map;
import javax.swing.JPopupMenu;
import forge.gui.toolbox.FLabel;
import forge.gui.toolbox.itemmanager.SItemManagerUtil.StatTypes;
import forge.gui.toolbox.itemmanager.filters.ItemFilter;
import forge.item.InventoryItem;
/**
* TODO: Write javadoc for this type.
*
*/
@SuppressWarnings("serial")
public final class InventoryItemManager extends ItemManager<InventoryItem> {
public InventoryItemManager(Map<StatTypes, FLabel> statLabels0, boolean wantUnique0) {
super(InventoryItem.class, statLabels0, wantUnique0);
}
@Override
protected ItemFilter<InventoryItem> createSearchFilter(String text) {
return null;
}
@Override
protected void buildFilterMenu(JPopupMenu menu) {
}
}

View File

@@ -17,6 +17,9 @@
*/
package forge.gui.toolbox.itemmanager;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@@ -24,8 +27,9 @@ import java.util.Map;
import java.util.Map.Entry;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import com.google.common.base.Predicate;
@@ -33,8 +37,11 @@ import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import forge.Command;
import forge.gui.GuiUtils;
import forge.gui.toolbox.FLabel;
import forge.gui.toolbox.FTextField;
import forge.gui.toolbox.LayoutHelper;
import forge.gui.toolbox.ToolTipListener;
import forge.gui.toolbox.itemmanager.filters.ItemFilter;
import forge.gui.toolbox.itemmanager.table.ItemTable;
@@ -43,6 +50,7 @@ import forge.item.InventoryItem;
import forge.item.ItemPool;
import forge.item.ItemPoolView;
import forge.util.Aggregates;
import forge.util.TypeUtil;
/**
@@ -51,21 +59,26 @@ import forge.util.Aggregates;
* @param <T>
* the generic type
*/
public final class ItemManager<T extends InventoryItem> extends JPanel {
private static final long serialVersionUID = 3164349984277267922L;
@SuppressWarnings("serial")
public abstract class ItemManager<T extends InventoryItem> extends JPanel {
private ItemPool<T> pool;
private final ItemManagerModel<T> model;
private Predicate<T> filterPredicate = null;
private final Map<ItemFilter.FilterTypes, ItemFilter<T>> filters =
new HashMap<ItemFilter.FilterTypes, ItemFilter<T>>();
private final Map<Class<? extends ItemFilter<T>>, List<ItemFilter<T>>> filters =
new HashMap<Class<? extends ItemFilter<T>>, List<ItemFilter<T>>>();
private final List<ItemFilter<T>> orderedFilters = new ArrayList<ItemFilter<T>>();
private boolean wantUnique = false;
private boolean alwaysNonUnique = false;
private final Class<T> genericType;
private final Map<SItemManagerUtil.StatTypes, FLabel> statLabels;
private final FLabel btnAddFilter = new FLabel.ButtonBuilder()
.text("Add")
.tooltip("Click to add filters to the list")
.reactOnMouseDown().build();
private final FTextField txtSearch = new FTextField.Builder().ghostText("Search").build();
private final ItemTable<T> table;
private final JScrollPane tableScroller;
private final JTextField txtSearch = new FTextField.Builder().ghostText("Search").build();
/**
* ItemManager Constructor.
@@ -74,7 +87,7 @@ public final class ItemManager<T extends InventoryItem> extends JPanel {
* @param statLabels0 stat labels for this item manager
* @param wantUnique0 whether this table should display only one item with the same name
*/
public ItemManager(final Class<T> genericType0, Map<SItemManagerUtil.StatTypes, FLabel> statLabels0, final boolean wantUnique0) {
protected ItemManager(final Class<T> genericType0, Map<SItemManagerUtil.StatTypes, FLabel> statLabels0, final boolean wantUnique0) {
this.genericType = genericType0;
this.statLabels = statLabels0;
this.wantUnique = wantUnique0;
@@ -92,25 +105,45 @@ public final class ItemManager<T extends InventoryItem> extends JPanel {
//build display
this.setOpaque(false);
this.setLayout(null);
this.add(this.btnAddFilter);
this.add(this.txtSearch);
this.add(this.tableScroller);
//setup command for btnAddFilter
final Command addFilterCommand = new Command() {
@Override
public void run() {
JPopupMenu menu = new JPopupMenu("FilterMenu");
GuiUtils.addMenuItem(menu, "Current text search",
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
new Runnable() {
@Override
public void run() {
ItemFilter<T> searchFilter = createSearchFilter(txtSearch.getText());
if (searchFilter != null) {
addFilter(searchFilter);
}
}
}, !txtSearch.isEmpty());
buildFilterMenu(menu);
menu.show(btnAddFilter, 0, btnAddFilter.getHeight());
}
};
this.btnAddFilter.setCommand(addFilterCommand);
this.btnAddFilter.setRightClickCommand(addFilterCommand); //show menu on right-click too
}
@Override
public void doLayout()
{
int x = 0;
int y = 0;
int width = this.getWidth();
int height = this.getHeight();
//position toolbar components //TODO: Uncomment
/*int toolbarHeight = FTextField.HEIGHT + 3;
this.txtSearch.setBounds(x, y, width / 2, FTextField.HEIGHT);
y += toolbarHeight;*/
//position current item view
this.tableScroller.setBounds(x, y, width, height - y);
LayoutHelper helper = new LayoutHelper(this);
/*helper.include(this.btnAddFilter, 30, FTextField.HEIGHT);
helper.include(this.txtSearch, 0.5f, FTextField.HEIGHT);
helper.newLine();
for (ItemFilter<T> filter : this.orderedFilters) {
helper.fillLine(filter.getPanel(), ItemFilter.PANEL_HEIGHT);
}*/
helper.fill(this.tableScroller);
}
/**
@@ -337,16 +370,48 @@ public final class ItemManager<T extends InventoryItem> extends JPanel {
return this.statLabels.get(s);
}
protected abstract ItemFilter<T> createSearchFilter(String text);
protected abstract void buildFilterMenu(JPopupMenu menu);
protected <F extends ItemFilter<T>> F getFilter(Class<F> filterClass) {
return TypeUtil.safeCast(this.filters.get(filterClass), filterClass);
}
@SuppressWarnings("unchecked")
public void addFilter(ItemFilter<T> filter) {
this.filters.put(filter.getType(), filter);
this.add(filter);
final Class<? extends ItemFilter<T>> filterClass = (Class<? extends ItemFilter<T>>) filter.getClass();
List<ItemFilter<T>> classFilters = this.filters.get(filterClass);
if (classFilters == null) {
classFilters = new ArrayList<ItemFilter<T>>();
this.filters.put(filterClass, classFilters);
}
if (classFilters.size() > 0) {
//if filter with the same class already exists, try to merge if allowed
//NOTE: can always use first filter for these checks since if
//merge is supported, only one will ever exist
ItemFilter<T> existingFilter = classFilters.get(0);
if (existingFilter.merge(filter)) {
//if new filter merged with existing filter, just update layout
this.revalidate();
return;
}
}
classFilters.add(filter);
this.add(filter.getPanel());
this.revalidate();
}
@SuppressWarnings("unchecked")
public void removeFilter(ItemFilter<T> filter) {
this.filters.remove(filter.getType());
this.remove(filter);
this.revalidate();
final Class<? extends ItemFilter<T>> filterClass = (Class<? extends ItemFilter<T>>) filter.getClass();
final List<ItemFilter<T>> classFilters = this.filters.get(filterClass);
if (classFilters != null && classFilters.remove(filter)) {
if (classFilters.size() == 0) {
this.filters.remove(filterClass);
}
this.remove(filter.getPanel());
this.revalidate();
}
}
public void buildFilterPredicate() {

View File

@@ -1,5 +1,7 @@
package forge.gui.toolbox.itemmanager.filters;
import javax.swing.JPanel;
import forge.gui.toolbox.itemmanager.ItemManager;
import forge.item.PaperCard;
@@ -7,7 +9,6 @@ import forge.item.PaperCard;
* TODO: Write javadoc for this type.
*
*/
@SuppressWarnings("serial")
public class CardCMCFilter extends ValueRangeFilter<PaperCard> {
public CardCMCFilter(ItemManager<PaperCard> itemManager0) {
@@ -15,12 +16,7 @@ public class CardCMCFilter extends ValueRangeFilter<PaperCard> {
}
@Override
public FilterTypes getType() {
return FilterTypes.CardCMC;
}
@Override
protected void addComponents() {
protected void buildPanel(JPanel panel) {
}

View File

@@ -1,26 +1,29 @@
package forge.gui.toolbox.itemmanager.filters;
import javax.swing.JPanel;
import forge.gui.toolbox.itemmanager.ItemManager;
import forge.gui.toolbox.itemmanager.SItemManagerUtil.StatTypes;
import forge.item.PaperCard;
/**
* TODO: Write javadoc for this type.
*
*/
@SuppressWarnings("serial")
public class CardColorFilter extends ToggleButtonsFilter<PaperCard> {
public CardColorFilter(ItemManager<PaperCard> itemManager0) {
super(itemManager0);
}
@Override
public FilterTypes getType() {
return FilterTypes.CardColor;
}
@Override
protected void addComponents() {
protected void buildPanel(JPanel panel) {
addToggleButton(panel, StatTypes.WHITE);
addToggleButton(panel, StatTypes.BLUE);
addToggleButton(panel, StatTypes.BLACK);
addToggleButton(panel, StatTypes.RED);
addToggleButton(panel, StatTypes.GREEN);
addToggleButton(panel, StatTypes.COLORLESS);
addToggleButton(panel, StatTypes.MULTICOLOR);
}
@Override

View File

@@ -1,5 +1,11 @@
package forge.gui.toolbox.itemmanager.filters;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JPanel;
import forge.game.GameFormat;
import forge.gui.toolbox.itemmanager.ItemManager;
import forge.item.PaperCard;
@@ -7,19 +13,33 @@ import forge.item.PaperCard;
* TODO: Write javadoc for this type.
*
*/
@SuppressWarnings("serial")
public class CardFormatFilter extends ListLabelFilter<PaperCard> {
public CardFormatFilter(ItemManager<PaperCard> itemManager0) {
private final Set<GameFormat> formats = new HashSet<GameFormat>();
public CardFormatFilter(ItemManager<PaperCard> itemManager0, GameFormat format0) {
super(itemManager0);
this.formats.add(format0);
}
public static boolean canAddFormat(GameFormat format, ItemFilter<PaperCard> existingFilter) {
return existingFilter == null || !((CardFormatFilter)existingFilter).formats.contains(format);
}
/**
* Merge the given filter with this filter if possible
* @param filter
* @return true if filter merged in or to suppress adding a new filter, false to allow adding new filter
*/
@Override
@SuppressWarnings("rawtypes")
public boolean merge(ItemFilter filter) {
CardFormatFilter cardFormatFilter = (CardFormatFilter)filter;
this.formats.addAll(cardFormatFilter.formats);
return true;
}
@Override
public FilterTypes getType() {
return FilterTypes.CardFormat;
}
@Override
protected void addComponents() {
protected void buildPanel(JPanel panel) {
}
@@ -27,4 +47,13 @@ public class CardFormatFilter extends ListLabelFilter<PaperCard> {
protected void onRemoved() {
}
@Override
protected Iterable<String> getList() {
Set<String> strings = new HashSet<String>();
for (GameFormat f : this.formats) {
strings.add(f.getName());
}
return strings;
}
}

View File

@@ -1,5 +1,7 @@
package forge.gui.toolbox.itemmanager.filters;
import javax.swing.JPanel;
import forge.gui.toolbox.itemmanager.ItemManager;
import forge.item.PaperCard;
@@ -7,19 +9,13 @@ import forge.item.PaperCard;
* TODO: Write javadoc for this type.
*
*/
@SuppressWarnings("serial")
public class CardPowerFilter extends ValueRangeFilter<PaperCard> {
public CardPowerFilter(ItemManager<PaperCard> itemManager0) {
super(itemManager0);
}
@Override
public FilterTypes getType() {
return FilterTypes.CardPower;
}
@Override
protected void addComponents() {
protected void buildPanel(JPanel panel) {
}

View File

@@ -1,25 +1,49 @@
package forge.gui.toolbox.itemmanager.filters;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JPanel;
import forge.Singletons;
import forge.gui.toolbox.itemmanager.ItemManager;
import forge.item.PaperCard;
import forge.quest.QuestWorld;
/**
* TODO: Write javadoc for this type.
*
*/
@SuppressWarnings("serial")
public class CardQuestWorldFilter extends ListLabelFilter<PaperCard> {
public CardQuestWorldFilter(ItemManager<PaperCard> itemManager0) {
private final Set<QuestWorld> questWorlds = new HashSet<QuestWorld>();
public CardQuestWorldFilter(ItemManager<PaperCard> itemManager0, QuestWorld questWorld0) {
super(itemManager0);
this.questWorlds.add(questWorld0);
}
public static boolean canAddQuestWorld(QuestWorld questWorld, ItemFilter<PaperCard> existingFilter) {
if (questWorld.getFormat() == null && Singletons.getModel().getQuest().getMainFormat() == null) {
return false; //must have format
}
return existingFilter == null || !((CardQuestWorldFilter)existingFilter).questWorlds.contains(questWorld);
}
/**
* Merge the given filter with this filter if possible
* @param filter
* @return true if filter merged in or to suppress adding a new filter, false to allow adding new filter
*/
@Override
@SuppressWarnings("rawtypes")
public boolean merge(ItemFilter filter) {
CardQuestWorldFilter cardQuestWorldFilter = (CardQuestWorldFilter)filter;
this.questWorlds.addAll(cardQuestWorldFilter.questWorlds);
return true;
}
@Override
public FilterTypes getType() {
return FilterTypes.CardQuestWorld;
}
@Override
protected void addComponents() {
protected void buildPanel(JPanel panel) {
}
@@ -27,4 +51,13 @@ public class CardQuestWorldFilter extends ListLabelFilter<PaperCard> {
protected void onRemoved() {
}
@Override
protected Iterable<String> getList() {
Set<String> strings = new HashSet<String>();
for (QuestWorld w : this.questWorlds) {
strings.add(w.getName());
}
return strings;
}
}

View File

@@ -0,0 +1,26 @@
package forge.gui.toolbox.itemmanager.filters;
import javax.swing.JPanel;
import forge.gui.toolbox.itemmanager.ItemManager;
import forge.item.PaperCard;
/**
* TODO: Write javadoc for this type.
*
*/
public class CardSearchFilter extends TextSearchFilter<PaperCard> {
public CardSearchFilter(ItemManager<PaperCard> itemManager0, String text0) {
super(itemManager0, text0);
}
@Override
protected void buildPanel(JPanel panel) {
}
@Override
protected void onRemoved() {
}
}

View File

@@ -1,5 +1,12 @@
package forge.gui.toolbox.itemmanager.filters;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JPanel;
import forge.gui.home.quest.DialogChooseSets;
import forge.gui.toolbox.itemmanager.ItemManager;
import forge.item.PaperCard;
@@ -7,19 +14,40 @@ import forge.item.PaperCard;
* TODO: Write javadoc for this type.
*
*/
@SuppressWarnings("serial")
public class CardSetFilter extends ListLabelFilter<PaperCard> {
public CardSetFilter(ItemManager<PaperCard> itemManager0) {
private final Set<String> sets = new HashSet<String>();
public CardSetFilter(ItemManager<PaperCard> itemManager0, Collection<String> sets) {
super(itemManager0);
this.sets.addAll(sets);
}
/**
* Merge the given filter with this filter if possible
* @param filter
* @return true if filter merged in or to suppress adding a new filter, false to allow adding new filter
*/
@Override
@SuppressWarnings("rawtypes")
public boolean merge(ItemFilter filter) {
CardSetFilter cardSetFilter = (CardSetFilter)filter;
this.sets.addAll(cardSetFilter.sets);
return true;
}
public void edit() {
final DialogChooseSets dialog = new DialogChooseSets(this.sets, null, true);
dialog.setOkCallback(new Runnable() {
@Override
public void run() {
sets.clear();
sets.addAll(dialog.getSelectedSets());
}
});
}
@Override
public FilterTypes getType() {
return FilterTypes.CardSet;
}
@Override
protected void addComponents() {
protected void buildPanel(JPanel panel) {
}
@@ -27,4 +55,9 @@ public class CardSetFilter extends ListLabelFilter<PaperCard> {
protected void onRemoved() {
}
@Override
protected Iterable<String> getList() {
return this.sets;
}
}

View File

@@ -1,5 +1,7 @@
package forge.gui.toolbox.itemmanager.filters;
import javax.swing.JPanel;
import forge.gui.toolbox.itemmanager.ItemManager;
import forge.item.PaperCard;
@@ -7,19 +9,13 @@ import forge.item.PaperCard;
* TODO: Write javadoc for this type.
*
*/
@SuppressWarnings("serial")
public class CardToughnessFilter extends ValueRangeFilter<PaperCard> {
public CardToughnessFilter(ItemManager<PaperCard> itemManager0) {
super(itemManager0);
}
@Override
public FilterTypes getType() {
return FilterTypes.CardToughness;
}
@Override
protected void addComponents() {
protected void buildPanel(JPanel panel) {
}

View File

@@ -1,26 +1,29 @@
package forge.gui.toolbox.itemmanager.filters;
import javax.swing.JPanel;
import forge.gui.toolbox.itemmanager.ItemManager;
import forge.gui.toolbox.itemmanager.SItemManagerUtil.StatTypes;
import forge.item.PaperCard;
/**
* TODO: Write javadoc for this type.
*
*/
@SuppressWarnings("serial")
public class CardTypeFilter extends ToggleButtonsFilter<PaperCard> {
public CardTypeFilter(ItemManager<PaperCard> itemManager0) {
super(itemManager0);
}
@Override
public FilterTypes getType() {
return FilterTypes.CardType;
}
@Override
protected void addComponents() {
protected void buildPanel(JPanel panel) {
addToggleButton(panel, StatTypes.LAND);
addToggleButton(panel, StatTypes.ARTIFACT);
addToggleButton(panel, StatTypes.CREATURE);
addToggleButton(panel, StatTypes.ENCHANTMENT);
addToggleButton(panel, StatTypes.PLANESWALKER);
addToggleButton(panel, StatTypes.INSTANT);
addToggleButton(panel, StatTypes.SORCERY);
}
@Override

View File

@@ -11,40 +11,62 @@ import forge.item.InventoryItem;
* TODO: Write javadoc for this type.
*
*/
@SuppressWarnings("serial")
public abstract class ItemFilter<T extends InventoryItem> extends JPanel {
public abstract class ItemFilter<T extends InventoryItem> {
private final ItemManager<T> itemManager;
private int number;
private JPanel panel;
public enum FilterTypes {
CardCMC,
CardColor,
CardFormat,
CardPower,
CardQuestWorld,
CardSet,
CardToughness,
CardType
}
public static int PANEL_HEIGHT = 30;
protected ItemFilter(ItemManager<T> itemManager0) {
this.itemManager = itemManager0;
this.setOpaque(false);
this.addComponents();
this.add(new FLabel.Builder().text("X").fontSize(10).hoverable(true)
.tooltip("Remove filter").cmdClick(new Command() {
}
public int getNumber() {
return this.number;
}
public void setNumber(int number0) {
this.number = number0;
}
@SuppressWarnings("serial")
public JPanel getPanel() {
if (this.panel == null) {
this.panel = new JPanel();
this.panel.setOpaque(false);
this.buildPanel(panel);
//add button to remove filter
this.panel.add(new FLabel.Builder()
.text("X")
.fontSize(10)
.hoverable(true)
.tooltip("Remove filter")
.cmdClick(new Command() {
@Override
public void run() {
itemManager.removeFilter(ItemFilter.this);
ItemFilter.this.onRemoved();
}
}).build(), "top");
}
return this.panel;
}
protected void applyChange() {
itemManager.buildFilterPredicate();
this.itemManager.buildFilterPredicate();
}
public abstract FilterTypes getType();
protected abstract void addComponents();
/**
* Merge the given filter with this filter if possible
* @param filter
* @return true if filter merged in or to suppress adding a new filter, false to allow adding new filter
*/
@SuppressWarnings("rawtypes")
public abstract boolean merge(ItemFilter filter);
protected abstract void buildPanel(JPanel panel);
protected abstract void onRemoved();
}

View File

@@ -7,10 +7,32 @@ import forge.item.InventoryItem;
* TODO: Write javadoc for this type.
*
*/
@SuppressWarnings("serial")
public abstract class ListLabelFilter<T extends InventoryItem> extends ItemFilter<T> {
protected ListLabelFilter(ItemManager<T> itemManager0) {
super(itemManager0);
}
protected abstract Iterable<String> getList();
public void buildPanel() {
StringBuilder label = new StringBuilder();
boolean truncated = false;
for (String str : getList()) {
// don't let the full label get too long
if (label.length() < 32) {
label.append(" ").append(str).append(";");
} else {
truncated = true;
break;
}
}
// chop off last semicolons
label.delete(label.length() - 1, label.length());
if (truncated) {
label.append("...");
}
}
}

View File

@@ -1,16 +0,0 @@
package forge.gui.toolbox.itemmanager.filters;
import forge.gui.toolbox.itemmanager.ItemManager;
import forge.item.InventoryItem;
/**
* TODO: Write javadoc for this type.
*
*/
@SuppressWarnings("serial")
public abstract class TextFieldFilter<T extends InventoryItem> extends ItemFilter<T> {
protected TextFieldFilter(ItemManager<T> itemManager0) {
super(itemManager0);
}
}

View File

@@ -0,0 +1,36 @@
package forge.gui.toolbox.itemmanager.filters;
import javax.swing.JPanel;
import forge.gui.toolbox.FTextField;
import forge.gui.toolbox.itemmanager.ItemManager;
import forge.item.InventoryItem;
/**
* TODO: Write javadoc for this type.
*
*/
public abstract class TextSearchFilter<T extends InventoryItem> extends ItemFilter<T> {
private String text;
protected TextSearchFilter(ItemManager<T> itemManager0, String text0) {
super(itemManager0);
this.text = text0;
}
/**
* Merge the given filter with this filter if possible
* @param filter
* @return true if filter merged in or to suppress adding a new filter, false to allow adding new filter
*/
@Override
@SuppressWarnings("rawtypes")
public boolean merge(ItemFilter filter) {
return false;
}
@Override
protected void buildPanel(JPanel panel) {
panel.add(new FTextField.Builder().text(this.text).build());
}
}

View File

@@ -1,6 +1,15 @@
package forge.gui.toolbox.itemmanager.filters;
import java.awt.Dimension;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import forge.Command;
import forge.gui.toolbox.FLabel;
import forge.gui.toolbox.itemmanager.ItemManager;
import forge.gui.toolbox.itemmanager.SItemManagerUtil.StatTypes;
import forge.item.InventoryItem;
/**
@@ -9,8 +18,60 @@ import forge.item.InventoryItem;
*/
@SuppressWarnings("serial")
public abstract class ToggleButtonsFilter<T extends InventoryItem> extends ItemFilter<T> {
private static final Dimension BUTTON_SIZE = new Dimension(60, 24);
private final ArrayList<FLabel> buttons = new ArrayList<FLabel>();
protected ToggleButtonsFilter(ItemManager<T> itemManager0) {
super(itemManager0);
}
protected void addToggleButton(JPanel panel, StatTypes s) {
addToggleButton(panel, s.toLabelString(), s.img);
}
protected void addToggleButton(JPanel panel, String filterName, ImageIcon icon) {
final FLabel button = new FLabel.Builder()
.icon(icon).iconScaleAuto(false)
.fontSize(11)
.tooltip(filterName + " (click to toggle the filter, right-click to show only " + filterName.toLowerCase() + ")")
.hoverable().selectable(true).selected(true)
.build();
button.setPreferredSize(BUTTON_SIZE);
button.setMinimumSize(BUTTON_SIZE);
button.setCommand(new Command() {
@Override
public void run() {
applyChange();
}
});
//hook so right-clicking a button toggles itself on and toggles off all other buttons
button.setRightClickCommand(new Command() {
@Override
public void run() {
for(FLabel btn : buttons) {
btn.setSelected(false);
}
button.setSelected(true);
applyChange();
}
});
this.buttons.add(button);
panel.add(button);
}
/**
* Merge the given filter with this filter if possible
* @param filter
* @return true if filter merged in or to suppress adding a new filter, false to allow adding new filter
*/
@Override
@SuppressWarnings("rawtypes")
public boolean merge(ItemFilter filter) {
return true;
}
}

View File

@@ -7,10 +7,20 @@ import forge.item.InventoryItem;
* TODO: Write javadoc for this type.
*
*/
@SuppressWarnings("serial")
public abstract class ValueRangeFilter<T extends InventoryItem> extends ItemFilter<T> {
protected ValueRangeFilter(ItemManager<T> itemManager0) {
super(itemManager0);
}
/**
* Merge the given filter with this filter if possible
* @param filter
* @return true if filter merged in or to suppress adding a new filter, false to allow adding new filter
*/
@Override
@SuppressWarnings("rawtypes")
public boolean merge(ItemFilter filter) {
return true;
}
}

View File

@@ -29,7 +29,7 @@ import forge.gui.toolbox.FList;
import forge.gui.toolbox.FRadioButton;
import forge.gui.toolbox.FScrollPane;
import forge.gui.toolbox.JXButtonPanel;
import forge.item.PreconDeck;
import forge.item.InventoryItem;
import forge.quest.QuestController;
import forge.quest.QuestEvent;
import forge.quest.QuestEventChallenge;
@@ -194,8 +194,7 @@ public class FDeckChooser extends JPanel {
lst.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
final List<String> customNames = new ArrayList<String>();
final IStorage<Deck> allDecks = Singletons.getModel().getDecks().getConstructed();
for (final Deck d : allDecks) { customNames.add(d.getName()); }
addDecksRecursive(Singletons.getModel().getDecks().getConstructed(), customNames, null);
lst.setListData(customNames.toArray(ArrayUtils.EMPTY_STRING_ARRAY));
lst.setName(DeckgenUtil.DeckTypes.CUSTOM.toString());
@@ -210,14 +209,23 @@ public class FDeckChooser extends JPanel {
lst.setSelectedIndex(0);
}
private <T extends InventoryItem> void addDecksRecursive(IStorage<T> node, List<String> customNames, String namePrefix ) {
String path = namePrefix == null ? "" : namePrefix + " / ";
for (final String fn : node.getFolders().getNames() )
{
IStorage<T> f = node.getFolders().get(fn);
addDecksRecursive(f, customNames, path + fn);
}
for (final T d : node) { customNames.add(path + d.getName()); }
}
/** Handles all control for "custom" radio button click. */
private void updatePrecons() {
final JList<String> lst = getLstDecks();
lst.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
final List<String> customNames = new ArrayList<String>();
final IStorage<PreconDeck> allDecks = QuestController.getPrecons();
for (final PreconDeck d : allDecks) { customNames.add(d.getName()); }
addDecksRecursive(QuestController.getPrecons(), customNames, null);
lst.setListData(customNames.toArray(ArrayUtils.EMPTY_STRING_ARRAY));
lst.setName(DeckgenUtil.DeckTypes.PRECON.toString());

View File

@@ -0,0 +1,166 @@
package forge.properties;
import java.awt.Color;
import java.awt.Font;
import java.util.ArrayList;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;
import forge.Singletons;
import forge.gui.toolbox.FSkin;
import forge.properties.ForgePreferences.FPref;
/**
* Sets the look and feel of the GUI based on the selected Forge theme.
*
* @see <a href="http://tips4java.wordpress.com/2008/10/09/uimanager-defaults/">UIManager Defaults</a>
*/
public final class ForgeLookAndFeel {
private Color FORE_COLOR = FSkin.getColor(FSkin.Colors.CLR_TEXT);
private Color BACK_COLOR = FSkin.getColor(FSkin.Colors.CLR_THEME2);
private Color HIGHLIGHT_COLOR = BACK_COLOR.brighter();
private Border LINE_BORDER = BorderFactory.createLineBorder(FORE_COLOR.darker(), 1);
private Border EMPTY_BORDER = BorderFactory.createEmptyBorder(2,2,2,2);
/**
* Sets the look and feel of the GUI based on the selected Forge theme.
*/
public void setForgeLookAndFeel(JFrame appFrame) {
if (isUIManagerEnabled()) {
if (setMetalLookAndFeel(appFrame)) {
setMenusLookAndFeel();
setComboBoxLookAndFeel();
setTabbedPaneLookAndFeel();
setButtonLookAndFeel();
}
}
}
/**
* Sets the standard "Java L&F" (also called "Metal") that looks the same on all platforms.
* <p>
* If not explicitly set then the Mac uses its native L&F which does
* not support various settings (eg. combobox background color).
*/
private boolean setMetalLookAndFeel(JFrame appFrame) {
boolean isMetalLafSet = false;
try {
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
SwingUtilities.updateComponentTreeUI(appFrame);
isMetalLafSet = true;
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
// Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log.
e.printStackTrace();
}
return isMetalLafSet;
}
/**
* Sets the look and feel for a JMenuBar, JMenu, JMenuItem & variations.
*/
private void setMenusLookAndFeel() {
// JMenuBar
Color clrTheme = FSkin.getColor(FSkin.Colors.CLR_THEME);
Color backgroundColor = FSkin.stepColor(clrTheme, 0);
Color menuBarEdgeColor = FSkin.stepColor(clrTheme, -80);
UIManager.put("MenuBar.foreground", FORE_COLOR);
UIManager.put("MenuBar.gradient", getColorGradients(backgroundColor.darker(), backgroundColor));
UIManager.put("MenuBar.border", BorderFactory.createMatteBorder(0, 0, 1, 0, menuBarEdgeColor));
// JMenu
UIManager.put("Menu.foreground", FORE_COLOR);
UIManager.put("Menu.background", BACK_COLOR);
UIManager.put("Menu.borderPainted", false);
UIManager.put("Menu.selectionBackground", HIGHLIGHT_COLOR);
UIManager.put("Menu.selectionForeground", FORE_COLOR);
UIManager.put("Menu.border", EMPTY_BORDER);
UIManager.put("Menu.opaque", false);
// JPopupMenu
UIManager.put("PopupMenu.border", LINE_BORDER);
UIManager.put("PopupMenu.background", BACK_COLOR);
UIManager.put("PopupMenu.foreground", FORE_COLOR);
// JMenuItem
UIManager.put("MenuItem.foreground", FORE_COLOR);
UIManager.put("MenuItem.background", BACK_COLOR);
UIManager.put("MenuItem.border", EMPTY_BORDER);
UIManager.put("MenuItem.selectionBackground", HIGHLIGHT_COLOR);
UIManager.put("MenuItem.selectionForeground", FORE_COLOR);
UIManager.put("MenuItem.acceleratorForeground", FORE_COLOR.darker());
UIManager.put("MenuItem.opaque", true);
// JSeparator (needs to be opaque!).
UIManager.put("Separator.foreground", FORE_COLOR.darker());
UIManager.put("Separator.background", BACK_COLOR);
// JRadioButtonMenuItem
UIManager.put("RadioButtonMenuItem.foreground", FORE_COLOR);
UIManager.put("RadioButtonMenuItem.background", BACK_COLOR);
UIManager.put("RadioButtonMenuItem.selectionBackground", HIGHLIGHT_COLOR);
UIManager.put("RadioButtonMenuItem.selectionForeground", FORE_COLOR);
UIManager.put("RadioButtonMenuItem.border", EMPTY_BORDER);
UIManager.put("RadioButtonMenuItem.acceleratorForeground", FORE_COLOR.darker());
// JCheckboxMenuItem
UIManager.put("CheckBoxMenuItem.foreground", FORE_COLOR);
UIManager.put("CheckBoxMenuItem.background", BACK_COLOR);
UIManager.put("CheckBoxMenuItem.selectionBackground", HIGHLIGHT_COLOR);
UIManager.put("CheckBoxMenuItem.selectionForeground", FORE_COLOR);
UIManager.put("CheckBoxMenuItem.border", EMPTY_BORDER);
UIManager.put("CheckBoxMenuItem.acceleratorForeground", FORE_COLOR.darker());
}
private void setTabbedPaneLookAndFeel() {
UIManager.put("TabbedPane.selected", HIGHLIGHT_COLOR);
UIManager.put("TabbedPane.contentOpaque", FSkin.getColor(FSkin.Colors.CLR_THEME));
UIManager.put("TabbedPane.unselectedBackground", BACK_COLOR);
}
/**
* Sets the look and feel for a <b>non-editable</b> JComboBox.
*/
private void setComboBoxLookAndFeel() {
UIManager.put("ComboBox.background", BACK_COLOR);
UIManager.put("ComboBox.foreground", FORE_COLOR);
UIManager.put("ComboBox.selectionBackground", HIGHLIGHT_COLOR);
UIManager.put("ComboBox.selectionForeground", FORE_COLOR);
UIManager.put("ComboBox.disabledBackground", BACK_COLOR);
UIManager.put("ComboBox.disabledForeground", BACK_COLOR.darker());
UIManager.put("ComboBox.font", getDefaultFont("ComboBox.font"));
UIManager.put("Button.select", HIGHLIGHT_COLOR);
}
private void setButtonLookAndFeel() {
UIManager.put("Button.foreground", FORE_COLOR);
UIManager.put("Button.background", BACK_COLOR);
UIManager.put("Button.select", HIGHLIGHT_COLOR);
UIManager.put("Button.focus", FORE_COLOR.darker());
UIManager.put("Button.rollover", false);
}
/**
* Determines whether theme styles should be applied to GUI.
* <p>
* TODO: Currently is using UI_THEMED_COMBOBOX setting but will
* eventually want to rename for clarity.
*/
private boolean isUIManagerEnabled() {
return Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_THEMED_COMBOBOX);
}
private Font getDefaultFont(String component) {
return FSkin.getFont(UIManager.getFont(component).getSize());
}
private ArrayList<Object> getColorGradients(Color bottom, Color top) {
ArrayList<Object> gradients = new ArrayList<>();
gradients.add(0.0);
gradients.add(0.0);
gradients.add(top);
gradients.add(bottom);
gradients.add(bottom);
return gradients;
}
}

View File

@@ -61,6 +61,7 @@ public class ForgePreferences extends PreferencesStore<ForgePreferences.FPref> {
UI_CLONE_MODE_SOURCE ("false"), /** */
UI_MATCH_IMAGE_VISIBLE ("true"),
UI_THEMED_COMBOBOX ("true"),
UI_HIDE_MENUBAR ("false"), // Dev setting only - cannot be set from GUI.
UI_FOR_TOUCHSCREN("false"),

View File

@@ -17,6 +17,7 @@
*/
package forge.util;
import java.io.File;
import java.util.Map;
/**
@@ -41,4 +42,8 @@ public interface IItemReader<T> {
* @return the item key
*/
String getItemKey(T item);
Iterable<File> getSubFolders();
IItemReader<T> getReaderForFolder(File subfolder);
}

View File

@@ -0,0 +1,21 @@
package forge.util;
/**
* TODO: Write javadoc for this type.
*
*/
public class TypeUtil {
/**
* Cast object to a given type if possible, returning null if not possible
* @param obj
* @param type
*/
@SuppressWarnings("unchecked")
public static <T> T safeCast(Object obj, Class<T> type) {
if (type.isInstance(obj)) {
return (T) obj;
}
return null;
}
}

View File

@@ -17,6 +17,9 @@
*/
package forge.util.storage;
import com.google.common.base.Function;
import forge.util.IItemReader;
import forge.util.IItemSerializer;
//reads and writeDeck Deck objects
@@ -32,6 +35,15 @@ import forge.util.IItemSerializer;
public class StorageImmediatelySerialized<T> extends StorageBase<T> {
private final IItemSerializer<T> serializer;
private final IStorage<IStorage<T>> subfolders;
private final Function<IItemReader<T>, IStorage<T>> nestedFactory = new Function<IItemReader<T>, IStorage<T>>() {
@Override
public IStorage<T> apply(IItemReader<T> io) {
return new StorageImmediatelySerialized<T>((IItemSerializer<T>) io, true);
}
};
/**
* <p>
* Constructor for DeckManager.
@@ -40,8 +52,14 @@ public class StorageImmediatelySerialized<T> extends StorageBase<T> {
* @param io the io
*/
public StorageImmediatelySerialized(final IItemSerializer<T> io) {
this(io, false);
}
public StorageImmediatelySerialized(final IItemSerializer<T> io, boolean withSubFolders) {
super(io);
this.serializer = io;
subfolders = withSubFolders ? new StorageNestedFolders<T>(io, nestedFactory) : null;
}
/*
@@ -65,4 +83,12 @@ public class StorageImmediatelySerialized<T> extends StorageBase<T> {
public final void delete(final String deckName) {
this.serializer.erase(this.map.remove(deckName));
}
/* (non-Javadoc)
* @see forge.util.storage.StorageBase#getFolders()
*/
@Override
public IStorage<IStorage<T>> getFolders() {
return subfolders == null ? super.getFolders() : subfolders;
}
}

View File

@@ -0,0 +1,36 @@
package forge.util.storage;
import java.io.File;
import java.util.HashMap;
import org.apache.commons.lang.NotImplementedException;
import com.google.common.base.Function;
import forge.util.IItemReader;
public class StorageNestedFolders<T> extends StorageBase<IStorage<T>> {
public StorageNestedFolders(IItemReader<T> io, Function<IItemReader<T>, IStorage<T>> factory) {
super(new HashMap<String, IStorage<T>>());
for(File sf : io.getSubFolders() )
{
map.put(sf.getName(), factory.apply(io.getReaderForFolder(sf)));
}
}
// need code implementations for folder create/delete operations
@Override
public void add(IStorage<T> deck) {
// need folder name here!
throw new NotImplementedException();
}
@Override
public void delete(String deckName) {
throw new NotImplementedException();
}
}

View File

@@ -0,0 +1,27 @@
package forge.util.storage;
import java.io.File;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import forge.util.IItemReader;
public abstract class StorageReaderBase<T> implements IItemReader<T> {
protected final Function<? super T, String> keySelector;
public StorageReaderBase(final Function<? super T, String> keySelector0) {
keySelector = keySelector0;
}
@Override
public Iterable<File> getSubFolders() {
// TODO Auto-generated method stub
return ImmutableList.of();
}
@Override
public IItemReader<T> getReaderForFolder(File subfolder) {
throw new UnsupportedOperationException("This reader is not supposed to have nested folders");
}
}

View File

@@ -28,7 +28,6 @@ import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Function;
import forge.util.FileUtil;
import forge.util.IItemReader;
/**
* This class treats every line of a given file as a source for a named object.
@@ -36,10 +35,10 @@ import forge.util.IItemReader;
* @param <T>
* the generic type
*/
public abstract class StorageReaderFile<T> implements IItemReader<T> {
public abstract class StorageReaderFile<T> extends StorageReaderBase<T> {
private final File file;
private final Function<? super T, String> keySelector;
/**
* Instantiates a new storage reader file.
@@ -58,8 +57,8 @@ public abstract class StorageReaderFile<T> implements IItemReader<T> {
* @param keySelector0 the key selector0
*/
public StorageReaderFile(final File file0, final Function<? super T, String> keySelector0) {
super(keySelector0);
this.file = file0;
this.keySelector = keySelector0;
}
/* (non-Javadoc)
@@ -121,5 +120,4 @@ public abstract class StorageReaderFile<T> implements IItemReader<T> {
public String getItemKey(final T item) {
return this.keySelector.apply(item);
}
}

View File

@@ -30,7 +30,6 @@ import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Function;
import forge.util.FileUtil;
import forge.util.IItemReader;
/**
* This class treats every line of a given file as a source for a named object.
@@ -38,18 +37,18 @@ import forge.util.IItemReader;
* @param <T>
* the generic type
*/
public abstract class StorageReaderFileSections<T> implements IItemReader<T> {
public abstract class StorageReaderFileSections<T> extends StorageReaderBase<T> {
private final File file;
private final Function<? super T, String> keySelector;
public StorageReaderFileSections(final String pathname, final Function<? super T, String> keySelector0) {
this(new File(pathname), keySelector0);
}
public StorageReaderFileSections(final File file0, final Function<? super T, String> keySelector0) {
super(keySelector0);
this.file = file0;
this.keySelector = keySelector0;
}
/* (non-Javadoc)

View File

@@ -18,9 +18,11 @@
package forge.util.storage;
import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
@@ -34,7 +36,6 @@ import com.google.common.base.Function;
import forge.deck.io.OldDeckFileFormatException;
import forge.error.BugReporter;
import forge.util.IItemReader;
/**
* This class treats every file in the given folder as a source for a named
@@ -43,19 +44,9 @@ import forge.util.IItemReader;
*
* @param <T> the generic type
*/
public abstract class StorageReaderFolder<T> implements IItemReader<T> {
public abstract class StorageReaderFolder<T> extends StorageReaderBase<T> {
private final File directory;
private final Function<? super T, String> keySelector;
/**
* Gets the directory.
*
* @return the directory
*/
protected final File getDirectory() {
return this.directory;
}
protected final File directory;
/**
* Instantiates a new storage reader folder.
@@ -63,9 +54,9 @@ public abstract class StorageReaderFolder<T> implements IItemReader<T> {
* @param deckDir0 the deck dir0
*/
public StorageReaderFolder(final File deckDir0, Function<? super T, String> keySelector0) {
super(keySelector0);
this.directory = deckDir0;
keySelector = keySelector0;
if (this.directory == null) {
throw new IllegalArgumentException("No deck directory specified");
@@ -154,4 +145,17 @@ public abstract class StorageReaderFolder<T> implements IItemReader<T> {
return keySelector.apply(item);
}
// methods handling nested folders are provided. It's up to consumer whether to use these or not.
@Override
public Iterable<File> getSubFolders() {
File[] list = this.directory.listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return file.isDirectory() && !file.isHidden();
}
});
return Arrays.asList(list);
}
}