From b007e3943c1dc60db43442a84cd63e64bc0cc3de Mon Sep 17 00:00:00 2001 From: myk Date: Wed, 30 Jan 2013 22:04:21 +0000 Subject: [PATCH] - fixed resize cursor not appearing when hovering between columns in table headers - added forge-specific spinner widget (FSpinner) - allowed labels to have their toggle state read externally and added configuration to set whether the onClick command is executed on mouse button down or mouse button up (FLabel) - added builder pattern to FTextField and autoset properties to common values - fixed header comments in WrapLayout - renamed DialogCustomFormat to the more generic DialogChooseSets since I use it now from the filters too; extended its functionality to run a specified command on ok button click - removed Filters dockable panel - added old filters functionality to the stats buttons above the catalog table (stats can no longer be removed via a preference setting) - combined scattered metadata about the filters (e.g. icon, label, filter predicate) into a single enum - rewrote filter utility functions to not have any side effects (they now use no global data/singletons) - added "Owned" column to spell shop catalog, indicating number of cards already owned by player (can remove column with preference) - don't count the "click" as a sort command when resizing a column - exposed top-level main world custom format in QuestController -- other format-retrieving methods would be masked by the current world selection - added utility fn to TextUtils to create a (locale-independent) Title out of an ENUM - added a templated Pair utility class for ad-hoc two-value parameter returning - prevented invalid enum values in editor_preferred.xml from causing errors --- .gitattributes | 3 - .settings/org.eclipse.m2e.core.prefs | 4 + res/layouts/editor_default.xml | 3 +- res/preferences/editor.preferences | 6 +- src/main/java/forge/control/FControl.java | 8 +- src/main/java/forge/gui/WrapLayout.java | 4 +- .../forge/gui/deckeditor/CDeckEditorUI.java | 7 +- .../java/forge/gui/deckeditor/SEditorIO.java | 5 +- .../forge/gui/deckeditor/SEditorUtil.java | 125 ++--- .../forge/gui/deckeditor/SFilterUtil.java | 457 ++++-------------- .../deckeditor/controllers/CCardCatalog.java | 443 ++++++++++++++++- .../controllers/CEditorDraftingProcess.java | 19 - .../controllers/CEditorPreferences.java | 14 +- .../controllers/CEditorQuestCardShop.java | 11 +- .../gui/deckeditor/controllers/CFilters.java | 181 ------- .../deckeditor/tables/EditorTableModel.java | 3 +- .../gui/deckeditor/tables/SColumnUtil.java | 1 + .../deckeditor/tables/TableColumnInfo.java | 2 - .../gui/deckeditor/views/ITableContainer.java | 50 +- .../gui/deckeditor/views/VCardCatalog.java | 378 +++++++-------- .../gui/deckeditor/views/VCurrentDeck.java | 181 +------ .../deckeditor/views/VEditorPreferences.java | 21 +- .../forge/gui/deckeditor/views/VFilters.java | 333 ------------- .../gui/deckeditor/views/VStatistics.java | 36 +- src/main/java/forge/gui/framework/EDocID.java | 2 - .../java/forge/gui/framework/SLayoutIO.java | 4 +- .../home/gauntlet/VSubmenuGauntletBuild.java | 13 +- .../gui/home/quest/CSubmenuQuestData.java | 4 +- ...ustomFormat.java => DialogChooseSets.java} | 308 ++++++------ src/main/java/forge/gui/toolbox/FLabel.java | 55 ++- src/main/java/forge/gui/toolbox/FSpinner.java | 49 ++ .../java/forge/gui/toolbox/FTextField.java | 68 ++- .../java/forge/quest/QuestController.java | 7 + .../forge/quest/QuestRewardCardChooser.java | 237 +++++++++ src/main/java/forge/quest/QuestUtilCards.java | 43 +- src/main/java/forge/util/Pair.java | 11 + src/main/java/forge/util/TextUtil.java | 11 +- src/main/java/forge/view/FView.java | 5 +- 38 files changed, 1455 insertions(+), 1657 deletions(-) create mode 100644 .settings/org.eclipse.m2e.core.prefs delete mode 100644 src/main/java/forge/gui/deckeditor/controllers/CFilters.java delete mode 100644 src/main/java/forge/gui/deckeditor/views/VFilters.java rename src/main/java/forge/gui/home/quest/{DialogCustomFormat.java => DialogChooseSets.java} (90%) create mode 100644 src/main/java/forge/gui/toolbox/FSpinner.java create mode 100644 src/main/java/forge/quest/QuestRewardCardChooser.java create mode 100644 src/main/java/forge/util/Pair.java diff --git a/.gitattributes b/.gitattributes index 7683638eba4..4ee79fff8af 100644 --- a/.gitattributes +++ b/.gitattributes @@ -13984,7 +13984,6 @@ src/main/java/forge/gui/deckeditor/controllers/CEditorPreferences.java -text src/main/java/forge/gui/deckeditor/controllers/CEditorQuest.java svneol=native#text/plain src/main/java/forge/gui/deckeditor/controllers/CEditorQuestCardShop.java -text src/main/java/forge/gui/deckeditor/controllers/CEditorVariant.java -text -src/main/java/forge/gui/deckeditor/controllers/CFilters.java -text src/main/java/forge/gui/deckeditor/controllers/CProbabilities.java -text src/main/java/forge/gui/deckeditor/controllers/CStatistics.java -text src/main/java/forge/gui/deckeditor/package-info.java -text @@ -14004,7 +14003,6 @@ src/main/java/forge/gui/deckeditor/views/VCardCatalog.java -text src/main/java/forge/gui/deckeditor/views/VCurrentDeck.java -text src/main/java/forge/gui/deckeditor/views/VDeckgen.java -text src/main/java/forge/gui/deckeditor/views/VEditorPreferences.java -text -src/main/java/forge/gui/deckeditor/views/VFilters.java -text src/main/java/forge/gui/deckeditor/views/VProbabilities.java -text src/main/java/forge/gui/deckeditor/views/VStatistics.java -text src/main/java/forge/gui/download/GuiDownloadPicturesLQ.java svneol=native#text/plain @@ -14055,7 +14053,6 @@ src/main/java/forge/gui/home/quest/CSubmenuDuels.java -text src/main/java/forge/gui/home/quest/CSubmenuQuestData.java -text src/main/java/forge/gui/home/quest/CSubmenuQuestDecks.java -text src/main/java/forge/gui/home/quest/CSubmenuQuestPrefs.java -text -src/main/java/forge/gui/home/quest/DialogCustomFormat.java -text src/main/java/forge/gui/home/quest/IVQuestStats.java -text src/main/java/forge/gui/home/quest/PnlEvent.java -text src/main/java/forge/gui/home/quest/QuestFileLister.java -text diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 00000000000..f897a7f1cb2 --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/res/layouts/editor_default.xml b/res/layouts/editor_default.xml index 52f95a2ff8b..d1e368a72e9 100644 --- a/res/layouts/editor_default.xml +++ b/res/layouts/editor_default.xml @@ -3,7 +3,6 @@ CARD_PICTURE EDITOR_PREFERENCES - EDITOR_FILTERS EDITOR_CURRENTDECK @@ -18,4 +17,4 @@ EDITOR_CATALOG - \ No newline at end of file + diff --git a/res/preferences/editor.preferences b/res/preferences/editor.preferences index 5a0c1fdeb64..5ba9c65bdc4 100644 --- a/res/preferences/editor.preferences +++ b/res/preferences/editor.preferences @@ -2,13 +2,12 @@ - - - + + @@ -17,6 +16,7 @@ + diff --git a/src/main/java/forge/control/FControl.java b/src/main/java/forge/control/FControl.java index 589ed4fe355..577e3557d05 100644 --- a/src/main/java/forge/control/FControl.java +++ b/src/main/java/forge/control/FControl.java @@ -270,11 +270,9 @@ public enum FControl { Component[] children = display.getComponentsInLayer(JLayeredPane.DEFAULT_LAYER); if (children.length != 0) { children[0].setSize(display.getSize()); } - children = display.getComponentsInLayer(FView.TARGETING_LAYER); - if (children.length != 0) { children[0].setSize(display.getSize()); } - - children = display.getComponentsInLayer(JLayeredPane.MODAL_LAYER); - if (children.length != 0) { children[0].setSize(display.getSize()); } + for (Component child : display.getComponentsInLayer(JLayeredPane.MODAL_LAYER)) { + child.setSize(display.getSize()); + } } /** @return {@link forge.game.player.Player} */ diff --git a/src/main/java/forge/gui/WrapLayout.java b/src/main/java/forge/gui/WrapLayout.java index d04531275ed..c48313ffa00 100644 --- a/src/main/java/forge/gui/WrapLayout.java +++ b/src/main/java/forge/gui/WrapLayout.java @@ -39,8 +39,8 @@ public class WrapLayout extends FlowLayout { * and the indicated horizontal and vertical gaps. *

