diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/DeckImport.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/DeckImport.java
index c295a55402a..a9d97818409 100644
--- a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/DeckImport.java
+++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/DeckImport.java
@@ -26,12 +26,14 @@ import javax.swing.BorderFactory;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
-import forge.deck.Deck;
-import forge.deck.DeckBase;
-import forge.deck.DeckImportController;
-import forge.deck.DeckRecognizer;
+import forge.StaticData;
+import forge.card.CardEdition;
+import forge.deck.*;
import forge.deck.DeckRecognizer.TokenType;
+import forge.game.GameFormat;
+import forge.game.GameType;
import forge.item.InventoryItem;
+import forge.model.FModel;
import forge.screens.deckeditor.controllers.ACEditorBase;
import forge.toolbox.FButton;
import forge.toolbox.FCheckBox;
@@ -45,7 +47,7 @@ import forge.util.Localizer;
import forge.view.FDialog;
/**
- *
+ *
* Dialog for quick import of decks.
*
* @param
@@ -56,26 +58,56 @@ public class DeckImport ex
private final FTextArea txtInput = new FTextArea();
private static final String STYLESHEET = "";
+ // TODO: Add localisation support
private static final String HTML_WELCOME_TEXT = ""
+ + ""
+ DeckImport.STYLESHEET
- + "You'll see recognized cards here
"
- + "Legend
"
- + ""
- + "- Recognized cards will be shown in green. These cards will be auto-imported into a new deck
"
- + "- Lines which seem to be cards but are either misspelled or unsupported by Forge, are shown in dark-red
"
- + "" + "
"
- + "Choosing source
"
- + "In most cases when you paste from clipboard a carefully selected area of a webpage, it works perfectly.
"
- + "Sometimes to filter out unneeded data you may have to export deck in MTGO format, and paste here downloaded file contents.
"
- + "Sideboard recognition is supported. Make sure that the sideboard cards are listed after a line that contains the word 'Sideboard'
"
+ + ""
+ + ""
+ + "How to use the Deck Importer
" +
+ "Quick Instructions:\n" +
+ "Using the Deck Importer is very simple: " +
+ "just type or paste the names of the cards you want (one per line in the Card List), " +
+ "and the Importer will automatically create the Decklist with M:TG cards in Forge." +
+ "You could also specify how many copies of each card you want (default: 1), " +
+ "and their corresponding Edition.\nIf No Edition is specified, the card print will be " +
+ "selected automatically according to the Card Art Preference option in Game Settings.\n\n" +
+ "For example: \"4 Power Sink TMP\" will import:" +
+ "
4 copies of Power Sink from Tempest.
" +
+ "Each line in the list will be processed on-the-fly, and rendered in the Decklist with the following " +
+ "color-codes:" +
+ "" +
+ "- Card Recognized: Successful match in the database.
" +
+ "- Card Not Found, or Not Supported yet in Forge.
" +
+ "-
" +
+ "
" +
+ "Additional Options:" +
+ "
" +
+ "- Deck Name: you can specify a name for your deck . Just type " +
+ "
Name: <NAME OF YOUR DECK> in the Card List; " +
+ "- Card types: you can organise your list by types, e.g. " +
+ "
Creature, Instant, Land, Sorcery; " +
+ "- Deck Section: Similarly, you can organise your list by Deck Sections, " +
+ "e.g.
Main, Sideboard; " +
+ "- Collector Number: You can identify a specific Card Print by including its CollNr., " +
+ "e.g.
20 Island M21 265 " +
+ "
" +
+ "Deck Formats:" +
+ "Card Lists in the following formats are supported : MTG Arena (.MTGA); " +
+ "MTG Goldfish (.MTGO); TappedOut; DeckStats.net; .dec files.
"
+ + ""
+ "";
private final FHtmlViewer htmlOutput = new FHtmlViewer(DeckImport.HTML_WELCOME_TEXT);
@@ -83,30 +115,49 @@ public class DeckImport ex
private final FScrollPane scrollOutput = new FScrollPane(this.htmlOutput, false);
private final FLabel summaryMain = new FLabel.Builder().text(Localizer.getInstance().getMessage("lblImportedDeckSummay")).build();
private final FLabel summarySide = new FLabel.Builder().text(Localizer.getInstance().getMessage("lblSideboardSummayLine")).build();
- private final FButton cmdAccept = new FButton(Localizer.getInstance().getMessage("lblImportDeck"));
private final FButton cmdCancel = new FButton(Localizer.getInstance().getMessage("lblCancel"));
- private final FCheckBox newEditionCheck = new FCheckBox(Localizer.getInstance().getMessage("lblImportLatestVersionCard"), true);
- private final FCheckBox dateTimeCheck = new FCheckBox(Localizer.getInstance().getMessage("lblUseOnlySetsReleasedBefore"), false);
- private final FCheckBox onlyCoreExpCheck = new FCheckBox(Localizer.getInstance().getMessage("lblUseOnlyCoreAndExpansionSets"), true);
- private final FComboBox monthDropdown = new FComboBox<>(); //don't need wrappers since skin can't change while this dialog is open
+ private FButton cmdAccept; // Not initialised as label will be adaptive.
+ private final FCheckBox dateTimeCheck = new FCheckBox(Localizer.getInstance().getMessage("lblUseOnlySetsReleasedBefore"), false);
+ private final FCheckBox replaceDeckCheckbox = new FCheckBox(Localizer.getInstance().getMessage("lblReplaceDeck"), false);
+ private final DeckFormat deckFormat;
+
+ //don't need wrappers since skin can't change while this dialog is open
+ private final FComboBox monthDropdown = new FComboBox<>();
private final FComboBox yearDropdown = new FComboBox<>();
private final DeckImportController controller;
private final ACEditorBase host;
+ private final String IMPORT_CARDS_CMD_LABEL = Localizer.getInstance().getMessage("lblImportCardsCmd");
+ private final String IMPORT_DECK_CMD_LABEL = Localizer.getInstance().getMessage("lblImportDeckCmd");
+ private final String REPLACE_CARDS_CMD_LABEL = Localizer.getInstance().getMessage("lblReplaceCardsCmd");
+
+
+ public DeckImport(final ACEditorBase g) {
+ boolean currentDeckIsNotEmpty = !(g.getDeckController().isEmpty());
+ DeckFormat currentDeckFormat = g.getGameType().getDeckFormat();
+ this.deckFormat = currentDeckFormat;
+ GameType currentGameType = g.getGameType();
+ // get the game format with the same name of current game type (if any)
+ GameFormat currentGameFormat = FModel.getFormats().get(currentGameType.name());
+ if (currentGameFormat == null)
+ currentGameFormat = FModel.getFormats().get("Vintage"); // default for constructed
+ List allowedSetCodes = currentGameFormat.getAllowedSetCodes();
+ this.controller = new DeckImportController(dateTimeCheck, monthDropdown, yearDropdown,
+ currentDeckIsNotEmpty, allowedSetCodes, currentDeckFormat);
+ String cmdAcceptLabel = currentDeckIsNotEmpty ? IMPORT_CARDS_CMD_LABEL : IMPORT_DECK_CMD_LABEL;
+ this.cmdAccept = new FButton(cmdAcceptLabel);
- public DeckImport(final ACEditorBase g, final boolean allowCardsFromAllSets) {
- this.controller = new DeckImportController(!g.getDeckController().isEmpty(),
- newEditionCheck, dateTimeCheck, onlyCoreExpCheck, monthDropdown, yearDropdown);
this.host = g;
- final int wWidth = 700;
- final int wHeight = 600;
+ final int wWidth = 900;
+ final int wHeight = 900;
this.setPreferredSize(new java.awt.Dimension(wWidth, wHeight));
this.setSize(wWidth, wHeight);
- this.setTitle(Localizer.getInstance().getMessage("lblDeckImporter"));
+ String gameTypeName = String.format(" %s", currentGameType.name());
+ this.setTitle(Localizer.getInstance().getMessage("lblDeckImporter") + gameTypeName);
txtInput.setFocusable(true);
txtInput.setEditable(true);
@@ -118,19 +169,21 @@ public class DeckImport ex
this.scrollOutput.setViewportBorder(BorderFactory.createLoweredBevelBorder());
this.add(this.scrollInput, "cell 0 0, w 50%, growy, pushy");
- this.add(this.newEditionCheck, "cell 0 1, w 50%, ax c");
this.add(this.dateTimeCheck, "cell 0 2, w 50%, ax c");
this.add(monthDropdown, "cell 0 3, w 20%, ax left, split 2, pad 0 4 0 0");
this.add(yearDropdown, "w 15%");
- this.onlyCoreExpCheck.setSelected(!allowCardsFromAllSets);
- this.add(this.onlyCoreExpCheck, "cell 0 4, w 50%, ax c");
-
this.add(this.scrollOutput, "cell 1 0, w 50%, growy, pushy");
this.add(this.summaryMain, "cell 1 1, label");
this.add(this.summarySide, "cell 1 2, label");
+ if (currentDeckIsNotEmpty){
+ // Disabled Default behaviour to replace current deck: bulk import cards into the existing deck!
+ //this.replaceDeckCheckbox.setSelected(currentDeckIsNotEmpty);
+ this.add(this.replaceDeckCheckbox, "cell 1 3, align r, ax r");
+ }
+
this.add(this.cmdAccept, "cell 1 4, split 2, w 150, align r, h 26");
this.add(this.cmdCancel, "w 150, h 26");
@@ -145,16 +198,27 @@ public class DeckImport ex
@SuppressWarnings("unchecked")
@Override
public void actionPerformed(final ActionEvent e) {
- final Deck deck = controller.accept();
+ String currentDeckName = g.getDeckController().getModelName();
+ final Deck deck = controller.accept(currentDeckName);
if (deck == null) { return; }
+ // If the soon-to-import card list hasn't got any name specified in the list
+ // we set it to the current one (if any) or set a new one.
+ // In this way, if this deck will replace the current one, the name will be kept the same!
+ if (!deck.hasName()){
+ if (currentDeckName.equals(""))
+ deck.setName("New Deck"); // TODO: try to generate a deck name?
+ else
+ deck.setName(currentDeckName);
+ }
- DeckImport.this.host.getDeckController().loadDeck(deck);
+ DeckImport.this.host.getDeckController().loadDeck(deck, controller.getReplacingDeck());
DeckImport.this.processWindowEvent(new WindowEvent(DeckImport.this, WindowEvent.WINDOW_CLOSING));
}
});
final ActionListener updateDateCheck = new ActionListener() {
- @Override public void actionPerformed(final ActionEvent e) {
+ @Override
+ public void actionPerformed(final ActionEvent e) {
final boolean isSel = dateTimeCheck.isSelected();
monthDropdown.setEnabled(isSel);
yearDropdown.setEnabled(isSel);
@@ -169,14 +233,23 @@ public class DeckImport ex
}
};
- this.newEditionCheck.addActionListener(reparse);
- this.onlyCoreExpCheck.addActionListener(reparse);
+ final ActionListener toggleDeckReplace = new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) { toggleDeckReplaceOption(); }
+ };
+
this.yearDropdown.addActionListener(reparse);
this.monthDropdown.addActionListener(reparse);
updateDateCheck.actionPerformed(null); // update actual state
this.txtInput.getDocument().addDocumentListener(new OnChangeTextUpdate());
this.cmdAccept.setEnabled(false);
+
+
+ if (currentDeckIsNotEmpty){
+ this.replaceDeckCheckbox.setSelected(false);
+ this.replaceDeckCheckbox.addActionListener(toggleDeckReplace);
+ }
}
/**
@@ -208,11 +281,17 @@ public class DeckImport ex
updateSummaries(tokens);
}
+ private void toggleDeckReplaceOption(){
+ boolean replaceDeckStatus = this.replaceDeckCheckbox.isSelected();
+ this.controller.setReplacingDeck(replaceDeckStatus);
+ String cmdAcceptLabel = replaceDeckStatus ? this.REPLACE_CARDS_CMD_LABEL : this.IMPORT_CARDS_CMD_LABEL;
+ this.cmdAccept.setText(cmdAcceptLabel);
+ }
+
private void displayTokens(final List tokens) {
- if (tokens.isEmpty()) {
+ if (tokens.isEmpty() || hasOnlyComment(tokens)) {
htmlOutput.setText(HTML_WELCOME_TEXT);
- }
- else {
+ } else {
final StringBuilder sbOut = new StringBuilder("");
sbOut.append(DeckImport.STYLESHEET);
for (final DeckRecognizer.Token t : tokens) {
@@ -223,6 +302,14 @@ public class DeckImport ex
}
}
+ private boolean hasOnlyComment(final List tokens) {
+ for (DeckRecognizer.Token token : tokens) {
+ if (token.getType() != TokenType.Comment && token.getType() != TokenType.UnknownText)
+ return false;
+ }
+ return true;
+ }
+
private void updateSummaries(final List tokens) {
final int[] cardsOk = new int[2];
final int[] cardsUnknown = new int[2];
@@ -234,7 +321,7 @@ public class DeckImport ex
if (t.getType() == TokenType.UnknownCard) {
cardsUnknown[idx] += t.getNumber();
}
- if ((t.getType() == TokenType.SectionName) && t.getText().toLowerCase().contains("side")) {
+ if ((t.getType() == TokenType.DeckSectionName) && t.getText().toLowerCase().contains("side")) {
idx = 1;
}
}
@@ -243,20 +330,57 @@ public class DeckImport ex
cmdAccept.setEnabled(cardsOk[0] > 0);
}
- private static String makeHtmlViewOfToken(final DeckRecognizer.Token token) {
+// private static String makeHtmlViewOfToken(final DeckRecognizer.Token token) {
+// switch (token.getType()) {
+// case KnownCard:
+// return String.format("%s * %s [%s] %s
", token.getNumber(), token.getCard()
+// .getName(), token.getCard().getEdition(), token.getCard().isFoil() ? "foil" : "");
+// case UnknownCard:
+// return String.format("%s * %s
", token.getNumber(), token.getText());
+// case SectionName:
+// return String.format("%s
", token.getText());
+// case UnknownText:
+// case Comment:
+// return String.format("", token.getText());
+// default:
+// return "";
+// }
+// }
+
+ private String makeHtmlViewOfToken(final DeckRecognizer.Token token) {
switch (token.getType()) {
- case KnownCard:
- return String.format("%s * %s [%s] %s
", token.getNumber(), token.getCard()
- .getName(), token.getCard().getEdition(), token.getCard().isFoil() ? "foil" : "");
- case UnknownCard:
- return String.format("%s * %s
", token.getNumber(), token.getText());
- case SectionName:
- return String.format("%s
", token.getText());
- case UnknownText:
- case Comment:
- return String.format("", token.getText());
- default:
- return "";
+ case KnownCard:
+ CardEdition edition = StaticData.instance().getEditions().get(token.getCard().getEdition());
+ String editionName;
+ if (edition == null)
+ editionName = "Unknown Edition";
+ else
+ editionName = edition.getName();
+ // TODO: String Padding for alignment
+ return String.format("%s x %s from %s (%s) %s
",
+ token.getNumber(), token.getCard().getName(),
+ editionName, token.getCard().getEdition(),
+ token.getCard().isFoil() ? "foil" : "");
+ case UnknownCard:
+ return String.format("%s x %s (%s)
",
+ token.getNumber(), token.getText(),
+ Localizer.getInstance().getMessage("lblUnknownCard"));
+ case IllegalCard:
+ return String.format("%s x %s (%s %s)
",
+ token.getNumber(), token.getText(),
+ Localizer.getInstance().getMessage("lblIllegalCard"),
+ this.deckFormat.name());
+ case DeckSectionName:
+ return String.format("%s
", token.getText());
+ case CardType:
+ return String.format("%s
", token.getText());
+ case DeckName:
+ return String.format("Deck Name: %s
", token.getText());
+ case UnknownText:
+ case Comment:
+ default:
+ return "";
+ // return String.format("", token.getText());
}
}
}