diff --git a/forge-core/src/main/java/forge/util/storage/StorageReaderRecursiveFolderWithUserFolder.java b/forge-core/src/main/java/forge/util/storage/StorageReaderRecursiveFolderWithUserFolder.java
new file mode 100644
index 00000000000..fba09b57f74
--- /dev/null
+++ b/forge-core/src/main/java/forge/util/storage/StorageReaderRecursiveFolderWithUserFolder.java
@@ -0,0 +1,160 @@
+/*
+ * Forge: Play Magic: the Gathering.
+ * Copyright (C) 2011 Nate
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package forge.util.storage;
+
+import com.google.common.base.Function;
+import forge.util.TextUtil;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * This class treats every file in the given folder as a source for a named
+ * object. The descendant should implement read method to deserialize a single
+ * item. So that readAll will return a map of Name => Object as read from disk
+ *
+ * @param the generic type
+ */
+public abstract class StorageReaderRecursiveFolderWithUserFolder extends StorageReaderBase {
+ /**
+ * @return the directory
+ */
+ public File getDirectory() {
+ return directory;
+ }
+
+ @Override
+ public String getFullPath() {
+ return directory.getPath();
+ }
+
+ protected final File directory;
+ protected final File userDirectory;
+
+ /**
+ * Instantiates a new storage reader folder.
+ *
+ * @param itemDir0 the item dir0
+ */
+ public StorageReaderRecursiveFolderWithUserFolder(final File itemDir0, final File userItemDir0, Function super T, String> keySelector0) {
+ super(keySelector0);
+
+ this.directory = itemDir0;
+ this.userDirectory = userItemDir0;
+
+ if (this.directory == null) {
+ throw new IllegalArgumentException("No directory specified");
+ }
+ try {
+ if (this.directory.isFile()) {
+ throw new IOException("Not a directory");
+ } else {
+ this.directory.mkdirs();
+ if (!this.directory.isDirectory()) {
+ throw new IOException("Directory can't be created");
+ }
+ }
+ } catch (final IOException ex) {
+ throw new RuntimeException("StorageReaderFolder.ctor() error, " + ex.getMessage());
+ }
+ }
+
+ public final List objectsThatFailedToLoad = new ArrayList();
+
+ /* (non-Javadoc)
+ * @see forge.util.IItemReader#readAll()
+ */
+ @Override
+ public Map readAll() {
+ final Map result = new TreeMap();
+
+ Collection forgeFormats = listFileTree(directory);
+ Collection customFormats = listFileTree(userDirectory);
+
+ forgeFormats.addAll(customFormats);
+
+ final File[] files = forgeFormats.toArray(new File[forgeFormats.size()]);
+
+ for (final File file : files) {
+ try {
+ final T newDeck = this.read(file);
+ if (null == newDeck) {
+ final String msg = "An object stored in " + file.getPath() + " failed to load.\nPlease submit this as a bug with the mentioned file/directory attached.";
+ continue;//skip format completely - perhaps non format file
+ }
+
+ String newKey = keySelector.apply(newDeck);
+ if (result.containsKey(newKey)) {
+ System.err.println("StorageReaderFolder: Overwriting an object with key " + newKey);
+ }
+ result.put(newKey, newDeck);
+ } catch (final NoSuchElementException ex) {
+ final String message = TextUtil.concatWithSpace( file.getName(),"failed to load because ----", ex.getMessage());
+ objectsThatFailedToLoad.add(message);
+ }
+ }
+ return result;
+ }
+
+ private Collection listFileTree(File dir) {
+ Set fileTree = new HashSet();
+ if(dir==null||dir.listFiles(getFileFilter())==null){
+ return fileTree;
+ }
+ for (File entry : dir.listFiles(getFileFilter())) {
+ if (entry.isFile()) fileTree.add(entry);
+ else fileTree.addAll(listFileTree(entry));
+ }
+ return fileTree;
+ }
+
+ /**
+ * Read the object from file.
+ *
+ * @param file the file
+ * @return the object deserialized by inherited class
+ */
+ protected abstract T read(File file);
+
+ /**
+ * TODO: Write javadoc for this method.
+ *
+ * @return FilenameFilter to pick only relevant objects for deserialization
+ */
+ protected abstract FilenameFilter getFileFilter();
+
+ @Override
+ public String getItemKey(T item) {
+ return keySelector.apply(item);
+ }
+
+ // methods handling nested folders are provided. It's up to consumer whether to use these or not.
+ @Override
+ public Iterable getSubFolders() {
+ File[] list = this.directory.listFiles(new FileFilter() {
+ @Override
+ public boolean accept(File file) {
+ return file.isDirectory() && !file.isHidden();
+ }
+ });
+ return Arrays.asList(list);
+ }
+}
diff --git a/forge-game/src/main/java/forge/game/GameFormat.java b/forge-game/src/main/java/forge/game/GameFormat.java
index c624abb49c5..48be6ad57fb 100644
--- a/forge-game/src/main/java/forge/game/GameFormat.java
+++ b/forge-game/src/main/java/forge/game/GameFormat.java
@@ -34,28 +34,39 @@ import forge.item.PaperCard;
import forge.util.FileSection;
import forge.util.FileUtil;
import forge.util.storage.StorageBase;
-import forge.util.storage.StorageReaderFolder;
+import forge.util.storage.StorageReaderRecursiveFolderWithUserFolder;
import java.io.File;
import java.io.FilenameFilter;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;
public class GameFormat implements Comparable {
private final String name;
- public enum FormatType {Sanctioned, Casual, Historic, Custom}
+ public enum FormatType {Sanctioned, Casual, Historic, Digital, Custom}
+ public enum FormatSubType {Block, Standard, Extended, Modern, Legacy, Vintage, Commander, Planechase, Videogame, MTGO, Custom}
+
// contains allowed sets, when empty allows all sets
private FormatType formatType;
+ private FormatSubType formatSubType;
protected final List allowedSetCodes; // this is mutable to support quest mode set unlocks
protected final List allowedRarities;
protected final List bannedCardNames;
protected final List restrictedCardNames;
-
+ protected final List additionalCardNames; // for cards that are legal but not reprinted in any of the allowed Sets
+ protected boolean restrictedLegendary = false;
+ private Date effectiveDate;
+ private final static SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
+ private final static String DEFAULTDATE = "1990-01-01";
+
protected final transient List allowedSetCodes_ro;
protected final transient List bannedCardNames_ro;
protected final transient List restrictedCardNames_ro;
+ protected final transient List additionalCardNames_ro;
protected final transient Predicate filterRules;
protected final transient Predicate filterPrinted;
@@ -63,24 +74,46 @@ public class GameFormat implements Comparable {
private final int index;
public GameFormat(final String fName, final Iterable sets, final List bannedCards) {
- this(fName, sets, bannedCards, null, null, 0, FormatType.Custom);
+ this(fName, parseDate(DEFAULTDATE), sets, bannedCards, null, false, null, null, 0, FormatType.Custom, FormatSubType.Custom);
}
- public static final GameFormat NoFormat = new GameFormat("(none)", null, null, null, null, Integer.MAX_VALUE, FormatType.Custom);
+ public static final GameFormat NoFormat = new GameFormat("(none)", parseDate(DEFAULTDATE) , null, null, null, false
+ , null, null, Integer.MAX_VALUE, FormatType.Custom, FormatSubType.Custom);
- public GameFormat(final String fName, final Iterable sets, final List bannedCards,
- final List restrictedCards, final List rarities, int compareIdx, FormatType formatType) {
+ public GameFormat(final String fName, final Date effectiveDate, final Iterable sets, final List bannedCards,
+ final List restrictedCards, Boolean restrictedLegendary, final List additionalCards,
+ final List rarities, int compareIdx, FormatType formatType, FormatSubType formatSubType) {
this.index = compareIdx;
this.formatType = formatType;
+ this.formatSubType = formatSubType;
this.name = fName;
- allowedSetCodes = sets == null ? new ArrayList() : Lists.newArrayList(sets);
+ this.effectiveDate = effectiveDate;
+
+ if(sets != null) {
+ Set parsedSets = new HashSet<>();
+ for (String set : sets) {
+ if (StaticData.instance().getEditions().get(set) == null) {
+ System.out.println("Set " + set + " in format " + fName + " does not match any valid editions!");
+ continue;
+ }
+ parsedSets.add(set);
+
+ }
+ allowedSetCodes = Lists.newArrayList(parsedSets);
+ }else{
+ allowedSetCodes = new ArrayList();
+ }
+
bannedCardNames = bannedCards == null ? new ArrayList() : Lists.newArrayList(bannedCards);
restrictedCardNames = restrictedCards == null ? new ArrayList() : Lists.newArrayList(restrictedCards);
allowedRarities = rarities == null ? new ArrayList() : rarities;
+ this.restrictedLegendary = restrictedLegendary;
+ additionalCardNames = additionalCards == null ? new ArrayList() : Lists.newArrayList(additionalCards);
this.allowedSetCodes_ro = Collections.unmodifiableList(allowedSetCodes);
this.bannedCardNames_ro = Collections.unmodifiableList(bannedCardNames);
this.restrictedCardNames_ro = Collections.unmodifiableList(restrictedCardNames);
+ this.additionalCardNames_ro = Collections.unmodifiableList(additionalCardNames);
this.filterRules = this.buildFilterRules();
this.filterPrinted = this.buildFilterPrinted();
@@ -99,6 +132,9 @@ public class GameFormat implements Comparable {
}
p = Predicates.and(p, Predicates.or(crp));
}
+ if (!this.additionalCardNames_ro.isEmpty()) {
+ p = Predicates.or(p, IPaperCard.Predicates.names(this.additionalCardNames_ro));
+ }
return p;
}
@@ -114,10 +150,26 @@ public class GameFormat implements Comparable {
return this.name;
}
+ private static Date parseDate(String date) {
+ if( date.length() <= 7 )
+ date = date + "-01";
+ try {
+ return formatter.parse(date);
+ } catch (ParseException e) {
+ return new Date();
+ }
+ }
+
+ public Date getEffectiveDate() { return effectiveDate; }
+
public FormatType getFormatType() {
return this.formatType;
}
+ public FormatSubType getFormatSubType() {
+ return this.formatSubType;
+ }
+
public List getAllowedSetCodes() {
return this.allowedSetCodes_ro;
}
@@ -129,6 +181,15 @@ public class GameFormat implements Comparable {
public List getRestrictedCards() {
return restrictedCardNames_ro;
}
+
+ public Boolean isRestrictedLegendary() {
+ return restrictedLegendary;
+ }
+
+ public List getAdditionalCards() {
+ return additionalCardNames_ro;
+ }
+
public List getAllowedRarities() {
return allowedRarities;
}
@@ -171,9 +232,11 @@ public class GameFormat implements Comparable {
}
}
- if(!restrictedCardNames_ro.isEmpty() ) {
+ if(!restrictedCardNames_ro.isEmpty() || restrictedLegendary ) {
for (Entry poolEntry : allCards) {
- if( poolEntry.getValue().intValue() > 1 && restrictedCardNames_ro.contains(poolEntry.getKey().getName()))
+ if( poolEntry.getValue().intValue() > 1 && (restrictedCardNames_ro.contains(poolEntry.getKey().getName())
+ || (poolEntry.getKey().getRules().getType().isLegendary()
+ && !poolEntry.getKey().getRules().getType().isPlaneswalker() && restrictedLegendary)))
return false;
}
}
@@ -201,36 +264,80 @@ public class GameFormat implements Comparable {
if (null == other) {
return 1;
}
- return index - other.index;
+ if (other.formatType != formatType){
+ return formatType.compareTo(other.formatType);
+ }else{
+ if (other.formatSubType != formatSubType){
+ return formatSubType.compareTo(other.formatSubType);
+ }
+ }
+ if (formatType.equals(FormatType.Historic)){
+ if(effectiveDate!=other.effectiveDate) {//for matching dates or default dates default to name sorting
+ return other.effectiveDate.compareTo(effectiveDate);
+ }
+ }
+ return name.compareTo(other.name);
+ //return index - other.index;
}
public int getIndex() {
return index;
}
- public static class Reader extends StorageReaderFolder {
+ public static class Reader extends StorageReaderRecursiveFolderWithUserFolder {
List naturallyOrdered = new ArrayList();
+ boolean includeHistoric;
+ private List coreFormats = new ArrayList<>();
+ {
+ coreFormats.add("Standard.txt");
+ coreFormats.add("Modern.txt");
+ coreFormats.add("Legacy.txt");
+ coreFormats.add("Vintage.txt");
+ coreFormats.add("Commander.txt");
+
+ }
- public Reader(File file0) {
- super(file0, GameFormat.FN_GET_NAME);
+ public Reader(File forgeFormats, File customFormats, boolean includeHistoric) {
+ super(forgeFormats, customFormats, GameFormat.FN_GET_NAME);
+ this.includeHistoric=includeHistoric;
}
@Override
protected GameFormat read(File file) {
+ if(!includeHistoric && !coreFormats.contains(file.getName())){
+ return null;
+ }
final Map> contents = FileSection.parseSections(FileUtil.readFile(file));
List sets = null; // default: all sets allowed
List bannedCards = null; // default: nothing banned
List restrictedCards = null; // default: nothing restricted
+ Boolean restrictedLegendary = false;
+ List additionalCards = null; // default: nothing additional
List rarities = null;
- FileSection section = FileSection.parse(contents.get("format"), ":");
+ List formatStrings = contents.get("format");
+ if (formatStrings == null){
+ return null;
+ }
+ FileSection section = FileSection.parse(formatStrings, ":");
String title = section.get("name");
FormatType formatType;
try {
formatType = FormatType.valueOf(section.get("type"));
- } catch (IllegalArgumentException e) {
+ } catch (Exception e) {
formatType = FormatType.Custom;
}
+ FormatSubType formatsubType;
+ try {
+ formatsubType = FormatSubType.valueOf(section.get("subtype"));
+ } catch (Exception e) {
+ formatsubType = FormatSubType.Custom;
+ }
Integer idx = section.getInt("order");
+ String dateStr = section.get("effective");
+ if (dateStr == null){
+ dateStr = DEFAULTDATE;
+ }
+ Date date = parseDate(dateStr);
String strSets = section.get("sets");
if ( null != strSets ) {
sets = Arrays.asList(strSets.split(", "));
@@ -245,6 +352,16 @@ public class GameFormat implements Comparable {
restrictedCards = Arrays.asList(strCars.split("; "));
}
+ Boolean strRestrictedLegendary = section.getBoolean("restrictedlegendary");
+ if ( strRestrictedLegendary != null ) {
+ restrictedLegendary = strRestrictedLegendary;
+ }
+
+ strCars = section.get("additional");
+ if ( strCars != null ) {
+ additionalCards = Arrays.asList(strCars.split("; "));
+ }
+
strCars = section.get("rarities");
if ( strCars != null ) {
CardRarity cr;
@@ -257,7 +374,7 @@ public class GameFormat implements Comparable {
}
}
- GameFormat result = new GameFormat(title, sets, bannedCards, restrictedCards, rarities, idx, formatType);
+ GameFormat result = new GameFormat(title, date, sets, bannedCards, restrictedCards, restrictedLegendary, additionalCards, rarities, idx, formatType,formatsubType);
naturallyOrdered.add(result);
return result;
}
@@ -270,24 +387,31 @@ public class GameFormat implements Comparable {
public static final FilenameFilter TXT_FILE_FILTER = new FilenameFilter() {
@Override
public boolean accept(final File dir, final String name) {
- return name.endsWith(".txt");
+ return name.endsWith(".txt") || dir.isDirectory();
}
};
}
public static class Collection extends StorageBase {
private List naturallyOrdered;
+ private List reverseDateOrdered;
public Collection(GameFormat.Reader reader) {
super("Format collections", reader);
naturallyOrdered = reader.naturallyOrdered;
+ reverseDateOrdered = new ArrayList<>(naturallyOrdered);
Collections.sort(naturallyOrdered);
+ Collections.sort(reverseDateOrdered, new InverseDateComparator());
}
public Iterable getOrderedList() {
return naturallyOrdered;
}
+ public Iterable getReverseDateOrderedList() {
+ return reverseDateOrdered;
+ }
+
public Iterable getSanctionedList() {
List coreList = new ArrayList<>();
for(GameFormat format: naturallyOrdered){
@@ -298,6 +422,41 @@ public class GameFormat implements Comparable {
return coreList;
}
+ public Iterable getFilterList() {
+ List coreList = new ArrayList<>();
+ for(GameFormat format: naturallyOrdered){
+ if(!format.getFormatType().equals(FormatType.Historic)
+ &&!format.getFormatType().equals(FormatType.Digital)){
+ coreList.add(format);
+ }
+ }
+ return coreList;
+ }
+
+ public Iterable getHistoricList() {
+ List coreList = new ArrayList<>();
+ for(GameFormat format: naturallyOrdered){
+ if(format.getFormatType().equals(FormatType.Historic)){
+ coreList.add(format);
+ }
+ }
+ return coreList;
+ }
+
+ public Map> getHistoricMap() {
+ Map> coreList = new HashMap<>();
+ for(GameFormat format: naturallyOrdered){
+ if(format.getFormatType().equals(FormatType.Historic)){
+ String alpha = format.getName().substring(0,1);
+ if(!coreList.containsKey(alpha)){
+ coreList.put(alpha,new ArrayList<>());
+ }
+ coreList.get(alpha).add(format);
+ }
+ }
+ return coreList;
+ }
+
public GameFormat getStandard() {
return this.map.get("Standard");
}
@@ -315,7 +474,7 @@ public class GameFormat implements Comparable {
}
public GameFormat getFormatOfDeck(Deck deck) {
- for(GameFormat gf : naturallyOrdered) {
+ for(GameFormat gf : reverseDateOrdered) {
if ( gf.isDeckLegal(deck) )
return gf;
}
@@ -336,11 +495,26 @@ public class GameFormat implements Comparable {
}
public Set getAllFormatsOfDeck(Deck deck) {
+ return getAllFormatsOfDeck(deck, false);
+ }
+
+ public Set getAllFormatsOfDeck(Deck deck, Boolean exhaustive) {
SortedSet result = new TreeSet();
+ Set coveredTypes = new HashSet<>();
CardPool allCards = deck.getAllCardsInASinglePool();
- for(GameFormat gf : naturallyOrdered) {
+ for(GameFormat gf : reverseDateOrdered) {
+ if (gf.getFormatType().equals(FormatType.Digital) && !exhaustive){
+ //exclude Digital formats from lists for now
+ continue;
+ }
+ if (gf.getFormatType().equals(FormatType.Historic) && coveredTypes.contains(gf.getFormatSubType())
+ && !exhaustive){
+ //exclude duplicate formats - only keep first of e.g. Standard historical
+ continue;
+ }
if (gf.isPoolLegal(allCards)) {
result.add(gf);
+ coveredTypes.add(gf.getFormatSubType());
}
}
if (result.isEmpty()) {
@@ -355,6 +529,27 @@ public class GameFormat implements Comparable {
}
}
+ public static class InverseDateComparator implements Comparator {
+ public int compare(GameFormat gf1, GameFormat gf2){
+ if ((null == gf1) || (null == gf2)) {
+ return 1;
+ }
+ if (gf2.formatType != gf1.formatType){
+ return gf1.formatType.compareTo(gf2.formatType);
+ }else{
+ if (gf2.formatSubType != gf1.formatSubType){
+ return gf1.formatSubType.compareTo(gf2.formatSubType);
+ }
+ }
+ if (gf1.formatType.equals(FormatType.Historic)){
+ if(gf1.effectiveDate!=gf2.effectiveDate) {//for matching dates or default dates default to name sorting
+ return gf1.effectiveDate.compareTo(gf2.effectiveDate);
+ }
+ }
+ return gf1.name.compareTo(gf2.name);
+ }
+ }
+
public final Predicate editionLegalPredicate = new Predicate() {
@Override
public boolean apply(final CardEdition subject) {
diff --git a/forge-gui-desktop/src/main/java/forge/itemmanager/CardManager.java b/forge-gui-desktop/src/main/java/forge/itemmanager/CardManager.java
index 2b3985078d4..8fe9f7f912e 100644
--- a/forge-gui-desktop/src/main/java/forge/itemmanager/CardManager.java
+++ b/forge-gui-desktop/src/main/java/forge/itemmanager/CardManager.java
@@ -7,10 +7,13 @@ import forge.itemmanager.filters.*;
import forge.model.FModel;
import forge.quest.QuestWorld;
import forge.quest.data.QuestPreferences;
+import forge.screens.home.quest.DialogChooseFormats;
import forge.screens.home.quest.DialogChooseSets;
import forge.screens.match.controllers.CDetailPicture;
import javax.swing.*;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
@@ -82,7 +85,7 @@ public class CardManager extends ItemManager {
GuiUtils.addSeparator(menu); //separate from current search item
JMenu fmt = GuiUtils.createMenu("Format");
- for (final GameFormat f : FModel.getFormats().getOrderedList()) {
+ for (final GameFormat f : FModel.getFormats().getFilterList()) {
GuiUtils.addMenuItem(fmt, f.getName(), null, new Runnable() {
@Override
public void run() {
@@ -92,6 +95,27 @@ public class CardManager extends ItemManager {
}
menu.add(fmt);
+ GuiUtils.addMenuItem(menu, "Formats...", null, new Runnable() {
+ @Override public void run() {
+ final CardSetFilter existingFilter = itemManager.getFilter(CardSetFilter.class);
+ if (existingFilter != null) {
+ existingFilter.edit();
+ } else {
+ final DialogChooseFormats dialog = new DialogChooseFormats();
+ dialog.setOkCallback(new Runnable() {
+ @Override public void run() {
+ final List formats = dialog.getSelectedFormats();
+ if (!formats.isEmpty()) {
+ for(GameFormat format: formats) {
+ itemManager.addFilter(new CardFormatFilter(itemManager, format));
+ }
+ }
+ }
+ });
+ }
+ }
+ });
+
GuiUtils.addMenuItem(menu, "Sets...", null, new Runnable() {
@Override
public void run() {
diff --git a/forge-gui-desktop/src/main/java/forge/itemmanager/DeckManager.java b/forge-gui-desktop/src/main/java/forge/itemmanager/DeckManager.java
index 28dfc800cc8..fec8122965f 100644
--- a/forge-gui-desktop/src/main/java/forge/itemmanager/DeckManager.java
+++ b/forge-gui-desktop/src/main/java/forge/itemmanager/DeckManager.java
@@ -4,18 +4,15 @@ import java.awt.Component;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
-import java.util.HashMap;
-import java.util.TreeSet;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import java.util.Map.Entry;
-import java.util.SortedSet;
import javax.swing.JMenu;
import javax.swing.JTable;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
+import forge.screens.home.quest.DialogChooseFormats;
import org.apache.commons.lang3.StringUtils;
import forge.Singletons;
@@ -176,7 +173,7 @@ public final class DeckManager extends ItemManager implements IHasGam
menu.add(folder);
final JMenu fmt = GuiUtils.createMenu("Format");
- for (final GameFormat f : FModel.getFormats().getOrderedList()) {
+ for (final GameFormat f : FModel.getFormats().getFilterList()) {
GuiUtils.addMenuItem(fmt, f.getName(), null, new Runnable() {
@Override
public void run() {
@@ -186,6 +183,29 @@ public final class DeckManager extends ItemManager implements IHasGam
}
menu.add(fmt);
+
+ GuiUtils.addMenuItem(menu, "Formats...", null, new Runnable() {
+ @Override public void run() {
+ final DeckFormatFilter existingFilter = getFilter(DeckFormatFilter.class);
+ if (existingFilter != null) {
+ existingFilter.edit();
+ } else {
+ final DialogChooseFormats dialog = new DialogChooseFormats();
+ dialog.setOkCallback(new Runnable() {
+ @Override public void run() {
+ final List formats = dialog.getSelectedFormats();
+ if (!formats.isEmpty()) {
+ for(GameFormat format: formats) {
+ addFilter(new DeckFormatFilter(DeckManager.this, format));
+ }
+ }
+ }
+ });
+ }
+ }
+ });
+
+
GuiUtils.addMenuItem(menu, "Sets...", null, new Runnable() {
@Override public void run() {
final DeckSetFilter existingFilter = getFilter(DeckSetFilter.class);
diff --git a/forge-gui-desktop/src/main/java/forge/itemmanager/filters/DeckFormatFilter.java b/forge-gui-desktop/src/main/java/forge/itemmanager/filters/DeckFormatFilter.java
index 891ca39bb0f..fb3de87acdb 100644
--- a/forge-gui-desktop/src/main/java/forge/itemmanager/filters/DeckFormatFilter.java
+++ b/forge-gui-desktop/src/main/java/forge/itemmanager/filters/DeckFormatFilter.java
@@ -6,6 +6,7 @@ import forge.game.GameFormat;
import forge.deck.DeckProxy;
import forge.itemmanager.ItemManager;
import forge.itemmanager.SFilterUtil;
+import forge.screens.home.quest.DialogChooseFormats;
public class DeckFormatFilter extends FormatFilter {
@@ -27,4 +28,16 @@ public class DeckFormatFilter extends FormatFilter {
protected final Predicate buildPredicate() {
return DeckProxy.createPredicate(SFilterUtil.buildFormatFilter(this.formats, this.allowReprints));
}
+
+ public void edit() {
+ final DialogChooseFormats dialog = new DialogChooseFormats(this.formats);
+ dialog.setOkCallback(new Runnable() {
+ @Override
+ public void run() {
+ allowReprints = dialog.getWantReprints();
+ formats.clear();
+ formats.addAll(dialog.getSelectedFormats());
+ }
+ });
+ }
}
diff --git a/forge-gui-desktop/src/main/java/forge/itemmanager/filters/FormatFilter.java b/forge-gui-desktop/src/main/java/forge/itemmanager/filters/FormatFilter.java
index a5c104eca30..114437e9d3c 100644
--- a/forge-gui-desktop/src/main/java/forge/itemmanager/filters/FormatFilter.java
+++ b/forge-gui-desktop/src/main/java/forge/itemmanager/filters/FormatFilter.java
@@ -27,6 +27,7 @@ public abstract class FormatFilter extends ListLabelFil
protected String getTooltip() {
Set sets = new HashSet();
Set bannedCards = new HashSet();
+ Set additionalCards = new HashSet<>();
for (GameFormat format : this.formats) {
List formatSets = format.getAllowedSetCodes();
@@ -37,6 +38,10 @@ public abstract class FormatFilter extends ListLabelFil
if (formatBannedCards != null) {
bannedCards.addAll(formatBannedCards);
}
+ List formatAdditionalCards = format.getAdditionalCards();
+ if (formatAdditionalCards != null) {
+ additionalCards.addAll(formatAdditionalCards);
+ }
}
//use HTML tooltips so we can insert line breaks
@@ -58,7 +63,9 @@ public abstract class FormatFilter extends ListLabelFil
}
CardEdition edition = editions.get(code);
- tooltip.append(" ").append(edition.getName()).append(" (").append(code).append("),");
+ if(edition!=null) {
+ tooltip.append(" ").append(edition.getName()).append(" (").append(code).append("),");
+ }
lineLen = tooltip.length() - lastLen;
}
@@ -90,6 +97,27 @@ public abstract class FormatFilter extends ListLabelFil
// chop off last semicolon
tooltip.delete(tooltip.length() - 1, tooltip.length());
}
+
+ if (!additionalCards.isEmpty()) {
+ tooltip.append("
Additional:");
+ lastLen += lineLen;
+ lineLen = 0;
+
+ for (String cardName : additionalCards) {
+ // don't let a single line get too long
+ if (50 < lineLen) {
+ tooltip.append("
");
+ lastLen += lineLen;
+ lineLen = 0;
+ }
+
+ tooltip.append(" ").append(cardName).append(";");
+ lineLen = tooltip.length() - lastLen;
+ }
+
+ // chop off last semicolon
+ tooltip.delete(tooltip.length() - 1, tooltip.length());
+ }
tooltip.append("