* The value of the alignment argument must be one of - * WrapLayout, WrapLayout, - * or WrapLayout. + * FlowLayout.LEFT, FlowLayout.CENTER, + * or FlowLayout.RIGHT. * @param align the alignment value * @param hgap the horizontal gap between components * @param vgap the vertical gap between components diff --git a/src/main/java/forge/gui/deckeditor/CDeckEditorUI.java b/src/main/java/forge/gui/deckeditor/CDeckEditorUI.java index c3975eb9e2e..65b0fc71f88 100644 --- a/src/main/java/forge/gui/deckeditor/CDeckEditorUI.java +++ b/src/main/java/forge/gui/deckeditor/CDeckEditorUI.java @@ -23,10 +23,11 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import forge.Card; +import forge.deck.DeckBase; import forge.gui.CardContainer; import forge.gui.deckeditor.SEditorIO.EditorPreference; import forge.gui.deckeditor.controllers.ACEditorBase; -import forge.gui.deckeditor.views.VFilters; +import forge.gui.deckeditor.controllers.CCardCatalog; import forge.gui.match.controllers.CDetail; import forge.gui.match.controllers.CPicture; import forge.item.InventoryItem; @@ -74,7 +75,7 @@ public enum CDeckEditorUI implements CardContainer { /** * @return ACEditorBase */ - public ACEditorBase getCurrentEditorController() { + public ACEditorBase getCurrentEditorController() { return childController; } @@ -93,7 +94,7 @@ public enum CDeckEditorUI implements CardContainer { childController.getTableCatalog().setWantUnique(wantUnique); childController.getTableDeck().setWantUnique(wantUnique); } - VFilters.SINGLETON_INSTANCE.getLayoutControl().buildFilter(); + CCardCatalog.SINGLETON_INSTANCE.applyCurrentFilter(); } //========== Other methods diff --git a/src/main/java/forge/gui/deckeditor/SEditorIO.java b/src/main/java/forge/gui/deckeditor/SEditorIO.java index 1ffef3df1ee..f5e0c30ed2c 100644 --- a/src/main/java/forge/gui/deckeditor/SEditorIO.java +++ b/src/main/java/forge/gui/deckeditor/SEditorIO.java @@ -47,9 +47,8 @@ public class SEditorIO { } /** Preferences (must match with PREFS file). */ - public enum EditorPreference { /** */ - stats_deck, /** */ - stats_catalog, + public enum EditorPreference { + stats_deck, display_unique_only, elastic_columns } diff --git a/src/main/java/forge/gui/deckeditor/SEditorUtil.java b/src/main/java/forge/gui/deckeditor/SEditorUtil.java index 8b74923ecdd..2c177211e04 100644 --- a/src/main/java/forge/gui/deckeditor/SEditorUtil.java +++ b/src/main/java/forge/gui/deckeditor/SEditorUtil.java @@ -1,16 +1,14 @@ package forge.gui.deckeditor; import javax.swing.ImageIcon; -import javax.swing.JLabel; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Iterables; + import forge.Command; - - -import forge.card.CardRulesPredicates; import forge.card.CardRules; +import forge.card.CardRulesPredicates; import forge.gui.deckeditor.views.ITableContainer; import forge.gui.deckeditor.views.VCardCatalog; import forge.gui.deckeditor.views.VCurrentDeck; @@ -19,6 +17,7 @@ import forge.gui.toolbox.FSkin; import forge.item.InventoryItem; import forge.item.ItemPoolView; import forge.util.Aggregates; +import forge.util.TextUtil; /** @@ -31,53 +30,39 @@ import forge.util.Aggregates; * */ public final class SEditorUtil { - /** Pre-cached resized version. */ - public static final ImageIcon ICO_ARTIFACT = - new ImageIcon(FSkin.getImage(FSkin.EditorImages.IMG_ARTIFACT, 18, 18)); - /** Pre-cached resized version. */ - public static final ImageIcon ICO_CREATURE = - new ImageIcon(FSkin.getImage(FSkin.EditorImages.IMG_CREATURE, 18, 18)); - /** Pre-cached resized version. */ - public static final ImageIcon ICO_ENCHANTMENT = - new ImageIcon(FSkin.getImage(FSkin.EditorImages.IMG_ENCHANTMENT, 18, 18)); - /** Pre-cached resized version. */ - public static final ImageIcon ICO_INSTANT = - new ImageIcon(FSkin.getImage(FSkin.EditorImages.IMG_INSTANT, 18, 18)); - /** Pre-cached resized version. */ - public static final ImageIcon ICO_LAND = - new ImageIcon(FSkin.getImage(FSkin.EditorImages.IMG_LAND, 18, 18)); - /** Pre-cached resized version. */ - public static final ImageIcon ICO_PLANESWALKER = - new ImageIcon(FSkin.getImage(FSkin.EditorImages.IMG_PLANESWALKER, 18, 18)); - /** Pre-cached resized version. */ - public static final ImageIcon ICO_SORCERY = - new ImageIcon(FSkin.getImage(FSkin.EditorImages.IMG_SORCERY, 18, 18)); + /** An enum to encapsulate metadata for the stats/filter objects. */ + public static enum StatTypes { + TOTAL (FSkin.ZoneImages.ICO_HAND, null), + + WHITE (FSkin.ManaImages.IMG_WHITE, CardRulesPredicates.Presets.IS_WHITE), + BLUE (FSkin.ManaImages.IMG_BLUE, CardRulesPredicates.Presets.IS_BLUE), + BLACK (FSkin.ManaImages.IMG_BLACK, CardRulesPredicates.Presets.IS_BLACK), + RED (FSkin.ManaImages.IMG_RED, CardRulesPredicates.Presets.IS_RED), + GREEN (FSkin.ManaImages.IMG_GREEN, CardRulesPredicates.Presets.IS_GREEN), + COLORLESS (FSkin.ManaImages.IMG_COLORLESS, CardRulesPredicates.Presets.IS_COLORLESS), + MULTICOLOR (FSkin.EditorImages.IMG_MULTI, CardRulesPredicates.Presets.IS_MULTICOLOR), - /** Pre-cached resized version. */ - public static final ImageIcon ICO_TOTAL = - new ImageIcon(FSkin.getImage(FSkin.ZoneImages.ICO_HAND, 18, 18)); - /** Pre-cached resized version. */ - public static final ImageIcon ICO_MULTI = - new ImageIcon(FSkin.getImage(FSkin.EditorImages.IMG_MULTI, 18, 18)); - /** Pre-cached resized version. */ - public static final ImageIcon ICO_BLACK = - new ImageIcon(FSkin.getImage(FSkin.ManaImages.IMG_BLACK, 18, 18)); - /** Pre-cached resized version. */ - public static final ImageIcon ICO_BLUE = - new ImageIcon(FSkin.getImage(FSkin.ManaImages.IMG_BLUE, 18, 18)); - /** Pre-cached resized version. */ - public static final ImageIcon ICO_GREEN = - new ImageIcon(FSkin.getImage(FSkin.ManaImages.IMG_GREEN, 18, 18)); - /** Pre-cached resized version. */ - public static final ImageIcon ICO_RED = - new ImageIcon(FSkin.getImage(FSkin.ManaImages.IMG_RED, 18, 18)); - /** Pre-cached resized version. */ - public static final ImageIcon ICO_WHITE = - new ImageIcon(FSkin.getImage(FSkin.ManaImages.IMG_WHITE, 18, 18)); - /** Pre-cached resized version. */ - public static final ImageIcon ICO_COLORLESS = - new ImageIcon(FSkin.getImage(FSkin.ColorlessManaImages.IMG_X, 18, 18)); + LAND (FSkin.EditorImages.IMG_LAND, CardRulesPredicates.Presets.IS_LAND), + ARTIFACT (FSkin.EditorImages.IMG_ARTIFACT, CardRulesPredicates.Presets.IS_ARTIFACT), + CREATURE (FSkin.EditorImages.IMG_CREATURE, CardRulesPredicates.Presets.IS_CREATURE), + ENCHANTMENT (FSkin.EditorImages.IMG_ENCHANTMENT, CardRulesPredicates.Presets.IS_ENCHANTMENT), + PLANESWALKER (FSkin.EditorImages.IMG_PLANESWALKER, CardRulesPredicates.Presets.IS_PLANESWALKER), + INSTANT (FSkin.EditorImages.IMG_INSTANT, CardRulesPredicates.Presets.IS_INSTANT), + SORCERY (FSkin.EditorImages.IMG_SORCERY, CardRulesPredicates.Presets.IS_SORCERY); + + public final ImageIcon img; + public final Predicate predicate; + StatTypes(FSkin.SkinProp prop, Predicate pred) { + img = new ImageIcon(FSkin.getImage(prop, 18, 18)); + predicate = pred; + } + + public String toLabelString() { + return TextUtil.enumToLabel(this) + " cards"; + } + } + /** * Divides X by Y, multiplies by 100, rounds, returns. * @@ -86,12 +71,7 @@ public final class SEditorUtil { * @return rounded result (int) */ public static int calculatePercentage(final int x0, final int y0) { - return (int) Math.round((double) x0 / (double) y0 * 100); - } - - public static void setLabelTextSum(JLabel label, final ItemPoolView deck, Predicate predicate) { - int sum = Aggregates.sum(Iterables.filter(deck, Predicates.compose(predicate, deck.getFnToCard())), deck.getFnToCount()); - label.setText(String.valueOf(sum)); + return (int) Math.round((double) (x0 * 100) / (double) y0); } /** @@ -102,27 +82,25 @@ public final class SEditorUtil { * @param view   {@link forge.gui.deckeditor.views.ITableContainer} */ public static void setStats(final ItemPoolView deck, final ITableContainer view) { - view.getLblTotal().setText(String.valueOf(deck.countAll())); - - setLabelTextSum(view.getLblCreature(), deck, CardRulesPredicates.Presets.IS_CREATURE); - setLabelTextSum(view.getLblLand(), deck, CardRulesPredicates.Presets.IS_LAND); - setLabelTextSum(view.getLblEnchantment(), deck, CardRulesPredicates.Presets.IS_ENCHANTMENT); - setLabelTextSum(view.getLblArtifact(), deck, CardRulesPredicates.Presets.IS_ARTIFACT); - setLabelTextSum(view.getLblInstant(), deck, CardRulesPredicates.Presets.IS_INSTANT); - setLabelTextSum(view.getLblSorcery(), deck, CardRulesPredicates.Presets.IS_SORCERY); - setLabelTextSum(view.getLblPlaneswalker(), deck, CardRulesPredicates.Presets.IS_PLANESWALKER); - setLabelTextSum(view.getLblColorless(), deck, CardRulesPredicates.Presets.IS_COLORLESS); - setLabelTextSum(view.getLblBlack(), deck, CardRulesPredicates.Presets.IS_BLACK); - setLabelTextSum(view.getLblBlue(), deck, CardRulesPredicates.Presets.IS_BLUE); - setLabelTextSum(view.getLblGreen(), deck, CardRulesPredicates.Presets.IS_GREEN); - setLabelTextSum(view.getLblRed(), deck, CardRulesPredicates.Presets.IS_RED); - setLabelTextSum(view.getLblWhite(), deck, CardRulesPredicates.Presets.IS_WHITE); + for (StatTypes s : StatTypes.values()) { + switch (s) { + case TOTAL: + view.getStatLabel(StatTypes.TOTAL).setText(String.valueOf(deck.countAll())); + break; + case COLORLESS: + break; // TODO: why? + default: + view.getStatLabel(s).setText(String.valueOf( + Aggregates.sum(Iterables.filter(deck, Predicates.compose(s.predicate, deck.getFnToCard())), deck.getFnToCount()))); + } + } } // getStats() /** * Resets components that may have been changed * by various configurations of the deck editor. */ + @SuppressWarnings("serial") public static void resetUI() { VCardCatalog.SINGLETON_INSTANCE.getBtnAdd4().setVisible(true); VCurrentDeck.SINGLETON_INSTANCE.getBtnRemove4().setVisible(true); @@ -142,16 +120,13 @@ public final class SEditorUtil { VCurrentDeck.SINGLETON_INSTANCE.getTabLabel().setText("Current Deck"); VCurrentDeck.SINGLETON_INSTANCE.getBtnPrintProxies().setVisible(true); - VCurrentDeck.SINGLETON_INSTANCE.getBtnDoSideboard().setVisible(false); VCurrentDeck.SINGLETON_INSTANCE.getTxfTitle().setVisible(true); VCurrentDeck.SINGLETON_INSTANCE.getLblTitle().setText("Title:"); ((FLabel) VCurrentDeck.SINGLETON_INSTANCE.getBtnSave()) - .setCommand(new Command() { private static final long serialVersionUID = -7995834050136126035L; - - @Override - public void execute() { SEditorIO.saveDeck(); } }); + .setCommand(new Command() { + @Override public void execute() { SEditorIO.saveDeck(); } }); } } diff --git a/src/main/java/forge/gui/deckeditor/SFilterUtil.java b/src/main/java/forge/gui/deckeditor/SFilterUtil.java index 1e1147a1d7e..e1e9306dade 100644 --- a/src/main/java/forge/gui/deckeditor/SFilterUtil.java +++ b/src/main/java/forge/gui/deckeditor/SFilterUtil.java @@ -1,336 +1,120 @@ package forge.gui.deckeditor; -import java.awt.Graphics; -import java.awt.Image; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.swing.JCheckBox; -import javax.swing.JComboBox; -import javax.swing.JPanel; -import javax.swing.SwingConstants; -import javax.swing.border.EmptyBorder; - import com.google.common.base.Predicate; import com.google.common.base.Predicates; -import forge.card.CardEdition; -import forge.card.CardRulesPredicates; import forge.card.CardRules; -import forge.game.GameFormat; -import forge.gui.WrapLayout; -import forge.gui.deckeditor.views.VFilters; +import forge.card.CardRulesPredicates; +import forge.gui.deckeditor.views.VCardCatalog; +import forge.gui.deckeditor.views.VCardCatalog.RangeTypes; +import forge.gui.toolbox.FLabel; +import forge.gui.toolbox.FSpinner; import forge.item.CardPrinted; import forge.util.ComparableOp; +import forge.util.Pair; import forge.util.PredicateString.StringOp; /** * Static factory; holds blocks of form elements and predicates * which are used in various editing environments. *

- * (S at beginning of class name denotes a static factory.) - */ -public class SFilterUtil { - /** An enum to encapsulate metadata for the checkbox objects in the color/type filter maps. */ - private enum FilterProperty { - WHITE (SEditorUtil.ICO_WHITE.getImage(), "White Cards"), - BLUE (SEditorUtil.ICO_BLUE.getImage(), "Blue Cards"), - BLACK (SEditorUtil.ICO_BLACK.getImage(), "Black Cards"), - RED (SEditorUtil.ICO_RED.getImage(), "Red Cards"), - GREEN (SEditorUtil.ICO_GREEN.getImage(), "Green Cards"), - COLORLESS (SEditorUtil.ICO_COLORLESS.getImage(), "Colorless Cards"), - MULTICOLOR (SEditorUtil.ICO_MULTI.getImage(), "Multicolor Cards"), - - LAND (SEditorUtil.ICO_LAND.getImage(), "Land Cards"), - ARTIFACT (SEditorUtil.ICO_ARTIFACT.getImage(), "Artifact Cards"), - CREATURE (SEditorUtil.ICO_CREATURE.getImage(), "Creature Cards"), - ENCHANTMENT (SEditorUtil.ICO_ENCHANTMENT.getImage(), "Enchantment Cards"), - PLANESWALKER (SEditorUtil.ICO_PLANESWALKER.getImage(), "Planeswalker Cards"), - INSTANT (SEditorUtil.ICO_INSTANT.getImage(), "Instant Cards"), - SORCERY (SEditorUtil.ICO_SORCERY.getImage(), "Sorcery Cards"); - - private final Image img; - private final String tooltip; - - FilterProperty(final Image img0, final String tooltip0) { - img = img0; - tooltip = tooltip0; - } - - public Image getImage() { - return img; - } - - public String getTooltip() { - return tooltip; - } - } - - private static final FilterProperty[] COLOR_FILTER_PROPERTIES = { - FilterProperty.WHITE, - FilterProperty.BLUE, - FilterProperty.BLACK, - FilterProperty.RED, - FilterProperty.GREEN, - FilterProperty.COLORLESS, - FilterProperty.MULTICOLOR - }; - - private static final FilterProperty[] TYPE_FILTER_PROPERTIES = { - FilterProperty.LAND, - FilterProperty.ARTIFACT, - FilterProperty.CREATURE, - FilterProperty.ENCHANTMENT, - FilterProperty.PLANESWALKER, - FilterProperty.INSTANT, - FilterProperty.SORCERY - }; - - private static final Map MAP_COLOR_CHECKBOXES = - new HashMap(); - - private static final Map MAP_TYPE_CHECKBOXES = - new HashMap(); - - /** - - */ - private static boolean preventFiltering = false; - + * (S at beginning of class name denotes a static factory.) + */ +public class SFilterUtil { /** - * This will prevent a filter event on a checkbox state change. - * It's used for programmatic changes to the checkboxes when rebuilding - * the filter each time is expensive. - * - * @return boolean   true if filtering is prevented - */ - public static boolean isFilteringPrevented() { - return preventFiltering; - } - - /** - * This will prevent a filter event on a checkbox state change. - * It's used for programmatic changes to the checkboxes when rebuilding - * the filter each time is expensive. - * - * @param bool0   true to prevent filtering - */ - public static void setPreventFiltering(final boolean bool0) { - preventFiltering = bool0; - } - - /** - * Fills and returns a JPanel with checkboxes for color filter set. - * - * @return {@link javax.swing.JPanel} - */ - public static JPanel populateColorFilters() { - final JPanel pnl = new JPanel(new WrapLayout(SwingConstants.CENTER, 10, 5)); - pnl.setOpaque(false); - - MAP_COLOR_CHECKBOXES.clear(); - for (FilterProperty p : COLOR_FILTER_PROPERTIES) { - ChbPnl chbPnl = new ChbPnl(p.getImage(), p.getTooltip()); - MAP_COLOR_CHECKBOXES.put(p, chbPnl); - pnl.add(chbPnl); - } - - return pnl; - } - - /** - * Fills and returns a JPanel with checkboxes for type filter set. - * - * @return {@link javax.swing.JPanel} - */ - public static JPanel populateTypeFilters() { - final JPanel pnl = new JPanel(new WrapLayout(SwingConstants.CENTER, 10, 5)); - pnl.setOpaque(false); - - MAP_TYPE_CHECKBOXES.clear(); - for (FilterProperty p : TYPE_FILTER_PROPERTIES) { - ChbPnl chbPnl = new ChbPnl(p.getImage(), p.getTooltip()); - MAP_TYPE_CHECKBOXES.put(p, chbPnl); - pnl.add(chbPnl); - } - - return pnl; - } - - /** Turns all type checkboxes off or on. - * @param select0   boolean */ - public static void toggleTypeCheckboxes(final boolean select0) { - for (ChbPnl p : MAP_TYPE_CHECKBOXES.values()) { - p.getCheckBox().setSelected(select0); - } - } - - /** Turns all color checkboxes off or on. - * @param select0   boolean */ - public static void toggleColorCheckboxes(final boolean select0) { - for (ChbPnl p : MAP_COLOR_CHECKBOXES.values()) { - p.getCheckBox().setSelected(select0); - } - } - - /** - * Assembles checkboxes for color and returns a filter predicate. + * queries color filters for state and returns a predicate. *

* Handles "multicolor" label, which is quite tricky. - * - * @return Predicate */ - public static Predicate buildColorFilter() { - if (MAP_COLOR_CHECKBOXES.isEmpty()) { return Predicates.alwaysTrue(); } - - final List> colors = new ArrayList>(); - - if (MAP_COLOR_CHECKBOXES.get(FilterProperty.WHITE).getCheckBox().isSelected()) { colors.add(CardRulesPredicates.Presets.IS_WHITE); } - if (MAP_COLOR_CHECKBOXES.get(FilterProperty.BLUE).getCheckBox().isSelected()) { colors.add(CardRulesPredicates.Presets.IS_BLUE); } - if (MAP_COLOR_CHECKBOXES.get(FilterProperty.BLACK).getCheckBox().isSelected()) { colors.add(CardRulesPredicates.Presets.IS_BLACK); } - if (MAP_COLOR_CHECKBOXES.get(FilterProperty.RED).getCheckBox().isSelected()) { colors.add(CardRulesPredicates.Presets.IS_RED); } - if (MAP_COLOR_CHECKBOXES.get(FilterProperty.GREEN).getCheckBox().isSelected()) { colors.add(CardRulesPredicates.Presets.IS_GREEN); } - if (MAP_COLOR_CHECKBOXES.get(FilterProperty.COLORLESS).getCheckBox().isSelected()) { colors.add(CardRulesPredicates.Presets.IS_COLORLESS); } - - final Predicate preColors = colors.size() == 6 ? null : Predicates.or(colors); - - boolean wantMulticolor = MAP_COLOR_CHECKBOXES.get(FilterProperty.MULTICOLOR).getCheckBox().isSelected(); - final Predicate preExceptMulti = wantMulticolor ? null : Predicates.not(CardRulesPredicates.Presets.IS_MULTICOLOR); - - Predicate preFinal = colors.isEmpty() && wantMulticolor ? CardRulesPredicates.Presets.IS_MULTICOLOR : optimizedAnd(preExceptMulti, preColors); + public static Predicate buildColorAndTypeFilter(Map statLabels) { + final List> colors = new ArrayList>(); + final List> types = new ArrayList>(); + + boolean wantMulticolor = false; + Predicate preExceptMulti = null; + for (SEditorUtil.StatTypes s : SEditorUtil.StatTypes.values()) { + switch (s) { + case WHITE: case BLUE: case BLACK: case RED: case GREEN: case COLORLESS: + if (statLabels.get(s).isSelected()) { colors.add(s.predicate); } + break; + case MULTICOLOR: + wantMulticolor = statLabels.get(s).isSelected(); + preExceptMulti = wantMulticolor ? null : Predicates.not(CardRulesPredicates.Presets.IS_MULTICOLOR); + break; + case LAND: case ARTIFACT: case CREATURE: case ENCHANTMENT: case PLANESWALKER: case INSTANT: case SORCERY: + if (statLabels.get(s).isSelected()) { types.add(s.predicate); } + break; + + case TOTAL: + // ignore + break; + + default: + throw new RuntimeException("unhandled enum value: " + s); + } + } + Predicate preColors = colors.size() == 6 ? null : Predicates.or(colors); + Predicate preFinal = colors.isEmpty() && wantMulticolor ? + CardRulesPredicates.Presets.IS_MULTICOLOR : optimizedAnd(preExceptMulti, preColors); + + if (null == preFinal && 7 == types.size()) { + return Predicates.alwaysTrue(); + } + + Predicate typesFinal = Predicates.compose(Predicates.or(types), CardPrinted.FN_GET_RULES); if (null == preFinal) { + return typesFinal; + } + + Predicate colorFinal = Predicates.compose(preFinal, CardPrinted.FN_GET_RULES); + if (7 == types.size()) { + return colorFinal; + } + + return Predicates.and(colorFinal, typesFinal); + } + + /** + * builds a string search filter + */ + public static Predicate buildTextFilter(String text, boolean invert, boolean inName, boolean inType, boolean inText) { + if (text.trim().isEmpty()) { return Predicates.alwaysTrue(); } - - return Predicates.compose(preFinal, CardPrinted.FN_GET_RULES); - } - - /** - * Filters the set/format combo box. - * - * @return Predicate - */ - public static Predicate buildSetAndFormatFilter() { - // Set/Format filter - JComboBox cbox = VFilters.SINGLETON_INSTANCE.getCbxSets(); - if (cbox.getSelectedIndex() == 0) { - return Predicates.alwaysTrue(); - } - - final Object selected = cbox.getSelectedItem(); - final Predicate filter; - if (selected instanceof CardEdition) { - filter = CardPrinted.Predicates.printedInSets(((CardEdition) selected).getCode()); - } else { - filter = ((GameFormat) selected).getFilterRules(); - } - - return filter; - } - - /** - * Assembles checkboxes for type and returns a filter predicate. - * - * @return Predicate - */ - public static Predicate buildTypeFilter() { - if (MAP_TYPE_CHECKBOXES.isEmpty()) { return Predicates.alwaysTrue(); } - - final List> ors = new ArrayList>(); - if (MAP_TYPE_CHECKBOXES.get(FilterProperty.LAND).getCheckBox().isSelected()) { ors.add(CardRulesPredicates.Presets.IS_LAND); } - if (MAP_TYPE_CHECKBOXES.get(FilterProperty.ARTIFACT).getCheckBox().isSelected()) { ors.add(CardRulesPredicates.Presets.IS_ARTIFACT); } - if (MAP_TYPE_CHECKBOXES.get(FilterProperty.CREATURE).getCheckBox().isSelected()) { ors.add(CardRulesPredicates.Presets.IS_CREATURE); } - if (MAP_TYPE_CHECKBOXES.get(FilterProperty.ENCHANTMENT).getCheckBox().isSelected()) { ors.add(CardRulesPredicates.Presets.IS_ENCHANTMENT); } - if (MAP_TYPE_CHECKBOXES.get(FilterProperty.PLANESWALKER).getCheckBox().isSelected()) { ors.add(CardRulesPredicates.Presets.IS_PLANESWALKER); } - if (MAP_TYPE_CHECKBOXES.get(FilterProperty.INSTANT).getCheckBox().isSelected()) { ors.add(CardRulesPredicates.Presets.IS_INSTANT); } - if (MAP_TYPE_CHECKBOXES.get(FilterProperty.SORCERY).getCheckBox().isSelected()) { ors.add(CardRulesPredicates.Presets.IS_SORCERY); } - - if (ors.size() == 7) { - return Predicates.alwaysTrue(); - } - - return Predicates.compose(Predicates.or(ors), CardPrinted.FN_GET_RULES); - } - - /** - * Validates text field input (from txfContains and txfWithout), - * then assembles AND and NOT predicates accordingly, ANDs - * together, and returns. - * - * @return Predicate - */ - public static Predicate buildTextFilter() { - Predicate filterAnd = null; - Predicate filterNot = null; - - final String strContains = VFilters.SINGLETON_INSTANCE.getTxfContains().getText(); - final String strWithout = VFilters.SINGLETON_INSTANCE.getTxfWithout().getText(); - - final boolean useName = VFilters.SINGLETON_INSTANCE.getChbTextName().isSelected(); - final boolean useType = VFilters.SINGLETON_INSTANCE.getChbTextType().isSelected(); - final boolean useText = VFilters.SINGLETON_INSTANCE.getChbTextText().isSelected(); - - if (!strContains.isEmpty()) { - final String[] splitContains = strContains + + String[] splitText = text .replaceAll(",", "") .replaceAll(" ", " ") .toLowerCase().split(" "); - final List> ands = new ArrayList>(); + List> terms = new ArrayList>(); + for (String s : splitText) { + List> subands = new ArrayList>(); - for (final String s : splitContains) { - final List> subands = new ArrayList>(); + if (inName) { subands.add(CardRulesPredicates.name(StringOp.CONTAINS_IC, s)); } + if (inType) { subands.add(CardRulesPredicates.joinedType(StringOp.CONTAINS_IC, s)); } + + // rules cannot compare in ignore-case way + if (inText) { subands.add(CardRulesPredicates.rules(StringOp.CONTAINS, s)); } - if (useName) { subands.add(CardRulesPredicates.name(StringOp.CONTAINS_IC, s)); } - if (useType) { subands.add(CardRulesPredicates.joinedType(StringOp.CONTAINS_IC, s)); } - // rules cannot compare in ignore-case way - if (useText) { subands.add(CardRulesPredicates.rules(StringOp.CONTAINS, s)); } - - ands.add(Predicates.or(subands)); - } - filterAnd = Predicates.and(ands); + terms.add(Predicates.or(subands)); } - - if (!strWithout.isEmpty()) { - final String[] splitWithout = strWithout - .replaceAll(" ", " ") - .replaceAll(",", "") - .toLowerCase().split(" "); - - final List> nots = new ArrayList>(); - - for (final String s : splitWithout) { - final List> subnots = new ArrayList>(); - - if (useName) { subnots.add(CardRulesPredicates.name(StringOp.CONTAINS_IC, s)); } - if (useType) { subnots.add(CardRulesPredicates.joinedType(StringOp.CONTAINS_IC, s)); } - // rules cannot compare in ignore-case way - if (useText) { subnots.add(CardRulesPredicates.rules(StringOp.CONTAINS, s)); } - - nots.add(Predicates.or(subnots)); - } - filterNot = Predicates.not(Predicates.or(nots)); - } - Predicate preResult = optimizedAnd(filterAnd, filterNot); - if (preResult == null) { - return Predicates.alwaysTrue(); - } - return Predicates.compose(preResult, CardPrinted.FN_GET_RULES); + Predicate textFilter = invert ? Predicates.not(Predicates.or(terms)) : Predicates.and(terms); + + return Predicates.compose(textFilter, CardPrinted.FN_GET_RULES); } - private static Predicate getCardRulesFieldPredicate(String min, String max, CardRulesPredicates.LeafNumber.CardField field) { - boolean hasMin = !("*".equals(min)); - boolean hasMax = !("10+".equals(max)); + private static Predicate getCardRulesFieldPredicate(int min, int max, CardRulesPredicates.LeafNumber.CardField field) { + boolean hasMin = 0 != min; + boolean hasMax = 10 != max; - Predicate pMin = !hasMin ? null : new CardRulesPredicates.LeafNumber(field, ComparableOp.GT_OR_EQUAL, Integer.valueOf(min)); - Predicate pMax = !hasMax ? null : new CardRulesPredicates.LeafNumber(field, ComparableOp.LT_OR_EQUAL, Integer.valueOf(max)); + Predicate pMin = !hasMin ? null : new CardRulesPredicates.LeafNumber(field, ComparableOp.GT_OR_EQUAL, min); + Predicate pMax = !hasMax ? null : new CardRulesPredicates.LeafNumber(field, ComparableOp.LT_OR_EQUAL, max); return optimizedAnd(pMin, pMax); } @@ -341,78 +125,23 @@ public class SFilterUtil { } /** - * Validates combo box input, assembles predicate filters for each case, - * stacks them all together, and returns the predicate. - * - * @return Predicate + * builds a filter for an interval on a card field */ - public static Predicate buildIntervalFilter() { - final VFilters view = VFilters.SINGLETON_INSTANCE; + public static Predicate buildIntervalFilter( + Map> spinners, VCardCatalog.RangeTypes field) { + Pair sPair = spinners.get(field); + Predicate fieldFilter = getCardRulesFieldPredicate( + Integer.valueOf(sPair.a.getValue().toString()), Integer.valueOf(sPair.b.getValue().toString()), field.cardField); - // Must include -1 so non-creatures are included by default. - Predicate preToughness = getCardRulesFieldPredicate(view.getCbxTLow().getSelectedItem().toString(), view.getCbxTHigh().getSelectedItem().toString(), CardRulesPredicates.LeafNumber.CardField.TOUGHNESS); - Predicate prePower = getCardRulesFieldPredicate(view.getCbxPLow().getSelectedItem().toString(), view.getCbxPHigh().getSelectedItem().toString(), CardRulesPredicates.LeafNumber.CardField.POWER); - Predicate preCMC = getCardRulesFieldPredicate(view.getCbxCMCLow().getSelectedItem().toString(), view.getCbxCMCHigh().getSelectedItem().toString(), CardRulesPredicates.LeafNumber.CardField.CMC); + if (null != fieldFilter && VCardCatalog.RangeTypes.CMC != field) + { + fieldFilter = Predicates.and(fieldFilter, CardRulesPredicates.Presets.IS_CREATURE); + } - Predicate preCreature = optimizedAnd(preToughness, prePower); - preCreature = preCreature == null ? null : Predicates.and(preCreature, CardRulesPredicates.Presets.IS_CREATURE); - - Predicate preFinal = optimizedAnd(preCMC, preCreature); - if (preFinal == null) { + if (fieldFilter == null) { return Predicates.alwaysTrue(); } else { - return Predicates.compose(preFinal, CardPrinted.FN_GET_RULES); - } - } - - //========== Custom class handling - - /** - * A panel with a checkbox and an icon, which will toggle the - * checkbox when anywhere in the panel is clicked. - */ - @SuppressWarnings("serial") - private static class ChbPnl extends JPanel implements ItemListener { - private final JCheckBox checkBox = new JCheckBox(); - private final Image img; - - public ChbPnl(final Image img0, final String tooltip) { - super(); - this.img = img0; - this.setOpaque(false); - checkBox.setBorder(new EmptyBorder(0, 20, 0, 0)); - checkBox.setOpaque(false); - checkBox.setSelected(true); - checkBox.addItemListener(this); - checkBox.setToolTipText(tooltip); - add(checkBox); - - this.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(final MouseEvent me) { - checkBox.doClick(); - } - }); - } - - public JCheckBox getCheckBox() { - return this.checkBox; - } - - @Override - protected void paintComponent(final Graphics g) { - super.paintComponent(g); - g.drawImage(img, 0, 0, null); - } - - /* (non-Javadoc) - * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent) - */ - @Override - public void itemStateChanged(final ItemEvent arg0) { - if (!preventFiltering) { - VFilters.SINGLETON_INSTANCE.getLayoutControl().buildFilter(); - } + return Predicates.compose(fieldFilter, CardPrinted.FN_GET_RULES); } } } diff --git a/src/main/java/forge/gui/deckeditor/controllers/CCardCatalog.java b/src/main/java/forge/gui/deckeditor/controllers/CCardCatalog.java index 4d42b294558..b876368724c 100644 --- a/src/main/java/forge/gui/deckeditor/controllers/CCardCatalog.java +++ b/src/main/java/forge/gui/deckeditor/controllers/CCardCatalog.java @@ -1,11 +1,50 @@ package forge.gui.deckeditor.controllers; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.swing.JComponent; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.KeyStroke; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; + import forge.Command; +import forge.Singletons; +import forge.card.CardEdition; +import forge.card.EditionCollection; +import forge.deck.DeckBase; +import forge.game.GameFormat; import forge.gui.deckeditor.CDeckEditorUI; +import forge.gui.deckeditor.SEditorUtil; +import forge.gui.deckeditor.SFilterUtil; import forge.gui.deckeditor.views.VCardCatalog; +import forge.gui.deckeditor.views.VCardCatalog.RangeTypes; import forge.gui.framework.ICDoc; +import forge.gui.home.quest.DialogChooseSets; import forge.gui.toolbox.FLabel; +import forge.gui.toolbox.FSpinner; +import forge.item.CardPrinted; import forge.item.InventoryItem; +import forge.item.ItemPredicate; +import forge.quest.QuestWorld; +import forge.quest.data.GameFormatQuest; +import forge.util.Pair; /** * Controls the "card catalog" panel in the deck editor UI. @@ -17,7 +56,12 @@ public enum CCardCatalog implements ICDoc { /** */ SINGLETON_INSTANCE; - // refresh analysis on add + private final Set> activePredicates = new HashSet>(); + private final Set activeFormats = new HashSet(); + private final Set activeWorlds = new HashSet(); + private final Set activeRanges = EnumSet.noneOf(RangeTypes.class); + + private boolean disableFiltering = false; private CCardCatalog() { } @@ -38,8 +82,8 @@ public enum CCardCatalog implements ICDoc { @Override @SuppressWarnings("serial") public void initialize() { - // Add/remove buttons - ((FLabel) VCardCatalog.SINGLETON_INSTANCE.getBtnAdd()).setCommand(new Command() { + // Add/remove buttons (refresh analysis on add) + VCardCatalog.SINGLETON_INSTANCE.getBtnAdd().setCommand(new Command() { @Override public void execute() { CDeckEditorUI.SINGLETON_INSTANCE.getCurrentEditorController().addCard(); @@ -48,8 +92,7 @@ public enum CCardCatalog implements ICDoc { CProbabilities.SINGLETON_INSTANCE.update(); } }); - - ((FLabel) VCardCatalog.SINGLETON_INSTANCE.getBtnAdd4()).setCommand(new Command() { + VCardCatalog.SINGLETON_INSTANCE.getBtnAdd4().setCommand(new Command() { @Override public void execute() { final InventoryItem item = CDeckEditorUI.SINGLETON_INSTANCE @@ -65,6 +108,180 @@ public enum CCardCatalog implements ICDoc { CProbabilities.SINGLETON_INSTANCE.update(); } }); + + final Command updateFilterCommand = new Command() { + @Override + public void execute() { + if (!disableFiltering) { + applyCurrentFilter(); + } + } + }; + + for (FLabel statLabel : VCardCatalog.SINGLETON_INSTANCE.getStatLabels().values()) { + statLabel.setCommand(updateFilterCommand); + } + + VCardCatalog.SINGLETON_INSTANCE.getStatLabel(SEditorUtil.StatTypes.TOTAL).setCommand(new Command() { + private boolean lastToggle = true; + + @Override + public void execute() { + disableFiltering = true; + lastToggle = !lastToggle; + for (SEditorUtil.StatTypes s : SEditorUtil.StatTypes.values()) { + if (SEditorUtil.StatTypes.TOTAL != s) { + VCardCatalog.SINGLETON_INSTANCE.getStatLabel(s).setSelected(lastToggle); + } + } + disableFiltering = false; + applyCurrentFilter(); + } + }); + + // assemble add restriction menu + VCardCatalog.SINGLETON_INSTANCE.getBtnAddRestriction().setCommand(new Command() { + @Override + public void execute() { + JPopupMenu popup = new JPopupMenu("Popup"); + addMenuItem(popup, "Current text search", canSearch(), + KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), + new Command() { + @Override + public void execute() { + addRestriction(buildSearchRestriction(), null, null); + } + }); + JMenu fmt = new JMenu("Format"); + for (final GameFormat f : Singletons.getModel().getFormats()) { + addMenuItem(fmt, f.getName(), !isActive(activeFormats, f), null, new Command() { + @Override + public void execute() { + addRestriction(buildFormatRestriction(f.toString(), f), activeFormats, f); + } + }); + } + popup.add(fmt); + addMenuItem(popup, "Edition (set)...", true, null, new Command() { + @Override + public void execute() { + final List setCodes = new ArrayList(); + new DialogChooseSets(setCodes, new Runnable() { + @Override + public void run() { + if (setCodes.isEmpty()) { + return; + } + + GameFormat f = new GameFormat(null, setCodes, null); + + StringBuilder label = new StringBuilder("Sets:"); + boolean truncated = false; + for (String code : setCodes) + { + // don't let the full label get too long + if (32 > label.length()) { + label.append(" ").append(code).append(";"); + } else { + truncated = true; + break; + } + } + + // chop off last semicolons + label.delete(label.length() - 1, label.length()); + + if (truncated) { + label.append("..."); + } + + addRestriction(buildFormatRestriction(label.toString(), f), null, null); + } + }); + } + }); + JMenu range = new JMenu("Value range"); + for (final RangeTypes t : RangeTypes.values()) { + addMenuItem(range, t.toLabelString() + " restriction", !isActive(activeRanges, t), null, new Command() { + @Override + public void execute() { + addRestriction(buildRangeRestriction(t), activeRanges, t); + } + }); + } + popup.add(range); + JMenu world = new JMenu("Quest world"); + for (final QuestWorld w : Singletons.getModel().getWorlds()) { + addMenuItem(world, w.getName(), !isActive(activeWorlds, w), null, new Command() { + @Override + public void execute() { + addRestriction(buildWorldRestriction(w), activeWorlds, w); + } + }); + } + popup.add(world); + popup.show(VCardCatalog.SINGLETON_INSTANCE.getBtnAddRestriction(), 0, 0); + } + }); + + VCardCatalog.SINGLETON_INSTANCE.getCbSearchMode().addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent arg0) { + applyCurrentFilter(); + } + }); + + VCardCatalog.SINGLETON_INSTANCE.getTxfSearch().addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == 10) { + if (e.isControlDown() || e.isMetaDown()) { + if (canSearch()) { + addRestriction(buildSearchRestriction(), null, null); + } + } + } + } + + @Override + public void keyReleased(KeyEvent e) { + applyCurrentFilter(); + } + }); + + VCardCatalog.SINGLETON_INSTANCE.getLblName().setCommand(updateFilterCommand); + VCardCatalog.SINGLETON_INSTANCE.getLblType().setCommand(updateFilterCommand); + VCardCatalog.SINGLETON_INSTANCE.getLblText().setCommand(updateFilterCommand); + + // ensure mins can's exceed maxes and maxes can't fall below mins + for (Pair sPair : VCardCatalog.SINGLETON_INSTANCE.getSpinners().values()) { + final FSpinner min = sPair.a; + final FSpinner max = sPair.b; + + min.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent arg0) { + if (Integer.parseInt(max.getValue().toString()) < + Integer.parseInt(min.getValue().toString())) + { + max.setValue(min.getValue()); + } + applyCurrentFilter(); + } + }); + + max.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent arg0) { + if (Integer.parseInt(min.getValue().toString()) > + Integer.parseInt(max.getValue().toString())) + { + min.setValue(max.getValue()); + } + applyCurrentFilter(); + } + }); + } } /* (non-Javadoc) @@ -73,4 +290,220 @@ public enum CCardCatalog implements ICDoc { @Override public void update() { } + + @SuppressWarnings("unchecked") + public void applyCurrentFilter() { + // The main trick here is to apply a CardPrinted predicate + // to the table. CardRules will lead to difficulties. + + List> cardPredicates = new ArrayList>(); + cardPredicates.add(Predicates.instanceOf(CardPrinted.class)); + cardPredicates.add(SFilterUtil.buildColorAndTypeFilter(VCardCatalog.SINGLETON_INSTANCE.getStatLabels())); + cardPredicates.addAll(activePredicates); + + // apply current values in the range filters + for (RangeTypes t : RangeTypes.values()) { + if (activeRanges.contains(t)) { + cardPredicates.add(SFilterUtil.buildIntervalFilter(VCardCatalog.SINGLETON_INSTANCE.getSpinners(), t)); + } + } + + // get the current contents of the search box + cardPredicates.add(SFilterUtil.buildTextFilter( + VCardCatalog.SINGLETON_INSTANCE.getTxfSearch().getText(), + 0 != VCardCatalog.SINGLETON_INSTANCE.getCbSearchMode().getSelectedIndex(), + VCardCatalog.SINGLETON_INSTANCE.getLblName().isSelected(), + VCardCatalog.SINGLETON_INSTANCE.getLblType().isSelected(), + VCardCatalog.SINGLETON_INSTANCE.getLblText().isSelected())); + + Predicate cardFilter = Predicates.and(cardPredicates); + + // Until this is filterable, always show packs and decks in the card shop. + List> itemPredicates = new ArrayList>(); + itemPredicates.add(cardFilter); + itemPredicates.add(ItemPredicate.Presets.IS_PACK); + itemPredicates.add(ItemPredicate.Presets.IS_DECK); + Predicate filter = Predicates.or(itemPredicates); + + // Apply to table + // TODO: is there really no way to make this type safe? + ((ACEditorBase)CDeckEditorUI.SINGLETON_INSTANCE.getCurrentEditorController()) + .getTableCatalog().setFilter(filter); + } + + private boolean canSearch() { + return !VCardCatalog.SINGLETON_INSTANCE.getTxfSearch().getText().isEmpty() && + (VCardCatalog.SINGLETON_INSTANCE.getLblName().isSelected() || + VCardCatalog.SINGLETON_INSTANCE.getLblType().isSelected() || + VCardCatalog.SINGLETON_INSTANCE.getLblText().isSelected()); + } + + private boolean isActive(Set activeSet, T key) { + return activeSet.contains(key); + } + + private JMenuItem createMenuItem(String label, boolean enabled, KeyStroke accelerator, final Command onClick) { + JMenuItem item = new JMenuItem(label); + item.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + if (null != onClick) { + onClick.execute(); + } + } + }); + item.setEnabled(enabled); + item.setAccelerator(accelerator); + return item; + } + + private void addMenuItem(JPopupMenu parent, String label, boolean enabled, KeyStroke accelerator, Command onClick) { + parent.add(createMenuItem(label, enabled, accelerator, onClick)); + } + + private void addMenuItem(JMenuItem parent, String label, boolean enabled, KeyStroke accelerator, Command onClick) { + parent.add(createMenuItem(label, enabled, accelerator, onClick)); + } + + @SuppressWarnings("serial") + private void addRestriction(Pair> restriction, final Set activeSet, final T key) { + final Predicate predicate = restriction.b; + + if (null != predicate && activePredicates.contains(predicate)) { + return; + } + + VCardCatalog.SINGLETON_INSTANCE.addRestrictionWidget(restriction.a, new Command() { + @Override + public void execute() { + if (null != key) { + activeSet.remove(key); + } + if (null != predicate) { + activePredicates.remove(predicate); + } + applyCurrentFilter(); + } + }); + + if (null != key) { + activeSet.add(key); + } + if (null != predicate) { + activePredicates.add(predicate); + } + applyCurrentFilter(); + } + + private Pair> buildRangeRestriction(RangeTypes t) { + Pair s = VCardCatalog.SINGLETON_INSTANCE.getSpinners().get(t); + s.a.setValue(0); + s.b.setValue(10); + + return new Pair>( + VCardCatalog.SINGLETON_INSTANCE.buildRangeRestrictionWidget(t), null); + } + + private String buildSearchRestrictionText(String text, boolean isInverse, boolean wantName, boolean wantType, boolean wantText) { + StringBuilder sb = new StringBuilder(); + sb.append(isInverse ? "Without" : "Contains"); + sb.append(": '").append(text).append("' in:"); + if (wantName) { sb.append(" name,"); } + if (wantType) { sb.append(" type,"); } + if (wantText) { sb.append(" text,"); } + sb.delete(sb.length() - 1, sb.length()); // chop off last comma + + return sb.toString(); + } + + private Pair> buildSearchRestriction() { + boolean isInverse = + VCardCatalog.SEARCH_MODE_INVERSE_INDEX == VCardCatalog.SINGLETON_INSTANCE.getCbSearchMode().getSelectedIndex(); + String text = VCardCatalog.SINGLETON_INSTANCE.getTxfSearch().getText(); + boolean wantName = VCardCatalog.SINGLETON_INSTANCE.getLblName().getSelected(); + boolean wantType = VCardCatalog.SINGLETON_INSTANCE.getLblType().getSelected(); + boolean wantText = VCardCatalog.SINGLETON_INSTANCE.getLblText().getSelected(); + + String shortText = buildSearchRestrictionText(text, isInverse, wantName, wantType, wantText); + String fullText = null; + if (25 < text.length()) { + fullText = shortText; + shortText = buildSearchRestrictionText(text.substring(0, 22) + "...", + isInverse, wantName, wantType, wantText); + } + + VCardCatalog.SINGLETON_INSTANCE.getTxfSearch().setText(""); + + return new Pair>( + VCardCatalog.SINGLETON_INSTANCE.buildPlainRestrictionWidget(shortText, fullText), + SFilterUtil.buildTextFilter(text, isInverse, wantName, wantType, wantText)); + } + + private Pair> buildFormatRestriction(String displayName, GameFormat format) { + EditionCollection editions = Singletons.getModel().getEditions(); + StringBuilder tooltip = new StringBuilder("Sets:"); + + int lastLen = 0; + int lineLen = 0; + + // use HTML tooltips so we can insert line breaks + List sets = null == format ? null : format.getAllowedSetCodes(); + if (null == sets || sets.isEmpty()) { + tooltip.append(" All"); + } else { + for (String code : sets) { + // don't let a single line get too long + if (50 < lineLen) { + tooltip.append("
"); + lastLen += lineLen; + lineLen = 0; + } + + CardEdition edition = editions.get(code); + tooltip.append(" ").append(edition.getName()).append(" (").append(code).append("),"); + lineLen = tooltip.length() - lastLen; + } + + // chop off last comma + tooltip.delete(tooltip.length() - 1, tooltip.length()); + + tooltip.append("

Allowing identical cards from other sets"); + } + + List bannedCards = null == format ? null : format.getBannedCardNames(); + if (null != bannedCards && !bannedCards.isEmpty()) { + tooltip.append("

Banned:"); + lastLen += lineLen; + lineLen = 0; + + for (String cardName : bannedCards) { + // 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(""); + + return new Pair>( + VCardCatalog.SINGLETON_INSTANCE.buildPlainRestrictionWidget(displayName, tooltip.toString()), + format.getFilterRules()); + } + + private Pair> buildWorldRestriction(QuestWorld world) { + GameFormatQuest format = world.getFormat(); + if (null == format) { + // assumes that no world other than the main world will have a null format + format = Singletons.getModel().getQuest().getMainFormat(); + } + return buildFormatRestriction(world.getName(), format); + } } diff --git a/src/main/java/forge/gui/deckeditor/controllers/CEditorDraftingProcess.java b/src/main/java/forge/gui/deckeditor/controllers/CEditorDraftingProcess.java index 997b887f74f..75e24ad8845 100644 --- a/src/main/java/forge/gui/deckeditor/controllers/CEditorDraftingProcess.java +++ b/src/main/java/forge/gui/deckeditor/controllers/CEditorDraftingProcess.java @@ -33,7 +33,6 @@ import forge.gui.deckeditor.views.VAllDecks; import forge.gui.deckeditor.views.VCardCatalog; import forge.gui.deckeditor.views.VCurrentDeck; import forge.gui.deckeditor.views.VDeckgen; -import forge.gui.deckeditor.views.VFilters; import forge.gui.framework.DragCell; import forge.gui.framework.SRearrangingUtil; import forge.gui.home.sanctioned.CSubmenuDraft; @@ -55,7 +54,6 @@ public class CEditorDraftingProcess extends ACEditorBase private IBoosterDraft boosterDraft; private String ccAddLabel = "Add card"; - private DragCell filtersParent = null; private DragCell allDecksParent = null; private DragCell deckGenParent = null; @@ -297,17 +295,6 @@ public class CEditorDraftingProcess extends ACEditorBase } } - if (VFilters.SINGLETON_INSTANCE.getParentCell() != null) { - filtersParent = VFilters.SINGLETON_INSTANCE.getParentCell(); - filtersParent.removeDoc(VFilters.SINGLETON_INSTANCE); - VFilters.SINGLETON_INSTANCE.setParentCell(null); - - // If filters was first tab, the new first tab needs re-selecting. - if (filtersParent.getDocs().size() > 0) { - filtersParent.setSelected(filtersParent.getDocs().get(0)); - } - } - // Fill in gaps SwingUtilities.invokeLater(new Runnable() { @Override @@ -340,16 +327,10 @@ public class CEditorDraftingProcess extends ACEditorBase VCurrentDeck.SINGLETON_INSTANCE.getPnlHeader().setVisible(true); //Re-add tabs - if (filtersParent != null) { - - filtersParent.addDoc(VFilters.SINGLETON_INSTANCE); - } if (deckGenParent != null) { - deckGenParent.addDoc(VDeckgen.SINGLETON_INSTANCE); } if (allDecksParent != null) { - allDecksParent.addDoc(VAllDecks.SINGLETON_INSTANCE); } diff --git a/src/main/java/forge/gui/deckeditor/controllers/CEditorPreferences.java b/src/main/java/forge/gui/deckeditor/controllers/CEditorPreferences.java index 23db62b0427..4f611eb9f75 100644 --- a/src/main/java/forge/gui/deckeditor/controllers/CEditorPreferences.java +++ b/src/main/java/forge/gui/deckeditor/controllers/CEditorPreferences.java @@ -12,7 +12,6 @@ import forge.gui.deckeditor.SEditorIO; import forge.gui.deckeditor.SEditorIO.EditorPreference; import forge.gui.deckeditor.tables.SColumnUtil; import forge.gui.deckeditor.tables.SColumnUtil.ColumnName; -import forge.gui.deckeditor.views.VCardCatalog; import forge.gui.deckeditor.views.VCurrentDeck; import forge.gui.deckeditor.views.VEditorPreferences; import forge.gui.framework.ICDoc; @@ -57,6 +56,7 @@ public enum CEditorPreferences implements ICDoc { prefsDict.put(prefsInstance.getChbCatalogAI(), ColumnName.CAT_AI); prefsDict.put(prefsInstance.getChbCatalogPower(), ColumnName.CAT_POWER); prefsDict.put(prefsInstance.getChbCatalogToughness(), ColumnName.CAT_TOUGHNESS); + prefsDict.put(prefsInstance.getChbCatalogOwned(), ColumnName.CAT_OWNED); // Deck prefsDict.put(prefsInstance.getChbDeckColor(), ColumnName.DECK_COLOR); @@ -82,8 +82,6 @@ public enum CEditorPreferences implements ICDoc { } // Catalog/Deck Stats - VEditorPreferences.SINGLETON_INSTANCE.getChbCatalogStats().setSelected( - SEditorIO.getPref(EditorPreference.stats_catalog)); VEditorPreferences.SINGLETON_INSTANCE.getChbDeckStats().setSelected( SEditorIO.getPref(EditorPreference.stats_deck)); VEditorPreferences.SINGLETON_INSTANCE.getChbCardDisplayUnique().setSelected( @@ -94,9 +92,6 @@ public enum CEditorPreferences implements ICDoc { if (!SEditorIO.getPref(EditorPreference.stats_deck)) { VCurrentDeck.SINGLETON_INSTANCE.getPnlStats().setVisible(false); } - if (!SEditorIO.getPref(EditorPreference.stats_catalog)) { - VCardCatalog.SINGLETON_INSTANCE.getPnlStats().setVisible(false); - } boolean wantElastic = SEditorIO.getPref(EditorPreference.elastic_columns); boolean wantUnique = SEditorIO.getPref(EditorPreference.display_unique_only); @@ -110,13 +105,6 @@ public enum CEditorPreferences implements ICDoc { curEditor.getTableDeck().updateView(true); } - VEditorPreferences.SINGLETON_INSTANCE.getChbCatalogStats().addItemListener(new ItemListener() { - @Override public void itemStateChanged(final ItemEvent e) { - VCardCatalog.SINGLETON_INSTANCE.getPnlStats().setVisible( - ((JCheckBox) e.getSource()).isSelected()); - SEditorIO.setPref(EditorPreference.stats_catalog, ((JCheckBox) e.getSource()).isSelected()); - SEditorIO.savePreferences(); } }); - VEditorPreferences.SINGLETON_INSTANCE.getChbDeckStats().addItemListener(new ItemListener() { @Override public void itemStateChanged(final ItemEvent e) { VCurrentDeck.SINGLETON_INSTANCE.getPnlStats().setVisible( diff --git a/src/main/java/forge/gui/deckeditor/controllers/CEditorQuestCardShop.java b/src/main/java/forge/gui/deckeditor/controllers/CEditorQuestCardShop.java index 4b643691272..9e9a01c5cf2 100644 --- a/src/main/java/forge/gui/deckeditor/controllers/CEditorQuestCardShop.java +++ b/src/main/java/forge/gui/deckeditor/controllers/CEditorQuestCardShop.java @@ -117,15 +117,14 @@ public final class CEditorQuestCardShop extends ACEditorBase> columnsCatalog = SColumnUtil.getCatalogDefaultColumns(); final List> columnsDeck = SColumnUtil.getDeckDefaultColumns(); - // Add "price", "decks", and "new" column in catalog and deck + // Add spell shop-specific columns columnsCatalog.add(SColumnUtil.getColumn(ColumnName.CAT_PURCHASE_PRICE)); columnsCatalog.get(columnsCatalog.size() - 1).setSortAndDisplayFunctions( this.fnPriceCompare, this.fnPriceGet); - // card shop doesn't need "New" column - //columnsCatalog.add(SColumnUtil.getColumn(ColumnName.CAT_NEW)); - //columnsCatalog.get(columnsCatalog.size() - 1).setSortAndDisplayFunctions( - // this.questData.getCards().getFnNewCompare(), this.questData.getCards().getFnNewGet()); + columnsCatalog.add(1, SColumnUtil.getColumn(ColumnName.CAT_OWNED)); + columnsCatalog.get(1).setSortAndDisplayFunctions( + questData.getCards().getFnOwnedCompare(), questData.getCards().getFnOwnedGet()); columnsDeck.add(SColumnUtil.getColumn(ColumnName.DECK_SALE_PRICE)); columnsDeck.get(columnsDeck.size() - 1).setSortAndDisplayFunctions( @@ -139,7 +138,7 @@ public final class CEditorQuestCardShop extends ACEditorBase
(C at beginning of class name denotes a control class.) - * - */ -public enum CFilters implements ICDoc { - /** */ - SINGLETON_INSTANCE; - - private boolean filtersAllEnabled = true; - - //========== Overridden methods - - /* (non-Javadoc) - * @see forge.gui.framework.ICDoc#getCommandOnSelect() - */ - @Override - public Command getCommandOnSelect() { - return null; - } - - /* (non-Javadoc) - * @see forge.gui.framework.ICDoc#initialize() - */ - @SuppressWarnings("serial") - @Override - public void initialize() { - final ItemListener iliFilter = new ItemListener() { - @Override - public void itemStateChanged(final ItemEvent arg0) { - if (!SFilterUtil.isFilteringPrevented()) { - buildFilter(); - } - } - }; - - VFilters.SINGLETON_INSTANCE.getCbxSets().addItemListener(iliFilter); - VFilters.SINGLETON_INSTANCE.getCbxPLow().addItemListener(iliFilter); - VFilters.SINGLETON_INSTANCE.getCbxPHigh().addItemListener(iliFilter); - VFilters.SINGLETON_INSTANCE.getCbxTLow().addItemListener(iliFilter); - VFilters.SINGLETON_INSTANCE.getCbxTHigh().addItemListener(iliFilter); - VFilters.SINGLETON_INSTANCE.getCbxCMCLow().addItemListener(iliFilter); - VFilters.SINGLETON_INSTANCE.getCbxCMCHigh().addItemListener(iliFilter); - - ((FLabel) VFilters.SINGLETON_INSTANCE.getBtnToggle()).setCommand(new Command() { - @Override - public void execute() { - SFilterUtil.setPreventFiltering(true); - toggleColorTypeSetFilter(); - SFilterUtil.setPreventFiltering(false); - buildFilter(); - } - }); - - ((FLabel) VFilters.SINGLETON_INSTANCE.getBtnResetIntervals()).setCommand(new Command() { - @Override - public void execute() { - SFilterUtil.setPreventFiltering(true); - VFilters.SINGLETON_INSTANCE.getCbxPLow().setSelectedIndex(0); - VFilters.SINGLETON_INSTANCE.getCbxTLow().setSelectedIndex(0); - VFilters.SINGLETON_INSTANCE.getCbxCMCLow().setSelectedIndex(0); - - VFilters.SINGLETON_INSTANCE.getCbxPHigh().setSelectedIndex( - VFilters.SINGLETON_INSTANCE.getCbxPHigh().getItemCount() - 1); - VFilters.SINGLETON_INSTANCE.getCbxTHigh().setSelectedIndex( - VFilters.SINGLETON_INSTANCE.getCbxTHigh().getItemCount() - 1); - VFilters.SINGLETON_INSTANCE.getCbxCMCHigh().setSelectedIndex( - VFilters.SINGLETON_INSTANCE.getCbxCMCHigh().getItemCount() - 1); - - SFilterUtil.setPreventFiltering(false); - buildFilter(); - } - }); - - ((FLabel) VFilters.SINGLETON_INSTANCE.getBtnResetText()).setCommand(new Command() { - @Override - public void execute() { - VFilters.SINGLETON_INSTANCE.getTxfContains().setText(""); - VFilters.SINGLETON_INSTANCE.getTxfWithout().setText(""); - buildFilter(); - } - }); - - VFilters.SINGLETON_INSTANCE.getTxfContains().addKeyListener(new KeyAdapter() { - @Override - public void keyReleased(final KeyEvent e) { - if (e.getKeyCode() == 10) { buildFilter(); } - } - }); - - VFilters.SINGLETON_INSTANCE.getTxfWithout().addKeyListener(new KeyAdapter() { - @Override - public void keyReleased(final KeyEvent e) { - if (e.getKeyCode() == 10) { buildFilter(); } - } - }); - } - - /* (non-Javadoc) - * @see forge.gui.framework.ICDoc#update() - */ - @Override - public void update() { - } - - /** - * Clear filter button_action performed. - * - * @param e - * the e - */ - private void toggleColorTypeSetFilter() { - VFilters.SINGLETON_INSTANCE.getCbxSets().setSelectedIndex(0); - - if (filtersAllEnabled) { - filtersAllEnabled = false; - SFilterUtil.toggleColorCheckboxes(false); - SFilterUtil.toggleTypeCheckboxes(false); - } - else { - filtersAllEnabled = true; - SFilterUtil.toggleColorCheckboxes(true); - SFilterUtil.toggleTypeCheckboxes(true); - } - } - - //=========== - - /** - * - * Assembles filter from the ones available. To prevent a block - * of filters from being used, set its parent panel's visibility to false. - * - * @param   extends InventoryItem - * @param   extends DeckBase - */ - @SuppressWarnings("unchecked") - public void buildFilter() { - // The main trick here is to apply a CardPrinted predicate - // to the table. CardRules will lead to difficulties. - - final ACEditorBase ed = (ACEditorBase) - CDeckEditorUI.SINGLETON_INSTANCE.getCurrentEditorController(); - - Predicate classFilter = Predicates.instanceOf(CardPrinted.class); - Predicate color = SFilterUtil.buildColorFilter(); - Predicate type = SFilterUtil.buildTypeFilter(); - Predicate set = SFilterUtil.buildSetAndFormatFilter(); - Predicate text = SFilterUtil.buildTextFilter(); - Predicate interval = SFilterUtil.buildIntervalFilter(); - - // Until this is filterable, always show packs and decks in the card shop. - Predicate cardFilter = Predicates.and(classFilter, color, type, set, text, interval); - - Predicate itemFilter = Predicates.or(cardFilter, ItemPredicate.Presets.IS_PACK, ItemPredicate.Presets.IS_DECK); - - // Apply to table - ed.getTableCatalog().setFilter((Predicate) itemFilter); - } -} diff --git a/src/main/java/forge/gui/deckeditor/tables/EditorTableModel.java b/src/main/java/forge/gui/deckeditor/tables/EditorTableModel.java index 040f67e28ef..269874c8389 100644 --- a/src/main/java/forge/gui/deckeditor/tables/EditorTableModel.java +++ b/src/main/java/forge/gui/deckeditor/tables/EditorTableModel.java @@ -19,6 +19,7 @@ Forge Team */ package forge.gui.deckeditor.tables; +import java.awt.Cursor; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.MouseAdapter; @@ -225,7 +226,7 @@ public final class EditorTableModel extends AbstractTab header.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(final MouseEvent e) { - if (null == header.getResizingColumn()) { + if (Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR) != header.getCursor()) { headerClicked(e); } } diff --git a/src/main/java/forge/gui/deckeditor/tables/SColumnUtil.java b/src/main/java/forge/gui/deckeditor/tables/SColumnUtil.java index 3f9441d0e2c..174c5800215 100644 --- a/src/main/java/forge/gui/deckeditor/tables/SColumnUtil.java +++ b/src/main/java/forge/gui/deckeditor/tables/SColumnUtil.java @@ -72,6 +72,7 @@ public final class SColumnUtil { CAT_AI, /** */ CAT_NEW, /** */ CAT_PURCHASE_PRICE, /** */ + CAT_OWNED, /** */ DECK_QUANTITY, /** */ DECK_NAME, /** */ DECK_COST, /** */ diff --git a/src/main/java/forge/gui/deckeditor/tables/TableColumnInfo.java b/src/main/java/forge/gui/deckeditor/tables/TableColumnInfo.java index c59be9b3aad..5a318daae5c 100644 --- a/src/main/java/forge/gui/deckeditor/tables/TableColumnInfo.java +++ b/src/main/java/forge/gui/deckeditor/tables/TableColumnInfo.java @@ -46,8 +46,6 @@ public class TableColumnInfo extends TableColumn { /** */ public TableColumnInfo() { super(); - setResizable(true); - setMinWidth(30); } /** diff --git a/src/main/java/forge/gui/deckeditor/views/ITableContainer.java b/src/main/java/forge/gui/deckeditor/views/ITableContainer.java index 460fd4b16a9..ab4402e8c6c 100644 --- a/src/main/java/forge/gui/deckeditor/views/ITableContainer.java +++ b/src/main/java/forge/gui/deckeditor/views/ITableContainer.java @@ -1,8 +1,10 @@ package forge.gui.deckeditor.views; -import javax.swing.JLabel; import javax.swing.JTable; +import forge.gui.deckeditor.SEditorUtil; +import forge.gui.toolbox.FLabel; + /** * Dictates methods needed for a class to act as a container for * a EditorTableView deck editing component. @@ -19,47 +21,5 @@ public interface ITableContainer { */ void setTableView(JTable tbl0); - // Various card count total labels - - /** @return {@link javax.swing.JLabel} */ - JLabel getLblTotal(); - - /** @return {@link javax.swing.JLabel} */ - JLabel getLblBlack(); - - /** @return {@link javax.swing.JLabel} */ - JLabel getLblBlue(); - - /** @return {@link javax.swing.JLabel} */ - JLabel getLblGreen(); - - /** @return {@link javax.swing.JLabel} */ - JLabel getLblRed(); - - /** @return {@link javax.swing.JLabel} */ - JLabel getLblWhite(); - - /** @return {@link javax.swing.JLabel} */ - JLabel getLblColorless(); - - /** @return {@link javax.swing.JLabel} */ - JLabel getLblArtifact(); - - /** @return {@link javax.swing.JLabel} */ - JLabel getLblEnchantment(); - - /** @return {@link javax.swing.JLabel} */ - JLabel getLblCreature(); - - /** @return {@link javax.swing.JLabel} */ - JLabel getLblSorcery(); - - /** @return {@link javax.swing.JLabel} */ - JLabel getLblInstant(); - - /** @return {@link javax.swing.JLabel} */ - JLabel getLblPlaneswalker(); - - /** @return {@link javax.swing.JLabel} */ - JLabel getLblLand(); -} + FLabel getStatLabel(SEditorUtil.StatTypes s); + } diff --git a/src/main/java/forge/gui/deckeditor/views/VCardCatalog.java b/src/main/java/forge/gui/deckeditor/views/VCardCatalog.java index ff775d0e61e..22c9e819ce0 100644 --- a/src/main/java/forge/gui/deckeditor/views/VCardCatalog.java +++ b/src/main/java/forge/gui/deckeditor/views/VCardCatalog.java @@ -1,12 +1,22 @@ package forge.gui.deckeditor.views; -import javax.swing.ImageIcon; -import javax.swing.JLabel; +import java.awt.Container; +import java.awt.FlowLayout; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.BorderFactory; +import javax.swing.JComboBox; +import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; +import javax.swing.JTextField; import net.miginfocom.swing.MigLayout; +import forge.Command; +import forge.card.CardRulesPredicates; +import forge.gui.WrapLayout; import forge.gui.deckeditor.SEditorUtil; import forge.gui.deckeditor.controllers.CCardCatalog; import forge.gui.framework.DragCell; @@ -15,6 +25,10 @@ import forge.gui.framework.EDocID; import forge.gui.framework.IVDoc; import forge.gui.toolbox.FLabel; import forge.gui.toolbox.FSkin; +import forge.gui.toolbox.FSpinner; +import forge.gui.toolbox.FTextField; +import forge.util.Pair; +import forge.util.TextUtil; /** * Assembles Swing components of card catalog in deck editor. @@ -25,55 +39,75 @@ import forge.gui.toolbox.FSkin; public enum VCardCatalog implements IVDoc, ITableContainer { /** */ SINGLETON_INSTANCE; + + public static final int SEARCH_MODE_INVERSE_INDEX = 1; // Fields used with interface IVDoc private DragCell parentCell; private final DragTab tab = new DragTab("Card Catalog"); - // Total and color count labels - private final JPanel pnlStats = new JPanel(); - private final JLabel lblTotal = buildLabel(SEditorUtil.ICO_TOTAL); - private final JLabel lblBlack = buildLabel(SEditorUtil.ICO_BLACK); - private final JLabel lblBlue = buildLabel(SEditorUtil.ICO_BLUE); - private final JLabel lblGreen = buildLabel(SEditorUtil.ICO_GREEN); - private final JLabel lblRed = buildLabel(SEditorUtil.ICO_RED); - private final JLabel lblWhite = buildLabel(SEditorUtil.ICO_WHITE); - private final JLabel lblColorless = buildLabel(SEditorUtil.ICO_COLORLESS); - - // Card type labels - private final JLabel lblArtifact = buildLabel(SEditorUtil.ICO_ARTIFACT); - private final JLabel lblCreature = buildLabel(SEditorUtil.ICO_CREATURE); - private final JLabel lblEnchantment = buildLabel(SEditorUtil.ICO_ENCHANTMENT); - private final JLabel lblInstant = buildLabel(SEditorUtil.ICO_INSTANT); - private final JLabel lblLand = buildLabel(SEditorUtil.ICO_LAND); - private final JLabel lblPlaneswalker = buildLabel(SEditorUtil.ICO_PLANESWALKER); - private final JLabel lblSorcery = buildLabel(SEditorUtil.ICO_SORCERY); - - private final JLabel lblTitle = new FLabel.Builder() - .fontSize(14).build(); - + // panel where special instructions appear private final JPanel pnlHeader = new JPanel(new MigLayout("insets 0, gap 0")); + private final FLabel lblTitle = new FLabel.Builder().fontSize(14).build(); + // Total and color count labels/filter toggles + private final JPanel pnlStats = new JPanel(); + private final Map statLabels = + new HashMap(); + + // card transfer buttons private final JPanel pnlAddButtons = new JPanel(new MigLayout("insets 0, gap 0, ax center, hidemode 3")); - - private final JLabel btnAdd = new FLabel.Builder() + private final FLabel btnAdd = new FLabel.Builder() .fontSize(14) .text("Add card") .tooltip("Add selected card to current deck (or double click the row)") .icon(FSkin.getIcon(FSkin.InterfaceIcons.ICO_PLUS)) .iconScaleAuto(false).hoverable(true).build(); - - private final JLabel btnAdd4 = new FLabel.Builder() + private final FLabel btnAdd4 = new FLabel.Builder() .fontSize(14) .text("Add 4 of card") .tooltip("Add up to 4 of selected card to current deck") .icon(FSkin.getIcon(FSkin.InterfaceIcons.ICO_PLUS)) .iconScaleAuto(false).hoverable(true).build(); + // restriction button and search widgets + private final JPanel pnlSearch = new JPanel(new MigLayout("insets 0, gap 5px, center")); + private final FLabel btnAddRestriction = new FLabel.Builder() + .text("Filter by") + .tooltip("Filter shown cards by various properties") + .hoverable(true).opaque(true).reactOnMouseDown(true).build(); + private final JComboBox cbSearchMode = new JComboBox(); + private final JTextField txfSearch = new FTextField.Builder().build(); + private final FLabel lblName = new FLabel.Builder().text("Name").selectable(true).selected(true).hoverable(true).opaque(true).build(); + private final FLabel lblType = new FLabel.Builder().text("Type").selectable(true).selected(true).hoverable(true).opaque(true).build(); + private final FLabel lblText = new FLabel.Builder().text("Text").selectable(true).selected(true).hoverable(true).opaque(true).build(); + private final JPanel pnlRestrictions = new JPanel(new WrapLayout(FlowLayout.LEFT, 10, 5)); + + // restriction widgets + public static enum RangeTypes { + CMC (CardRulesPredicates.LeafNumber.CardField.CMC), + POWER (CardRulesPredicates.LeafNumber.CardField.POWER), + TOUGHNESS (CardRulesPredicates.LeafNumber.CardField.TOUGHNESS); + + public final CardRulesPredicates.LeafNumber.CardField cardField; + + RangeTypes(CardRulesPredicates.LeafNumber.CardField cardField) { + this.cardField = cardField; + } + + public String toLabelString() { + if (this == CMC) { return toString(); } + return TextUtil.enumToLabel(this); + } + } + private final Map> spinners = new HashMap>(); + + // card table private JTable tblCards = null; private final JScrollPane scroller = new JScrollPane(); + //========== Constructor /** */ private VCardCatalog() { @@ -82,238 +116,172 @@ public enum VCardCatalog implements IVDoc, ITableContainer { scroller.setBorder(null); scroller.getViewport().setBorder(null); - lblTotal.setToolTipText("Total Card Count"); - lblBlack.setToolTipText("Black Card Count"); - lblBlue.setToolTipText("Blue Card Count"); - lblGreen.setToolTipText("Green Card Count"); - lblRed.setToolTipText("Red Card Count"); - lblWhite.setToolTipText("White Card Count"); - lblColorless.setToolTipText("Total Card Count"); - lblArtifact.setToolTipText("Artifact Card Count"); - lblCreature.setToolTipText("Creature Card Count"); - lblColorless.setToolTipText("Colorless Card Count"); - lblEnchantment.setToolTipText("Enchantment Card Count"); - lblInstant.setToolTipText("Instant Card Count"); - lblLand.setToolTipText("Land Card Count"); - lblPlaneswalker.setToolTipText("Planeswalker Card Count"); - lblSorcery.setToolTipText("Sorcery Card Count"); - pnlStats.setOpaque(false); pnlStats.setLayout(new MigLayout("insets 0, gap 5px, ax center, wrap 7")); - - final String constraints = "w 57px!, h 20px!"; - pnlStats.add(lblTotal, constraints); - pnlStats.add(lblWhite, constraints); - pnlStats.add(lblBlue, constraints); - pnlStats.add(lblBlack, constraints); - pnlStats.add(lblRed, constraints); - pnlStats.add(lblGreen, constraints); - pnlStats.add(lblColorless, constraints); - - pnlStats.add(lblLand, constraints); - pnlStats.add(lblArtifact, constraints); - pnlStats.add(lblCreature, constraints); - pnlStats.add(lblEnchantment, constraints); - pnlStats.add(lblPlaneswalker, constraints); - pnlStats.add(lblInstant, constraints); - pnlStats.add(lblSorcery, constraints); - - pnlAddButtons.setOpaque(false); + + for (SEditorUtil.StatTypes s : SEditorUtil.StatTypes.values()) { + FLabel label = buildToggleLabel(s, SEditorUtil.StatTypes.TOTAL != s); + statLabels.put(s, label); + pnlStats.add(label, "w 57px!, h 20px!"); + } + + statLabels.get(SEditorUtil.StatTypes.TOTAL).setToolTipText("Total cards (click to toggle all filters)"); + + pnlAddButtons.setOpaque(false); pnlAddButtons.add(btnAdd, "w 30%!, h 30px!, gap 0 0 5px 5px"); pnlAddButtons.add(btnAdd4, "w 30%!, h 30px!, gap 5% 5% 5px 5px"); + + pnlSearch.setOpaque(false); + pnlSearch.add(btnAddRestriction, "center, width pref+4"); + cbSearchMode.addItem("With"); + cbSearchMode.addItem("Without"); + pnlSearch.add(cbSearchMode, "center"); + pnlSearch.add(txfSearch, "pushx, growx"); + pnlSearch.add(new FLabel.Builder().text("in").build()); + pnlSearch.add(lblName, "width pref+4"); + pnlSearch.add(lblType, "width pref+4"); + pnlSearch.add(lblText, "width pref+4"); + + pnlRestrictions.setOpaque(false); pnlHeader.setOpaque(false); pnlHeader.add(lblTitle, "w 100%!, h 100%!"); + + // fill spinner map + for (RangeTypes t : RangeTypes.values()) { + spinners.put(t, new Pair( + new FSpinner.Builder().maxValue(10).build(), + new FSpinner.Builder().maxValue(10).build())); + } } //========== Overridden from IVDoc - /* (non-Javadoc) - * @see forge.gui.framework.IVDoc#getDocumentID() - */ @Override public EDocID getDocumentID() { return EDocID.EDITOR_CATALOG; } - /* (non-Javadoc) - * @see forge.gui.framework.IVDoc#getTabLabel() - */ @Override public DragTab getTabLabel() { return tab; } - /* (non-Javadoc) - * @see forge.gui.framework.IVDoc#getLayoutControl() - */ @Override public CCardCatalog getLayoutControl() { return CCardCatalog.SINGLETON_INSTANCE; } - /* (non-Javadoc) - * @see forge.gui.framework.IVDoc#setParentCell(forge.gui.framework.DragCell) - */ @Override public void setParentCell(DragCell cell0) { this.parentCell = cell0; } - /* (non-Javadoc) - * @see forge.gui.framework.IVDoc#getParentCell() - */ @Override public DragCell getParentCell() { return this.parentCell; } - /* (non-Javadoc) - * @see forge.gui.framework.IVDoc#populate() - */ @Override public void populate() { - parentCell.getBody().setLayout(new MigLayout("insets 0, gap 0, wrap, hidemode 3")); - parentCell.getBody().add(pnlHeader, "w 98%!, h 30px!, gap 1% 0 1% 10px"); - parentCell.getBody().add(pnlStats, "w 96%, h 50px!, gap 2% 0 1% 1%"); - parentCell.getBody().add(pnlAddButtons, "w 96%!, gap 2% 0 0 0"); - parentCell.getBody().add(scroller, "w 98%!, h 100% - 35px, gap 1% 0 1% 1%"); + JPanel parentBody = parentCell.getBody(); + parentBody.setLayout(new MigLayout("insets 0, gap 0, wrap, hidemode 3")); + parentBody.add(pnlHeader, "w 98%!, h 30px!, gap 1% 1% 0 0"); + parentBody.add(pnlStats, "w 96%, h 50px!, gap 2% 0 1% 1%"); + parentBody.add(pnlAddButtons, "w 96%!, gapleft 1%"); + parentBody.add(pnlSearch, "w 96%, gapleft 1%"); + parentBody.add(pnlRestrictions, "w 96%, gapleft 1%, gapright push"); + parentBody.add(scroller, "w 98%!, h 100% - 35px, gap 1% 0 0 1%"); } //========== Overridden from ITableContainer - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#setTableView() - */ @Override public void setTableView(final JTable tbl0) { this.tblCards = tbl0; scroller.setViewportView(tblCards); } - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblTotal() - */ @Override - public JLabel getLblTotal() { return lblTotal; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblBlack() - */ - @Override - public JLabel getLblBlack() { return lblBlack; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblBlue() - */ - @Override - public JLabel getLblBlue() { return lblBlue; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblGreen() - */ - @Override - public JLabel getLblGreen() { return lblGreen; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblRed() - */ - @Override - public JLabel getLblRed() { return lblRed; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblWhite() - */ - @Override - public JLabel getLblWhite() { return lblWhite; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblColorless() - */ - @Override - public JLabel getLblColorless() { return lblColorless; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblArtifact() - */ - @Override - public JLabel getLblArtifact() { return lblArtifact; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblEnchantment() - */ - @Override - public JLabel getLblEnchantment() { return lblEnchantment; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblCreature() - */ - @Override - public JLabel getLblCreature() { return lblCreature; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblSorcery() - */ - @Override - public JLabel getLblSorcery() { return lblSorcery; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblInstant() - */ - @Override - public JLabel getLblInstant() { return lblInstant; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblPlaneswalker() - */ - @Override - public JLabel getLblPlaneswalker() { return lblPlaneswalker; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblLand() - */ - @Override - public JLabel getLblLand() { return lblLand; } + public FLabel getStatLabel(SEditorUtil.StatTypes s) { + return statLabels.get(s); + } //========== Accessor/mutator methods + public JPanel getPnlHeader() { return pnlHeader; } + public FLabel getLblTitle() { return lblTitle; } + public JPanel getPnlAddButtons() { return pnlAddButtons; } + public FLabel getBtnAdd() { return btnAdd; } + public FLabel getBtnAdd4() { return btnAdd4; } + public FLabel getLblName() { return lblName; } + public FLabel getLblType() { return lblType; } + public FLabel getLblText() { return lblText; } + + public FLabel getBtnAddRestriction() { return btnAddRestriction; } + public JComboBox getCbSearchMode() { return cbSearchMode; } + public JTextField getTxfSearch() { return txfSearch; } - /** @return {@link javax.swing.JLabel} */ - public JLabel getLblTitle() { - return lblTitle; + public Map getStatLabels() { + return statLabels; } - - /** @return {@link javax.swing.JLabel} */ - public JLabel getBtnAdd() { - return btnAdd; + public Map> getSpinners() { + return spinners; } - - /** @return {@link javax.swing.JLabel} */ - public JLabel getBtnAdd4() { - return btnAdd4; - } - - /** @return {@link javax.swing.JPanel} */ - public JPanel getPnlHeader() { - return pnlHeader; - } - - /** @return {@link javax.swing.JPanel} */ - public JPanel getPnlStats() { - return pnlStats; - } - - /** @return {@link javax.swing.JPanel} */ - public JPanel getPnlAddButtons() { - return pnlAddButtons; - } - + //========== Other methods - - private JLabel buildLabel(final ImageIcon icon0) { - final JLabel lbl = new FLabel.Builder().text("0") - .icon(icon0).iconScaleAuto(false) - .fontSize(11) + private FLabel buildToggleLabel(SEditorUtil.StatTypes s, boolean selectable) { + return new FLabel.Builder() + .icon(s.img).iconScaleAuto(false) + .text("0").fontSize(11) + .tooltip(s.toLabelString()) + .hoverable(true).selectable(selectable).selected(selectable) .build(); + } - return lbl; + @SuppressWarnings("serial") + public void addRestrictionWidget(JComponent component, final Command onRemove) { + final JPanel pnl = new JPanel(new MigLayout("insets 2, gap 2, h 30!")); + + pnl.setOpaque(false); + pnl.setBorder(BorderFactory.createMatteBorder(1, 2, 1, 2, FSkin.getColor(FSkin.Colors.CLR_TEXT))); + + final Container parent = pnlRestrictions.getParent(); + + pnl.add(component, "h 30!, center"); + pnl.add(new FLabel.Builder().text("X").fontSize(10).hoverable(true) + .tooltip("Remove filter").cmdClick(new Command() { + @Override + public void execute() { + pnlRestrictions.remove(pnl); + pnlRestrictions.validate(); + parent.validate(); + parent.repaint(); + + onRemove.execute(); + } + }).build(), "top"); + + pnlRestrictions.add(pnl, "h 30!"); + + pnlRestrictions.validate(); + parent.validate(); + parent.repaint(); + } + + public JComponent buildRangeRestrictionWidget(RangeTypes t) { + JPanel pnl = new JPanel(new MigLayout("insets 0, gap 2")); + pnl.setOpaque(false); + + Pair s = spinners.get(t); + pnl.add(s.a, "w 45!"); + pnl.add(new FLabel.Builder().text("<=").fontSize(11).build()); + pnl.add(new FLabel.Builder().text(t.toLabelString()).fontSize(11).build()); + pnl.add(new FLabel.Builder().text("<=").fontSize(11).build()); + pnl.add(s.b, "w 45!"); + + return pnl; + } + + public JComponent buildPlainRestrictionWidget(String label, String tooltip) { + return new FLabel.Builder().text(label).tooltip(tooltip).fontSize(11).build(); } } diff --git a/src/main/java/forge/gui/deckeditor/views/VCurrentDeck.java b/src/main/java/forge/gui/deckeditor/views/VCurrentDeck.java index dc1a252881a..754c6ba3d64 100644 --- a/src/main/java/forge/gui/deckeditor/views/VCurrentDeck.java +++ b/src/main/java/forge/gui/deckeditor/views/VCurrentDeck.java @@ -1,8 +1,8 @@ package forge.gui.deckeditor.views; -import java.awt.Insets; +import java.util.HashMap; +import java.util.Map; -import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; @@ -101,7 +101,7 @@ public enum VCurrentDeck implements IVDoc, ITableContainer { .icon(FSkin.getIcon(FSkin.InterfaceIcons.ICO_EDIT)) .iconScaleAuto(false).hoverable(true).build(); - private final JTextField txfTitle = new FTextField(); + private final JTextField txfTitle = new FTextField.Builder().text("[New Deck]").build(); private final JPanel pnlRemove = new JPanel(); private final JPanel pnlHeader = new JPanel(); @@ -110,21 +110,8 @@ public enum VCurrentDeck implements IVDoc, ITableContainer { .fontSize(14).build(); private final JPanel pnlStats = new JPanel(); - private final JLabel lblTotal = buildLabel(SEditorUtil.ICO_TOTAL); - private final JLabel lblBlack = buildLabel(SEditorUtil.ICO_BLACK); - private final JLabel lblBlue = buildLabel(SEditorUtil.ICO_BLUE); - private final JLabel lblGreen = buildLabel(SEditorUtil.ICO_GREEN); - private final JLabel lblRed = buildLabel(SEditorUtil.ICO_RED); - private final JLabel lblWhite = buildLabel(SEditorUtil.ICO_WHITE); - private final JLabel lblColorless = buildLabel(SEditorUtil.ICO_COLORLESS); - - private final JLabel lblArtifact = buildLabel(SEditorUtil.ICO_ARTIFACT); - private final JLabel lblCreature = buildLabel(SEditorUtil.ICO_CREATURE); - private final JLabel lblEnchantment = buildLabel(SEditorUtil.ICO_ENCHANTMENT); - private final JLabel lblInstant = buildLabel(SEditorUtil.ICO_INSTANT); - private final JLabel lblLand = buildLabel(SEditorUtil.ICO_LAND); - private final JLabel lblPlaneswalker = buildLabel(SEditorUtil.ICO_PLANESWALKER); - private final JLabel lblSorcery = buildLabel(SEditorUtil.ICO_SORCERY); + private final Map statLabels = + new HashMap(); private JTable tblCards = null; private final JScrollPane scroller = new JScrollPane(tblCards); @@ -132,16 +119,6 @@ public enum VCurrentDeck implements IVDoc, ITableContainer { //========== Constructor private VCurrentDeck() { - // Title text area - txfTitle.setText("[New Deck]"); - txfTitle.setMargin(new Insets(5, 5, 5, 5)); - txfTitle.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2)); - txfTitle.setOpaque(true); - txfTitle.setEditable(true); - txfTitle.setFocusable(true); - txfTitle.setOpaque(true); - txfTitle.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2)); - // Header area pnlHeader.setOpaque(false); pnlHeader.setLayout(new MigLayout("insets 0, gap 0, ax center, hidemode 3")); @@ -166,45 +143,17 @@ public enum VCurrentDeck implements IVDoc, ITableContainer { scroller.setBorder(null); scroller.getViewport().setBorder(null); - lblTotal.setToolTipText("Total Card Count"); - lblBlack.setToolTipText("Black Card Count"); - lblBlue.setToolTipText("Blue Card Count"); - lblGreen.setToolTipText("Green Card Count"); - lblRed.setToolTipText("Red Card Count"); - lblWhite.setToolTipText("White Card Count"); - lblColorless.setToolTipText("Total Card Count"); - lblArtifact.setToolTipText("Artifact Card Count"); - lblCreature.setToolTipText("Creature Card Count"); - lblColorless.setToolTipText("Colorless Card Count"); - lblEnchantment.setToolTipText("Enchantment Card Count"); - lblInstant.setToolTipText("Instant Card Count"); - lblLand.setToolTipText("Land Card Count"); - lblPlaneswalker.setToolTipText("Planeswalker Card Count"); - lblSorcery.setToolTipText("Sorcery Card Count"); - pnlStats.setOpaque(false); pnlStats.setLayout(new MigLayout("insets 0, gap 5px, ax center, wrap 7")); - - final String constraints = "w 55px!, h 20px!"; - pnlStats.add(lblTotal, constraints); - pnlStats.add(lblWhite, constraints); - pnlStats.add(lblBlue, constraints); - pnlStats.add(lblBlack, constraints); - pnlStats.add(lblRed, constraints); - pnlStats.add(lblGreen, constraints); - pnlStats.add(lblColorless, constraints); - - pnlStats.add(lblLand, constraints); - pnlStats.add(lblArtifact, constraints); - pnlStats.add(lblCreature, constraints); - pnlStats.add(lblEnchantment, constraints); - pnlStats.add(lblPlaneswalker, constraints); - pnlStats.add(lblInstant, constraints); - pnlStats.add(lblSorcery, constraints); - - pnlRemoveButtons.setOpaque(false); - pnlRemoveButtons.add(btnRemove, "w 30%!, h 30px!, gap 0 0 5px 5px"); - pnlRemoveButtons.add(btnRemove4, "w 30%!, h 30px!, gap 0 0 5px 5px"); + for (SEditorUtil.StatTypes s : SEditorUtil.StatTypes.values()) { + FLabel label = buildLabel(s); + statLabels.put(s, label); + pnlStats.add(label, "w 55px!, h 20px!"); + } + + pnlRemoveButtons.setOpaque(false); + pnlRemoveButtons.add(btnRemove, "w 30%!, h 30px!, gap 0 0 5px 5px"); + pnlRemoveButtons.add(btnRemove4, "w 30%!, h 30px!, gap 0 0 5px 5px"); pnlRemoveButtons.add(btnDoSideboard, "w 30%!, h 30px!, gap 0 0 5px 5px"); } @@ -278,95 +227,12 @@ public enum VCurrentDeck implements IVDoc, ITableContainer { scroller.setViewportView(tblCards); } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblTotal() - */ - @Override - public JLabel getLblTotal() { return lblTotal; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblTotal() - */ public JLabel getLblTitle() { return lblTitle; } - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblBlack() - */ @Override - public JLabel getLblBlack() { return lblBlack; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblBlue() - */ - @Override - public JLabel getLblBlue() { return lblBlue; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblGreen() - */ - @Override - public JLabel getLblGreen() { return lblGreen; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblRed() - */ - @Override - public JLabel getLblRed() { return lblRed; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblWhite() - */ - @Override - public JLabel getLblWhite() { return lblWhite; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblColorless() - */ - @Override - public JLabel getLblColorless() { return lblColorless; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblArtifact() - */ - @Override - public JLabel getLblArtifact() { return lblArtifact; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblEnchantment() - */ - @Override - public JLabel getLblEnchantment() { return lblEnchantment; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblCreature() - */ - @Override - public JLabel getLblCreature() { return lblCreature; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblSorcery() - */ - @Override - public JLabel getLblSorcery() { return lblSorcery; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblInstant() - */ - @Override - public JLabel getLblInstant() { return lblInstant; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblPlaneswalker() - */ - @Override - public JLabel getLblPlaneswalker() { return lblPlaneswalker; } - - /* (non-Javadoc) - * @see forge.gui.deckeditor.views.ITableContainer#getLblLand() - */ - @Override - public JLabel getLblLand() { return lblLand; } + public FLabel getStatLabel(SEditorUtil.StatTypes s) { + return statLabels.get(s); + } //========== Retrieval @@ -432,12 +298,11 @@ public enum VCurrentDeck implements IVDoc, ITableContainer { //========== Other methods - private JLabel buildLabel(final ImageIcon icon0) { - final JLabel lbl = new FLabel.Builder().text("0") - .icon(icon0).iconScaleAuto(false) - .fontSize(11) - .build(); - - return lbl; + private FLabel buildLabel(SEditorUtil.StatTypes s) { + return new FLabel.Builder() + .icon(s.img).iconScaleAuto(false) + .text("0").fontSize(11) + .tooltip(s.toLabelString()) + .build(); } } diff --git a/src/main/java/forge/gui/deckeditor/views/VEditorPreferences.java b/src/main/java/forge/gui/deckeditor/views/VEditorPreferences.java index a983cd7d8a6..c4431280b0f 100644 --- a/src/main/java/forge/gui/deckeditor/views/VEditorPreferences.java +++ b/src/main/java/forge/gui/deckeditor/views/VEditorPreferences.java @@ -52,6 +52,7 @@ public enum VEditorPreferences implements IVDoc { private JCheckBox chbCatalogAI = new FCheckBox("AI"); private JCheckBox chbCatalogPower = new FCheckBox("Power"); private JCheckBox chbCatalogToughness = new FCheckBox("Toughness"); + private JCheckBox chbCatalogOwned = new FCheckBox("Owned (Spell shop)"); private JCheckBox chbDeckColor = new FCheckBox("Color"); private JCheckBox chbDeckRarity = new FCheckBox("Rarity"); @@ -62,7 +63,6 @@ public enum VEditorPreferences implements IVDoc { private JCheckBox chbDeckToughness = new FCheckBox("Toughness"); private JCheckBox chbDeckStats = new FCheckBox("Show stats in current deck"); - private JCheckBox chbCatalogStats = new FCheckBox("Show stats in card catalog"); private JCheckBox chbElasticColumns = new FCheckBox("Use elastic resizing when changing column widths"); private JCheckBox chbCardDisplayUnique = new FCheckBox("Show unique cards only (only affects Constructed)"); @@ -84,6 +84,7 @@ public enum VEditorPreferences implements IVDoc { chbCatalogAI.setFont(FSkin.getFont(12)); chbCatalogPower.setFont(FSkin.getFont(12)); chbCatalogToughness.setFont(FSkin.getFont(12)); + chbCatalogOwned.setFont(FSkin.getFont(12)); chbDeckColor.setFont(FSkin.getFont(12)); chbDeckRarity.setFont(FSkin.getFont(12)); @@ -94,17 +95,14 @@ public enum VEditorPreferences implements IVDoc { chbDeckToughness.setFont(FSkin.getFont(12)); chbDeckStats.setFont(FSkin.getFont(12)); - chbCatalogStats.setFont(FSkin.getFont(12)); chbElasticColumns.setFont(FSkin.getFont(12)); chbDeckStats.setSelected(true); - chbCatalogStats.setSelected(true); chbElasticColumns.setSelected(false); chbCardDisplayUnique.setFont(FSkin.getFont(12)); chbCardDisplayUnique.setSelected(false); pnl.add(lblStats, "h 25px!, gap 5px 5px 5px 5px, ax center, span 2 1"); - pnl.add(chbCatalogStats, "h 25px!, gap 5px 5px 5px 5px, ax center, span 2 1"); pnl.add(chbDeckStats, "h 25px!, gap 5px 5px 5px 5px, ax center, span 2 1"); pnl.add(chbElasticColumns, "h 25px!, gap 5px 5px 5px 5px, ax center, span 2 1"); @@ -116,7 +114,8 @@ public enum VEditorPreferences implements IVDoc { pnl.add(chbCatalogSet, constraints); pnl.add(chbCatalogPower, constraints); pnl.add(chbCatalogToughness, constraints); - pnl.add(chbCatalogAI, constraints + ", wrap"); + pnl.add(chbCatalogAI, constraints); + pnl.add(chbCatalogOwned, constraints + ", wrap"); pnl.add(lblDeck, constraints + ", span 2 1"); pnl.add(chbDeckColor, constraints); @@ -224,6 +223,11 @@ public enum VEditorPreferences implements IVDoc { return chbCatalogToughness; } + /** @return {@link javax.swing.JCheckBox} */ + public JCheckBox getChbCatalogOwned() { + return chbCatalogOwned; + } + /** @return {@link javax.swing.JCheckBox} */ public JCheckBox getChbDeckColor() { return chbDeckColor; @@ -269,15 +273,8 @@ public enum VEditorPreferences implements IVDoc { return chbElasticColumns; } - /** @return {@link javax.swing.JCheckBox} */ - public JCheckBox getChbCatalogStats() { - return chbCatalogStats; - } - /** @return {@link javax.swing.JCheckBox} */ public JCheckBox getChbCardDisplayUnique() { return chbCardDisplayUnique; } - //========== Other methods - } diff --git a/src/main/java/forge/gui/deckeditor/views/VFilters.java b/src/main/java/forge/gui/deckeditor/views/VFilters.java deleted file mode 100644 index 0562b7ee4bb..00000000000 --- a/src/main/java/forge/gui/deckeditor/views/VFilters.java +++ /dev/null @@ -1,333 +0,0 @@ -package forge.gui.deckeditor.views; - -import java.awt.Insets; - -import javax.swing.JCheckBox; -import javax.swing.JComboBox; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTextField; -import javax.swing.border.MatteBorder; - -import net.miginfocom.swing.MigLayout; -import forge.Singletons; -import forge.card.CardEdition; -import forge.game.GameFormat; -import forge.gui.deckeditor.SFilterUtil; -import forge.gui.deckeditor.controllers.CFilters; -import forge.gui.framework.DragCell; -import forge.gui.framework.DragTab; -import forge.gui.framework.EDocID; -import forge.gui.framework.IVDoc; -import forge.gui.toolbox.FCheckBox; -import forge.gui.toolbox.FLabel; -import forge.gui.toolbox.FSkin; -import forge.gui.toolbox.FTextField; - -/** - * Assembles Swing components of deck editor filter tab. - * - *

(V at beginning of class name denotes a view class.) - */ -public enum VFilters implements IVDoc { - /** */ - SINGLETON_INSTANCE; - - // Fields used with interface IVDoc - private DragCell parentCell; - private final DragTab tab = new DragTab("Filters"); - - // Text filter components - private final JTextField txfContains = new FTextField(); - private final JTextField txfWithout = new FTextField(); - private final JLabel lblContains = new FLabel.Builder() - .text("Contains:").fontSize(14).build(); - private final JLabel lblWithout = new FLabel.Builder() - .text("Without:").fontSize(14).build(); - - private final JCheckBox chbName = new FCheckBox("Name"); - private final JCheckBox chbType = new FCheckBox("Type"); - private final JCheckBox chbText = new FCheckBox("Text"); - - // Interval filter components - private final JComboBox cbxSets = new JComboBox(); - private final JComboBox cbxPLow = new JComboBox(); - private final JComboBox cbxPHigh = new JComboBox(); - private final JComboBox cbxTLow = new JComboBox(); - private final JComboBox cbxTHigh = new JComboBox(); - private final JComboBox cbxCMCLow = new JComboBox(); - private final JComboBox cbxCMCHigh = new JComboBox(); - - private final JLabel lblP = new FLabel.Builder() - .fontSize(12).text(" <= Power <= ").build(); - - private final JLabel lblT = new FLabel.Builder() - .fontSize(12).text(" <= Toughness <= ").build(); - - private final JLabel lblCMC = new FLabel.Builder() - .fontSize(12).text(" <= CMC <= ").build(); - - // Title labels - private final JLabel lblProperties = new FLabel.Builder() - .text("Properties").tooltip("Filter by color, type, set, or format. Click to toggle.") - .hoverable(true).fontSize(14).build(); - - private final JLabel lblText = new FLabel.Builder() - .text("Card Text").tooltip("Filter by card name, type, and text, space delimited. Click to reset.") - .hoverable(true).fontSize(14).build(); - - private final JLabel lblIntervals = new FLabel.Builder() - .text("Intervals").tooltip("Filter by power, toughness, or converted mana cost. Click to reset.") - .hoverable(true).fontSize(14).build(); - - // Container components - private final JPanel pnlText = new JPanel(new MigLayout( - "insets 0, gap 0, wrap 3, ax center")); - private final JPanel pnlIntervals = new JPanel(new MigLayout( - "insets 0, gap 0, wrap 3, ax center")); - - private JPanel pnlContainer = new JPanel(new MigLayout("insets 0, gap 0, wrap")); - private JScrollPane scroller = new JScrollPane(pnlContainer); - - //========== Constructor - private VFilters() { - String constraints = ""; - - // Sets/formats combo box - cbxSets.addItem("All sets and formats"); - for (final GameFormat s : Singletons.getModel().getFormats()) { - cbxSets.addItem(s); - } - for (final CardEdition s : Singletons.getModel().getEditions()) { - cbxSets.addItem(s); - } - - // Color/type searches - lblProperties.setBorder(new MatteBorder(0, 0, 1, 0, - FSkin.getColor(FSkin.Colors.CLR_BORDERS))); - lblText.setBorder(new MatteBorder(0, 0, 1, 0, - FSkin.getColor(FSkin.Colors.CLR_BORDERS))); - lblIntervals.setBorder(new MatteBorder(0, 0, 1, 0, - FSkin.getColor(FSkin.Colors.CLR_BORDERS))); - - // Text search - txfContains.setMargin(new Insets(5, 5, 5, 5)); - txfContains.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2)); - txfContains.setOpaque(true); - txfContains.setEditable(true); - txfContains.setFocusable(true); - txfContains.setOpaque(true); - txfContains.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2)); - - txfWithout.setMargin(new Insets(5, 5, 5, 5)); - txfWithout.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2)); - txfWithout.setOpaque(true); - txfWithout.setEditable(true); - txfWithout.setFocusable(true); - txfWithout.setOpaque(true); - txfWithout.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2)); - - pnlText.setOpaque(false); - pnlText.add(lblText, "w 210px!, h 25px!"); - pnlText.add(lblContains, "w 80px!, h 30px!"); - pnlText.add(txfContains, "pushx, growx, span 2 1, gap 5px 5px 2px 2px, h 30px!"); - pnlText.add(lblWithout, "w 80px!, h 30px!"); - pnlText.add(txfWithout, "pushx, growx, span 2 1, gap 5px 5px 2px 2px, h 30px!"); - pnlText.add(chbName, "pushx, growx, w 70px!, h 25px!, gap 5px 5px 2px 2px"); - pnlText.add(chbType, "pushx, growx, w 70px!, h 25px!, gap 0 5px 2px 2px"); - pnlText.add(chbText, "w 60px!, h 25px!, gap 0 5px 2px 2px"); - - chbName.setSelected(true); - chbType.setSelected(true); - chbText.setSelected(true); - - cbxPLow.addItem("*"); - cbxTLow.addItem("*"); - cbxCMCLow.addItem("*"); - - // Interval search - for (int i = 0; i < 10; i++) { - cbxPLow.addItem(i); - cbxTLow.addItem(i); - cbxCMCLow.addItem(i); - cbxPHigh.addItem(i); - cbxTHigh.addItem(i); - cbxCMCHigh.addItem(i); - } - - cbxPHigh.addItem("10+"); - cbxTHigh.addItem("10+"); - cbxCMCHigh.addItem("10+"); - - cbxPLow.setSelectedItem("*"); - cbxTLow.setSelectedItem("*"); - cbxCMCLow.setSelectedItem("*"); - cbxPHigh.setSelectedItem("10+"); - cbxTHigh.setSelectedItem("10+"); - cbxCMCHigh.setSelectedItem("10+"); - - constraints = "w 80px!, h 25px!, gap 0 0 0 0"; - pnlIntervals.add(cbxPLow, constraints); - pnlIntervals.add(lblP, "w 100px!, h 25px!"); - pnlIntervals.add(cbxPHigh, constraints); - - pnlIntervals.add(cbxTLow, constraints); - pnlIntervals.add(lblT, "w 100px!, h 25px!"); - pnlIntervals.add(cbxTHigh, constraints); - - pnlIntervals.add(cbxCMCLow, constraints); - pnlIntervals.add(lblCMC, "w 100px!, h 25px!"); - pnlIntervals.add(cbxCMCHigh, constraints); - - pnlIntervals.setOpaque(false); - - // Core layout - final String constraints2 = "w 90%!, gap 5% 0 1% 0"; - pnlContainer.add(lblProperties, "w 90%!, h 25px!, gap 5% 0 1% 0"); - pnlContainer.add(SFilterUtil.populateColorFilters(), constraints2); - pnlContainer.add(SFilterUtil.populateTypeFilters(), constraints2); - pnlContainer.add(cbxSets, constraints2 + ", h 25px!"); - - pnlContainer.add(lblText, "w 90%!, h 25px!, gap 5% 0 15px 0"); - pnlContainer.add(pnlText, constraints2); - - pnlContainer.add(lblIntervals, "w 90%!, h 25px!, gap 5% 0 15px 0"); - pnlContainer.add(pnlIntervals, constraints2); - - pnlContainer.setOpaque(false); - scroller.setOpaque(false); - scroller.getViewport().setOpaque(false); - scroller.setBorder(null); - scroller.getViewport().setBorder(null); - } - - //========== Overridden methods - - /* (non-Javadoc) - * @see forge.gui.framework.IVDoc#getDocumentID() - */ - @Override - public EDocID getDocumentID() { - return EDocID.EDITOR_FILTERS; - } - - /* (non-Javadoc) - * @see forge.gui.framework.IVDoc#getTabLabel() - */ - @Override - public DragTab getTabLabel() { - return tab; - } - - /* (non-Javadoc) - * @see forge.gui.framework.IVDoc#getLayoutControl() - */ - @Override - public CFilters getLayoutControl() { - return CFilters.SINGLETON_INSTANCE; - } - - /* (non-Javadoc) - * @see forge.gui.framework.IVDoc#setParentCell(forge.gui.framework.DragCell) - */ - @Override - public void setParentCell(final DragCell cell0) { - this.parentCell = cell0; - } - - /* (non-Javadoc) - * @see forge.gui.framework.IVDoc#getParentCell() - */ - @Override - public DragCell getParentCell() { - return this.parentCell; - } - - /* (non-Javadoc) - * @see forge.gui.framework.IVDoc#populate() - */ - @Override - public void populate() { - parentCell.getBody().setLayout(new MigLayout("insets 0, gap 0, wrap")); - parentCell.getBody().add(scroller, "w 96%!, h 96%, gap 2% 0 2% 0"); - } - - //========== Retrieval methods - /** @return {javax.swing.JLabel} */ - public JLabel getBtnToggle() { - return lblProperties; - } - - /** @return {javax.swing.JLabel} */ - public JLabel getBtnResetText() { - return lblText; - } - - /** @return {javax.swing.JLabel} */ - public JLabel getBtnResetIntervals() { - return lblIntervals; - } - - /** @return {javax.swing.JComboBox} */ - public JComboBox getCbxSets() { - return cbxSets; - } - - /** @return {javax.swing.JTextField} */ - public JTextField getTxfContains() { - return txfContains; - } - - /** @return {javax.swing.JTextField} */ - public JTextField getTxfWithout() { - return txfWithout; - } - - /** @return {javax.swing.JComboBox} */ - public JComboBox getCbxPLow() { - return cbxPLow; - } - - /** @return {javax.swing.JComboBox} */ - public JComboBox getCbxPHigh() { - return cbxPHigh; - } - - /** @return {javax.swing.JComboBox} */ - public JComboBox getCbxTLow() { - return cbxTLow; - } - - /** @return {javax.swing.JComboBox} */ - public JComboBox getCbxTHigh() { - return cbxTHigh; - } - - /** @return {javax.swing.JComboBox} */ - public JComboBox getCbxCMCLow() { - return cbxCMCLow; - } - - /** @return {javax.swing.JComboBox} */ - public JComboBox getCbxCMCHigh() { - return cbxCMCHigh; - } - - /** @return {javax.swing.JCheckBox} */ - public JCheckBox getChbTextName() { - return chbName; - } - - /** @return {javax.swing.JCheckBox} */ - public JCheckBox getChbTextType() { - return chbType; - } - - /** @return {javax.swing.JCheckBox} */ - public JCheckBox getChbTextText() { - return chbText; - } - //========== Custom class handling - -} diff --git a/src/main/java/forge/gui/deckeditor/views/VStatistics.java b/src/main/java/forge/gui/deckeditor/views/VStatistics.java index 2dd1b5001b3..ecfd5f4c2bd 100644 --- a/src/main/java/forge/gui/deckeditor/views/VStatistics.java +++ b/src/main/java/forge/gui/deckeditor/views/VStatistics.java @@ -43,22 +43,22 @@ public enum VStatistics implements IVDoc { // Total and color count labels private final JPanel pnlStats = new JPanel(); - private final JLabel lblMulti = buildLabel(SEditorUtil.ICO_MULTI, true); - private final JLabel lblBlack = buildLabel(SEditorUtil.ICO_BLACK, false); - private final JLabel lblBlue = buildLabel(SEditorUtil.ICO_BLUE, true); - private final JLabel lblGreen = buildLabel(SEditorUtil.ICO_GREEN, false); - private final JLabel lblRed = buildLabel(SEditorUtil.ICO_RED, true); - private final JLabel lblWhite = buildLabel(SEditorUtil.ICO_WHITE, false); - private final JLabel lblColorless = buildLabel(SEditorUtil.ICO_COLORLESS, true); + private final JLabel lblMulti = buildLabel(SEditorUtil.StatTypes.MULTICOLOR, true); + private final JLabel lblBlack = buildLabel(SEditorUtil.StatTypes.BLACK, false); + private final JLabel lblBlue = buildLabel(SEditorUtil.StatTypes.BLUE, true); + private final JLabel lblGreen = buildLabel(SEditorUtil.StatTypes.GREEN, false); + private final JLabel lblRed = buildLabel(SEditorUtil.StatTypes.RED, true); + private final JLabel lblWhite = buildLabel(SEditorUtil.StatTypes.WHITE, false); + private final JLabel lblColorless = buildLabel(SEditorUtil.StatTypes.COLORLESS, true); // Card type labels - private final JLabel lblArtifact = buildLabel(SEditorUtil.ICO_ARTIFACT, true); - private final JLabel lblCreature = buildLabel(SEditorUtil.ICO_CREATURE, false); - private final JLabel lblEnchantment = buildLabel(SEditorUtil.ICO_ENCHANTMENT, true); - private final JLabel lblInstant = buildLabel(SEditorUtil.ICO_INSTANT, false); - private final JLabel lblLand = buildLabel(SEditorUtil.ICO_LAND, true); - private final JLabel lblPlaneswalker = buildLabel(SEditorUtil.ICO_PLANESWALKER, false); - private final JLabel lblSorcery = buildLabel(SEditorUtil.ICO_SORCERY, true); + private final JLabel lblArtifact = buildLabel(SEditorUtil.StatTypes.ARTIFACT, true); + private final JLabel lblCreature = buildLabel(SEditorUtil.StatTypes.CREATURE, false); + private final JLabel lblEnchantment = buildLabel(SEditorUtil.StatTypes.ENCHANTMENT, true); + private final JLabel lblInstant = buildLabel(SEditorUtil.StatTypes.INSTANT, false); + private final JLabel lblLand = buildLabel(SEditorUtil.StatTypes.LAND, true); + private final JLabel lblPlaneswalker = buildLabel(SEditorUtil.StatTypes.PLANESWALKER, false); + private final JLabel lblSorcery = buildLabel(SEditorUtil.StatTypes.SORCERY, true); // CMC labels private final JLabel lblCMC0 = buildLabel( @@ -251,9 +251,9 @@ public enum VStatistics implements IVDoc { //========== Other methods - private JLabel buildLabel(final ImageIcon icon0, final boolean zebra) { + private JLabel buildLabel(ImageIcon icon, boolean zebra) { final JLabel lbl = new FLabel.Builder().text("0") - .icon(icon0).iconScaleAuto(false) + .icon(icon).iconScaleAuto(false) .fontSize(11).build(); if (zebra) { @@ -263,4 +263,8 @@ public enum VStatistics implements IVDoc { return lbl; } + + private JLabel buildLabel(SEditorUtil.StatTypes statType, boolean zebra) { + return buildLabel(statType.img, zebra); + } } diff --git a/src/main/java/forge/gui/framework/EDocID.java b/src/main/java/forge/gui/framework/EDocID.java index a370661c30e..a74d12fa918 100644 --- a/src/main/java/forge/gui/framework/EDocID.java +++ b/src/main/java/forge/gui/framework/EDocID.java @@ -8,7 +8,6 @@ import forge.gui.deckeditor.views.VCardCatalog; import forge.gui.deckeditor.views.VCurrentDeck; import forge.gui.deckeditor.views.VDeckgen; import forge.gui.deckeditor.views.VEditorPreferences; -import forge.gui.deckeditor.views.VFilters; import forge.gui.deckeditor.views.VProbabilities; import forge.gui.deckeditor.views.VStatistics; import forge.gui.home.gauntlet.VSubmenuGauntletBuild; @@ -51,7 +50,6 @@ public enum EDocID { /** */ CARD_DETAIL (VDetail.SINGLETON_INSTANCE), /** */ CARD_ANTES (VAntes.SINGLETON_INSTANCE), /** */ - EDITOR_FILTERS (VFilters.SINGLETON_INSTANCE), /** */ EDITOR_PREFERENCES (VEditorPreferences.SINGLETON_INSTANCE), /** */ EDITOR_ALLDECKS (VAllDecks.SINGLETON_INSTANCE), /** */ EDITOR_STATISTICS (VStatistics.SINGLETON_INSTANCE), /** */ diff --git a/src/main/java/forge/gui/framework/SLayoutIO.java b/src/main/java/forge/gui/framework/SLayoutIO.java index 34b72ff5b9f..9b84c645f1d 100644 --- a/src/main/java/forge/gui/framework/SLayoutIO.java +++ b/src/main/java/forge/gui/framework/SLayoutIO.java @@ -190,7 +190,9 @@ public final class SLayoutIO { } else if (element.getName().getLocalPart().equals("doc")) { event = reader.nextEvent(); - cell.addDoc(EDocID.valueOf(event.asCharacters().getData()).getDoc()); + try { + cell.addDoc(EDocID.valueOf(event.asCharacters().getData()).getDoc()); + } catch (IllegalArgumentException e) { /* ignore; just don't add invalid element */ } } } } diff --git a/src/main/java/forge/gui/home/gauntlet/VSubmenuGauntletBuild.java b/src/main/java/forge/gui/home/gauntlet/VSubmenuGauntletBuild.java index 795894cc9bd..659bbebe7f1 100644 --- a/src/main/java/forge/gui/home/gauntlet/VSubmenuGauntletBuild.java +++ b/src/main/java/forge/gui/home/gauntlet/VSubmenuGauntletBuild.java @@ -1,7 +1,6 @@ package forge.gui.home.gauntlet; import java.awt.Color; -import java.awt.Insets; import javax.swing.ButtonGroup; import javax.swing.ImageIcon; @@ -68,7 +67,7 @@ public enum VSubmenuGauntletBuild implements IVSubmenu { private final JScrollPane scrRight = new FScrollPane(lstRight, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - private final JTextField txfFilename = new FTextField(); + private final JTextField txfFilename = new FTextField.Builder().text(GauntletIO.TXF_PROMPT).build(); private final FLabel lblDesc1 = new FLabel.Builder() .text("Left/right arrows add or remove decks.") @@ -139,16 +138,6 @@ public enum VSubmenuGauntletBuild implements IVSubmenu { grpRadios.add(radColorDecks); grpRadios.add(radThemeDecks); - // Text areas - txfFilename.setText(GauntletIO.TXF_PROMPT); - txfFilename.setMargin(new Insets(5, 5, 5, 5)); - txfFilename.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2)); - txfFilename.setOpaque(true); - txfFilename.setEditable(true); - txfFilename.setFocusable(true); - txfFilename.setOpaque(true); - txfFilename.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2)); - // File handling panel final FLabel lblFilename = new FLabel.Builder() .text("Gauntlet Name:").fontSize(14).build(); diff --git a/src/main/java/forge/gui/home/quest/CSubmenuQuestData.java b/src/main/java/forge/gui/home/quest/CSubmenuQuestData.java index f25ddf46295..7cac8a8ec95 100644 --- a/src/main/java/forge/gui/home/quest/CSubmenuQuestData.java +++ b/src/main/java/forge/gui/home/quest/CSubmenuQuestData.java @@ -61,11 +61,11 @@ public enum CSubmenuQuestData implements ICDoc { new Command() { @Override public void execute() { newQuest(); } }); view.getBtnCustomFormat().setCommand(new Command() { @Override public void execute() { - new DialogCustomFormat(customFormatCodes); + new DialogChooseSets(customFormatCodes, null); } }); view.getBtnPrizeCustomFormat().setCommand(new Command() { @Override public void execute() { - new DialogCustomFormat(customPrizeFormatCodes); + new DialogChooseSets(customPrizeFormatCodes, null); } }); } diff --git a/src/main/java/forge/gui/home/quest/DialogCustomFormat.java b/src/main/java/forge/gui/home/quest/DialogChooseSets.java similarity index 90% rename from src/main/java/forge/gui/home/quest/DialogCustomFormat.java rename to src/main/java/forge/gui/home/quest/DialogChooseSets.java index 259ca095dcc..fbce6fc3ce9 100644 --- a/src/main/java/forge/gui/home/quest/DialogCustomFormat.java +++ b/src/main/java/forge/gui/home/quest/DialogChooseSets.java @@ -1,150 +1,158 @@ -package forge.gui.home.quest; - -import java.awt.BorderLayout; -import java.awt.GridLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JDialog; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.WindowConstants; - -import forge.card.CardEdition; -import forge.Singletons; - -/** - * TODO: Write javadoc for this type. - * - */ -public class DialogCustomFormat extends JDialog { - - private static final long serialVersionUID = 3155211532871888181L; - private JScrollPane scrollPane; - private final JButton btnOK = new JButton("OK"); - private final JButton btnCancel = new JButton("Cancel"); - private final JPanel buttonPanel = new JPanel(); - private final List customFormat; - private final List choices = new ArrayList(); - - - /** - * Create the dialog. - * - * @param userFormat - * GameFormatQuest, the user-defined format to update - * - */ - public DialogCustomFormat(List userFormat) { - - customFormat = userFormat; - if (customFormat == null) { - throw new RuntimeException("Null GameFormatQuest in DialogCustomFormat"); - } - - this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - List editions = new ArrayList(); - - for (CardEdition ce : Singletons.getModel().getEditions()) { - if (canChoose(ce.getCode())) { - editions.add(ce); - } - } - - Collections.sort(editions); - Collections.reverse(editions); - - final int numEditions = editions.size(); - final int columns = 3; - final int rows = numEditions / columns + (numEditions % columns == 0 ? 0 : 1); - - - int getIdx = 0; - - JPanel p = new JPanel(); - p.setSize(600, 400); - p.setLayout(new GridLayout(rows, columns, 10, 0)); - - for (int row = 0; row < rows; row++) { - for (int col = 0; col < columns; col++) { - getIdx = row + (col * rows); - JCheckBox box; - if (getIdx < numEditions) { - CardEdition edition = getIdx < numEditions ? editions.get(getIdx) : null; - box = new JCheckBox(edition.getName()); - box.setName(edition.getCode()); - box.setSelected(customFormat.contains(edition.getCode())); - choices.add(box); - } else { - box = new JCheckBox(); - box.setEnabled(false); - } - - p.add(box); - } - } - scrollPane = new JScrollPane(p); - - getContentPane().add(scrollPane, BorderLayout.CENTER); - btnOK.addActionListener(new ActionListener() { - @Override - public void actionPerformed(final ActionEvent arg0) { - updateCustomFormat(); - dispose(); - } - }); - buttonPanel.add(btnOK, BorderLayout.WEST); - btnCancel.addActionListener(new ActionListener() { - @Override - public void actionPerformed(final ActionEvent arg0) { - dispose(); - } - }); - buttonPanel.add(btnCancel, BorderLayout.EAST); - getContentPane().add(buttonPanel, BorderLayout.SOUTH); - - this.setSize(600, 450); - this.setLocationRelativeTo(null); - this.setTitle("Choose sets for custom format:"); - this.setVisible(true); - - } - - /** - * Make some sets unselectable (currently only Alpha and Beta). - * Note that these sets can still be (theoretically) unlocked - * later, for an exorbitant price. There'd be nothing to be - * gained from allowing these initially (Unlimited already covers - * their cardbase), and a lot to be lost (namely, easy early access - * to extremely expensive cards...) --BBU - * - * @param setCode - * String, set code - * @return boolean, this set can be selected. - * - */ - private boolean canChoose(final String setCode) { - if (setCode == null) { - return true; - } - return !"LEA".equals(setCode) && !"LEB".equals(setCode) - && !"MBP".equals(setCode) && !"VAN".equals(setCode) - && !"ARC".equals(setCode) && !"PC2".equals(setCode); - } - - /** - * Update the custom format in accordance with the selections. - */ - void updateCustomFormat() { - customFormat.clear(); - for (JCheckBox box : choices) { - if (box.isSelected()) { - customFormat.add(box.getName()); - } - } - } -} +package forge.gui.home.quest; + +import java.awt.BorderLayout; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.WindowConstants; + +import forge.card.CardEdition; +import forge.Singletons; + +/** + * TODO: Write javadoc for this type. + * + */ +public class DialogChooseSets extends JDialog { + + private static final long serialVersionUID = 3155211532871888181L; + private JScrollPane scrollPane; + private final JButton btnOK = new JButton("OK"); + private final JButton btnCancel = new JButton("Cancel"); + private final JPanel buttonPanel = new JPanel(); + private final List customFormat; + private final Runnable onOk; + private final List choices = new ArrayList(); + + + /** + * Create the dialog. + * + * @param userFormat + * GameFormatQuest, the user-defined format to update + * + */ + public DialogChooseSets(List userFormat, Runnable onOk) { + + customFormat = userFormat; + this.onOk = onOk; + + if (customFormat == null) { + throw new RuntimeException("Null GameFormatQuest in DialogCustomFormat"); + } + + this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + List editions = new ArrayList(); + + for (CardEdition ce : Singletons.getModel().getEditions()) { + if (canChoose(ce.getCode())) { + editions.add(ce); + } + } + + Collections.sort(editions); + Collections.reverse(editions); + + final int numEditions = editions.size(); + final int columns = 3; + final int rows = numEditions / columns + (numEditions % columns == 0 ? 0 : 1); + + + int getIdx = 0; + + JPanel p = new JPanel(); + p.setLayout(new GridLayout(rows, columns, 10, 0)); + + for (int row = 0; row < rows; row++) { + for (int col = 0; col < columns; col++) { + getIdx = row + (col * rows); + JCheckBox box; + if (getIdx < numEditions) { + CardEdition edition = getIdx < numEditions ? editions.get(getIdx) : null; + box = new JCheckBox(String.format("%s (%s)", edition.getName(), edition.getCode())); + box.setName(edition.getCode()); + box.setSelected(customFormat.contains(edition.getCode())); + choices.add(box); + } else { + box = new JCheckBox(); + box.setEnabled(false); + } + + p.add(box); + } + } + scrollPane = new JScrollPane(p); + + getContentPane().add(scrollPane, BorderLayout.CENTER); + btnOK.addActionListener(new ActionListener() { + @Override + public void actionPerformed(final ActionEvent arg0) { + updateCustomFormat(); + dispose(); + } + }); + buttonPanel.add(btnOK, BorderLayout.WEST); + getRootPane().setDefaultButton(btnOK); + + btnCancel.addActionListener(new ActionListener() { + @Override + public void actionPerformed(final ActionEvent arg0) { + dispose(); + } + }); + buttonPanel.add(btnCancel, BorderLayout.EAST); + getContentPane().add(buttonPanel, BorderLayout.SOUTH); + + this.setSize(600, 450); + this.setLocationRelativeTo(null); + this.setTitle("Choose sets"); + this.setVisible(true); + + } + + /** + * Make some sets unselectable (currently only Alpha and Beta). + * Note that these sets can still be (theoretically) unlocked + * later, for an exorbitant price. There'd be nothing to be + * gained from allowing these initially (Unlimited already covers + * their cardbase), and a lot to be lost (namely, easy early access + * to extremely expensive cards...) --BBU + * + * @param setCode + * String, set code + * @return boolean, this set can be selected. + * + */ + private boolean canChoose(final String setCode) { + if (setCode == null) { + return true; + } + return !"LEA".equals(setCode) && !"LEB".equals(setCode) + && !"MBP".equals(setCode) && !"VAN".equals(setCode) + && !"ARC".equals(setCode) && !"PC2".equals(setCode); + } + + /** + * Update the custom format in accordance with the selections. + */ + void updateCustomFormat() { + customFormat.clear(); + for (JCheckBox box : choices) { + if (box.isSelected()) { + customFormat.add(box.getName()); + } + } + + if (null != onOk) { + onOk.run(); + } + } +} diff --git a/src/main/java/forge/gui/toolbox/FLabel.java b/src/main/java/forge/gui/toolbox/FLabel.java index 70720767c9d..6a752fdbf6c 100644 --- a/src/main/java/forge/gui/toolbox/FLabel.java +++ b/src/main/java/forge/gui/toolbox/FLabel.java @@ -51,7 +51,7 @@ public class FLabel extends JLabel implements ILocalRepaint { * new FLabel.Builder().method1(foo).method2(bar).method3(baz)... *
and then call build() to make the label (don't forget that part). */ - public static class Builder extends FLabel { + public static class Builder { //========== Default values for FLabel are set here. private double bldIconScaleFactor = 0.8; private int bldFontStyle = Font.PLAIN; @@ -61,10 +61,12 @@ public class FLabel extends JLabel implements ILocalRepaint { private Point bldIconInsets = new Point(0, 0); private boolean bldSelectable = false; + private boolean bldSelected = false; private boolean bldHoverable = false; private boolean bldOpaque = false; private boolean bldIconInBackground = false; private boolean bldIconScaleAuto = true; + private boolean reactOnMouseDown = false; private String bldText, bldToolTip; private ImageIcon bldIcon; @@ -103,6 +105,14 @@ public class FLabel extends JLabel implements ILocalRepaint { /**@param b0   boolean * @return {@link forge.gui.toolbox.Builder} */ public Builder selectable(final boolean b0) { this.bldSelectable = b0; return this; } + + /**@param b0   boolean + * @return {@link forge.gui.toolbox.Builder} */ + public Builder selected(final boolean b0) { this.bldSelected = b0; return this; } + + /**@param b0   boolean that controls when the label responds to mouse events + * @return {@link forge.gui.toolbox.Builder} */ + public Builder reactOnMouseDown(final boolean b0) { this.reactOnMouseDown = b0; return this; } /**@param c0   {@link forge.Command} to execute if clicked * @return {@link forge.gui.toolbox.Builder} */ @@ -158,6 +168,7 @@ public class FLabel extends JLabel implements ILocalRepaint { this.iconInBackground = b0.bldIconInBackground; this.iconScaleAuto = b0.bldIconScaleAuto; this.selectable = b0.bldSelectable; + this.selected = b0.bldSelected; this.iconAlignX = b0.bldIconAlignX; this.iconInsets = b0.bldIconInsets; @@ -165,8 +176,8 @@ public class FLabel extends JLabel implements ILocalRepaint { this.setFontSize(b0.bldFontSize); this.setIconAlpha(b0.bldIconAlpha); this.setCommand(b0.bldCmd); + this.setReactOnMouseDown(b0.reactOnMouseDown); this.setFontAlign(b0.bldFontAlign); - this.setText(b0.bldText); this.setToolTipText(b0.bldToolTip); this.setHoverable(b0.bldHoverable); @@ -176,8 +187,6 @@ public class FLabel extends JLabel implements ILocalRepaint { // Non-custom display properties this.setForeground(clrText); this.setBackground(clrInactive); - this.setVerticalTextPosition(SwingConstants.CENTER); - this.setVerticalAlignment(SwingConstants.CENTER); // Resize adapter this.removeComponentListener(cadResize); @@ -202,7 +211,7 @@ public class FLabel extends JLabel implements ILocalRepaint { private int fontStyle, iconAlignX; private int iw, ih; private boolean selectable, selected, hoverable, hovered, opaque, - iconInBackground, iconScaleAuto; + iconInBackground, iconScaleAuto, reactOnMouseDown; private Point iconInsets; // Various variables used in image rendering. @@ -246,19 +255,35 @@ public class FLabel extends JLabel implements ILocalRepaint { private final MouseAdapter madEvents = new MouseAdapter() { @Override public void mouseEntered(final MouseEvent e) { - hovered = true; repaintSelf(); + if (hoverable) { + hovered = true; repaintSelf(); + } } @Override public void mouseExited(final MouseEvent e) { - hovered = false; repaintSelf(); + if (hoverable) { + hovered = false; repaintSelf(); + } } + + private void _doMouseAction() { + if (selectable) { setSelected(!selected); } + if (cmdClick != null && FLabel.this.isEnabled()) { cmdClick.execute(); } + } + + @Override + public void mousePressed(MouseEvent e) { + if (reactOnMouseDown) { + _doMouseAction(); + } + } + @Override public void mouseClicked(final MouseEvent e) { - if (cmdClick != null && FLabel.this.isEnabled()) { cmdClick.execute(); } - if (!selectable) { return; } - if (selected) { setSelected(false); } - else { setSelected(true); } + if (!reactOnMouseDown) { + _doMouseAction(); + } } }; @@ -278,6 +303,10 @@ public class FLabel extends JLabel implements ILocalRepaint { repaintSelf(); } + public boolean getSelected() { + return this.selected; + } + /** Sets alpha if icon is in background. * @param f0   float */ // NOT public; must be set when label is built. @@ -359,6 +388,10 @@ public class FLabel extends JLabel implements ILocalRepaint { this.cmdClick = c0; } + public void setReactOnMouseDown(boolean b0) { + this.reactOnMouseDown = b0; + } + @Override public void setOpaque(final boolean b0) { // Must be overridden to allow drawing order of background, icon, string diff --git a/src/main/java/forge/gui/toolbox/FSpinner.java b/src/main/java/forge/gui/toolbox/FSpinner.java new file mode 100644 index 00000000000..177dc439820 --- /dev/null +++ b/src/main/java/forge/gui/toolbox/FSpinner.java @@ -0,0 +1,49 @@ +package forge.gui.toolbox; + +import java.awt.Insets; + +import javax.swing.JFormattedTextField; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; +import javax.swing.text.NumberFormatter; + +/** + * A custom instance of JSpinner using Forge skin properties. Only numeric + * integer spinners are implemented, since that's all we've needed so far. + * + */ +@SuppressWarnings("serial") +public class FSpinner extends JSpinner { + public static class Builder { + //========== Default values for FTextField are set here. + private int initialValue = 0; + private int minValue = 0; + private int maxValue = Integer.MAX_VALUE; + private String toolTip; + + public FSpinner build() { return new FSpinner(this); } + + public Builder initialValue(int i0) { initialValue = i0; return this; } + public Builder minValue(int i0) { minValue = i0; return this; } + public Builder maxValue(int i0) { maxValue = i0; return this; } + + public Builder tooltip(String s0) { toolTip = s0; return this; } + } + + private FSpinner(Builder builder) { + this.setOpaque(false); + + this.setModel(new SpinnerNumberModel(builder.initialValue, builder.minValue, builder.maxValue, 1)); + this.setEditor(new JSpinner.NumberEditor(this, "##")); + JFormattedTextField txt = ((JSpinner.NumberEditor)this.getEditor()).getTextField(); + ((NumberFormatter)txt.getFormatter()).setAllowsInvalid(false); + txt.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT)); + txt.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2)); + txt.setCaretColor(FSkin.getColor(FSkin.Colors.CLR_TEXT)); + txt.setMargin(new Insets(5, 5, 5, 5)); + txt.setOpaque(true); + + this.setToolTipText(builder.toolTip); + this.setFocusable(true); + } +} diff --git a/src/main/java/forge/gui/toolbox/FTextField.java b/src/main/java/forge/gui/toolbox/FTextField.java index 1228bd0d554..8d41124a37b 100644 --- a/src/main/java/forge/gui/toolbox/FTextField.java +++ b/src/main/java/forge/gui/toolbox/FTextField.java @@ -1,6 +1,11 @@ package forge.gui.toolbox; +import java.awt.Insets; + import javax.swing.JTextField; +import javax.swing.text.AttributeSet; +import javax.swing.text.BadLocationException; +import javax.swing.text.PlainDocument; /** * A custom instance of JTextArea using Forge skin properties. @@ -8,13 +13,64 @@ import javax.swing.JTextField; */ @SuppressWarnings("serial") public class FTextField extends JTextField { - /** */ - public FTextField() { - super(); + /** + * Uses the Builder pattern to facilitate/encourage inline styling. + * Credit to Effective Java 2 (Joshua Bloch). + * Methods in builder can be chained. To declare: + * new FTextField.Builder().method1(foo).method2(bar).method3(baz)... + *
and then call build() to make the widget (don't forget that part). + */ + public static class Builder { + //========== Default values for FTextField are set here. + private int maxLength = 0; // <=0 indicates no maximum + private boolean readonly = false; + private String text; + private String toolTip; + + public FTextField build() { return new FTextField(this); } + + public Builder maxLength(int i0) { maxLength = i0; return this; } + public Builder readonly(boolean b0) { readonly = b0; return this; } + + public Builder text(String s0) { text = s0; return this; } + public Builder tooltip(String s0) { toolTip = s0; return this; } + } + + private FTextField(Builder builder) { this.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT)); + this.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2)); this.setCaretColor(FSkin.getColor(FSkin.Colors.CLR_TEXT)); - this.setOpaque(false); - this.setFocusable(false); - this.setEditable(false); + this.setMargin(new Insets(5, 5, 5, 5)); + this.setOpaque(true); + + if (0 < builder.maxLength) + { + this.setDocument(new _LengthLimitedDocument(builder.maxLength)); + } + + this.setEditable(!builder.readonly); + this.setText(builder.text); + this.setToolTipText(builder.toolTip); + this.setFocusable(true); + } + + private static class _LengthLimitedDocument extends PlainDocument { + private final int _limit; + + _LengthLimitedDocument(int limit) { _limit = limit; } + + // called each time a character is typed or a string is pasted + @Override + public void insertString(int offset, String s, AttributeSet attributeSet) + throws BadLocationException { + if (_limit <= this.getLength()) { + return; + } + int newLen = this.getLength() + s.length(); + if (_limit < newLen) { + s = s.substring(0, _limit - this.getLength()); + } + super.insertString(offset, s, attributeSet); + } } } diff --git a/src/main/java/forge/quest/QuestController.java b/src/main/java/forge/quest/QuestController.java index 3d70a7615e7..fa519e00eca 100644 --- a/src/main/java/forge/quest/QuestController.java +++ b/src/main/java/forge/quest/QuestController.java @@ -137,6 +137,13 @@ public class QuestController { return (getWorldFormat() == null ? this.questFormat : getWorldFormat()); } + /** + * Gets the custom format for the main world, if any. + */ + public GameFormatQuest getMainFormat() { + return this.questFormat; + } + /** * Gets the current event. * diff --git a/src/main/java/forge/quest/QuestRewardCardChooser.java b/src/main/java/forge/quest/QuestRewardCardChooser.java new file mode 100644 index 00000000000..48334d014b8 --- /dev/null +++ b/src/main/java/forge/quest/QuestRewardCardChooser.java @@ -0,0 +1,237 @@ +package forge.quest; + +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import forge.Singletons; +import forge.item.CardDb; +import forge.item.CardPrinted; +import forge.card.CardRules; +import forge.item.InventoryItem; +import forge.item.ItemPool; + +/** + * Resolves a card chooser InventoryItem into a CardPrinted. + * The initial version includes "duplicate", other type may be added later. + * + */ +public class QuestRewardCardChooser implements InventoryItem { + + /** + * Possible types for this object. + */ + public enum poolType { + /** The player's own cardpool (duplicate card). */ + playerCards, + /** Filtered by a predicate that will be parsed. */ + predicateFilter + } + + private poolType type; + private final String description; + private final Predicate predicates; + + /** + * The constructor. + * The parameter indicates the more specific type. + * @param setType String, the type of the choosable card. + * @param creationParameters String, used to build the predicates and description for the predicateFilter type + */ + public QuestRewardCardChooser(final poolType setType, final String[] creationParameters) { + type = setType; + if (type == poolType.playerCards) { + description = "a duplicate card"; + predicates = null; + } else { + description = buildDescription(creationParameters); + predicates = buildPredicates(creationParameters); + } + } + + private String buildDescription(final String [] input) { + final String defaultDescription = "a card"; + if (input == null || input.length < 1) { + return defaultDescription; + } + + String buildDesc = null; + + for (String s : input) { + if (s.startsWith("desc:") || s.startsWith("Desc:")) { + String[] tmp = s.split(":"); + if (tmp.length > 1) { + buildDesc = new String(tmp[1]); + } else { + buildDesc = new String(); + } + } else if (buildDesc != null) { + if (s.contains(":")) { + return buildDesc; + } else { + buildDesc = buildDesc + " " + s; + } + } + } + + if (buildDesc != null) { + return buildDesc; + } + return defaultDescription; + } + + + private Predicate buildPredicates(final String [] input) { + if (input == null || input.length < 1) { + return null; + } + + Predicate filters = Singletons.getModel().getQuest().getFormat().getFilterPrinted(); + Predicate filterRules = null; + Predicate filterRarity = null; + + for (String s : input) { + if (s.startsWith("sets:") || s.startsWith("Sets:")) { + final String[] tmp = s.split(":"); + if (tmp.length > 1) { + String [] setcodes = tmp[1].split(","); + if (setcodes.length > 0) { + List sets = new ArrayList(); + for (String code : setcodes) { + if (Singletons.getModel().getEditions().contains(code)) { + // System.out.println("Set " + code + " was found!"); + sets.add(code); + } + // else { System.out.println("Unknown set code " + code); } + } + if (sets.size() > 0) { + filters = CardPrinted.Predicates.printedInSets(sets, true); + } + } + } + } else if (s.startsWith("rules:") || s.startsWith("Rules:")) { + final String[] tmp = s.split(":"); + if (tmp.length > 1) { + String [] ruleCodes = tmp[1].split(","); + if (ruleCodes.length > 0) { + for (String rule : ruleCodes) { + final Predicate newRule = BoosterUtils.parseRulesLimitation(rule); + if (newRule != null) { + filterRules = (filterRules == null ? newRule : Predicates.and(filterRules, newRule)); + } + } + } + } + } else if (s.startsWith("rarity:") || s.startsWith("Rarity:")) { + final String[] tmp = s.split(":"); + if (tmp.length > 1) { + String [] rarityCodes = tmp[1].split(","); + if (rarityCodes.length > 0) { + for (String rarity : rarityCodes) { + if (rarity.startsWith("C") || rarity.startsWith("c")) { + filterRarity = (filterRarity == null ? CardPrinted.Predicates.Presets.IS_COMMON : Predicates.or(filterRarity, CardPrinted.Predicates.Presets.IS_COMMON)); + } else if (rarity.startsWith("U") || rarity.startsWith("u")) { + filterRarity = (filterRarity == null ? CardPrinted.Predicates.Presets.IS_UNCOMMON : Predicates.or(filterRarity, CardPrinted.Predicates.Presets.IS_UNCOMMON)); + } else if (rarity.startsWith("R") || rarity.startsWith("r")) { + filterRarity = (filterRarity == null ? CardPrinted.Predicates.Presets.IS_RARE : Predicates.or(filterRarity, CardPrinted.Predicates.Presets.IS_RARE)); + } else if (rarity.startsWith("M") || rarity.startsWith("m")) { + filterRarity = (filterRarity == null ? CardPrinted.Predicates.Presets.IS_MYTHIC_RARE : Predicates.or(filterRarity, CardPrinted.Predicates.Presets.IS_MYTHIC_RARE)); + } + } + } + } + } + } + + if (filterRules != null) { + final Predicate rulesPrinted = Predicates.compose(filterRules, CardPrinted.FN_GET_RULES); + filters = Predicates.and(filters, rulesPrinted); + } + if (filterRarity != null) { + filters = Predicates.and(filters, filterRarity); + } + return filters; + } + + /** + * The name. + * + * @return the name + */ + @Override + public String getName() { + return description; + } + + /** + * A QuestRewardCardChooser ought to always be resolved to an actual card, hence no images. + * + * @return an empty string + */ + @Override + public String getImageFilename() { + return ""; + } + + /** + * The item type. + * + * @return item type + */ + @Override + public String getItemType() { + switch (type) { + case playerCards: + return "duplicate card"; + case predicateFilter: default: + return "chosen card"; + } + } + + /** + * Get type as enum. + * @return enum, item type. + */ + public poolType getType() { + return type; + } + + /** + * Produces a list of options to choose from. + * + * @return a List or null if could not create a list. + */ + public final List getChoices() { + if (type == poolType.playerCards) { + final ItemPool playerCards = Singletons.getModel().getQuest().getAssets().getCardPool(); + if (!playerCards.isEmpty()) { // Maybe a redundant check since it's hard to win a duel without any cards... + + List cardChoices = new ArrayList(); + for (final Map.Entry card : playerCards) { + cardChoices.add(card.getKey()); + } + Collections.sort(cardChoices); + + return Collections.unmodifiableList(cardChoices); + } + + } else if (type == poolType.predicateFilter) { + List cardChoices = new ArrayList(); + + for (final CardPrinted card : Iterables.filter(CardDb.instance().getAllTraditionalCards(), predicates)) { + cardChoices.add(card); + } + Collections.sort(cardChoices); + + return Collections.unmodifiableList(cardChoices); + } else { + throw new RuntimeException("Unknown QuestRewardCardType: " + type); + } + return null; + } +} diff --git a/src/main/java/forge/quest/QuestUtilCards.java b/src/main/java/forge/quest/QuestUtilCards.java index 4681b3f1789..f75ff7ba079 100644 --- a/src/main/java/forge/quest/QuestUtilCards.java +++ b/src/main/java/forge/quest/QuestUtilCards.java @@ -576,20 +576,10 @@ public final class QuestUtilCards { this.qa.getNewCardList().clear(); } - /** - * Gets the fn new compare. - * - * @return the fnNewCompare - */ public Function, Comparable> getFnNewCompare() { return this.fnNewCompare; } - /** - * Gets the fn new get. - * - * @return the fnNewGet - */ public Function, Object> getFnNewGet() { return this.fnNewGet; } @@ -600,7 +590,8 @@ public final class QuestUtilCards { // deck editors // Maybe we should consider doing so later /** The fn new compare. */ - private final Function, Comparable> fnNewCompare = new Function, Comparable>() { + private final Function, Comparable> fnNewCompare = + new Function, Comparable>() { @Override public Comparable apply(final Entry from) { return QuestUtilCards.this.qa.getNewCardList().contains(from.getKey()) ? Integer.valueOf(1) : Integer @@ -609,10 +600,38 @@ public final class QuestUtilCards { }; /** The fn new get. */ - private final Function, Object> fnNewGet = new Function, Object>() { + private final Function, Object> fnNewGet = + new Function, Object>() { @Override public Object apply(final Entry from) { return QuestUtilCards.this.qa.getNewCardList().contains(from.getKey()) ? "NEW" : ""; } }; + + public Function, Comparable> getFnOwnedCompare() { + return this.fnOwnedCompare; + } + + public Function, Object> getFnOwnedGet() { + return this.fnOwnedGet; + } + + // These functions provide a way to sort and compare cards in the spell shop according to how many are already owned + private final Function, Comparable> fnOwnedCompare = + new Function, Comparable>() { + @Override + public Comparable apply(final Entry from) { + InventoryItem i = from.getKey(); + return i instanceof CardPrinted ? QuestUtilCards.this.qa.getCardPool().count((CardPrinted)i) : null; + } + }; + + private final Function, Object> fnOwnedGet = + new Function, Object>() { + @Override + public Object apply(final Entry from) { + InventoryItem i = from.getKey(); + return i instanceof CardPrinted ? QuestUtilCards.this.qa.getCardPool().count((CardPrinted)i) : null; + } + }; } diff --git a/src/main/java/forge/util/Pair.java b/src/main/java/forge/util/Pair.java new file mode 100644 index 00000000000..a2a69e6334c --- /dev/null +++ b/src/main/java/forge/util/Pair.java @@ -0,0 +1,11 @@ +package forge.util; + +public class Pair { + public final T a; + public final V b; + + public Pair(T a, V b) { + this.a = a; + this.b = b; + } +} diff --git a/src/main/java/forge/util/TextUtil.java b/src/main/java/forge/util/TextUtil.java index f734453e717..99795041f94 100644 --- a/src/main/java/forge/util/TextUtil.java +++ b/src/main/java/forge/util/TextUtil.java @@ -2,6 +2,7 @@ package forge.util; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Map.Entry; @@ -77,5 +78,13 @@ public class TextUtil { return result.toArray(ArrayUtils.EMPTY_STRING_ARRAY); } - + + /** + * Converts an enum value to a printable label but upcasing the first letter + * and lcasing all subsequent letters + */ + public static String enumToLabel(Enum val) { + return val.toString().substring(0, 1).toUpperCase(Locale.ENGLISH) + + val.toString().substring(1).toLowerCase(Locale.ENGLISH); + } } diff --git a/src/main/java/forge/view/FView.java b/src/main/java/forge/view/FView.java index 68147a21fdd..d4c7d5d16fc 100644 --- a/src/main/java/forge/view/FView.java +++ b/src/main/java/forge/view/FView.java @@ -35,8 +35,6 @@ public enum FView { /** */ SINGLETON_INSTANCE; - /** */ - public static final Integer TARGETING_LAYER = JLayeredPane.MODAL_LAYER - 1; private final List allCells = new ArrayList(); private SplashFrame frmSplash; @@ -84,8 +82,7 @@ public enum FView { // Note: when adding new panels here, keep in mind that the layered pane // has a null layout, so new components will be W0 x H0 pixels - gotcha! // FControl has a method called "sizeComponents" which will fix this. - lpnDocument.add(TargetingOverlay.SINGLETON_INSTANCE.getPanel(), TARGETING_LAYER); - + lpnDocument.add(TargetingOverlay.SINGLETON_INSTANCE.getPanel(), JLayeredPane.MODAL_LAYER); pnlInsets.add(pnlContent, BorderLayout.CENTER); pnlInsets.setBackgroundTexture(FSkin.getIcon(FSkin.Backgrounds.BG_TEXTURE)); pnlInsets.setCornerDiameter(0);