diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorWinstonProcess.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorWinstonProcess.java index 2e7fd713ec3..71623f5d377 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorWinstonProcess.java +++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorWinstonProcess.java @@ -273,6 +273,7 @@ public class CEditorWinstonProcess extends ACEditorBase { * @see forge.gui.deckeditor.ACEditorBase#show(forge.Command) */ @Override + @SuppressWarnings("serial") public void update() { this.getCatalogManager().setup(ItemManagerConfig.DRAFT_PACK); this.getDeckManager().setup(ItemManagerConfig.DRAFT_POOL); diff --git a/forge-gui-mobile/src/forge/deck/FDeckEditor.java b/forge-gui-mobile/src/forge/deck/FDeckEditor.java index 0fbfdbcf324..231c093a5ff 100644 --- a/forge-gui-mobile/src/forge/deck/FDeckEditor.java +++ b/forge-gui-mobile/src/forge/deck/FDeckEditor.java @@ -1,9 +1,14 @@ package forge.deck; +import org.apache.commons.lang3.StringUtils; + +import com.google.common.base.Supplier; + import forge.assets.FImage; import forge.assets.FSkin; import forge.assets.FSkinImage; import forge.assets.FTextureRegionImage; +import forge.deck.io.DeckPreferences; import forge.item.PaperCard; import forge.itemmanager.CardManager; import forge.itemmanager.ItemManagerConfig; @@ -13,19 +18,73 @@ import forge.screens.TabPageScreen; import forge.toolbox.FEvent; import forge.toolbox.FEvent.FEventHandler; import forge.toolbox.FLabel; +import forge.toolbox.FOptionPane; import forge.toolbox.FTextField; +import forge.util.Callback; import forge.util.ItemPool; import forge.util.Utils; +import forge.util.storage.IStorage; public class FDeckEditor extends TabPageScreen { public enum EditorType { - Constructed, - Draft, - Sealed, - Commander, - Archenemy, - Planechase, - Vanguard, + Constructed(new DeckController(FModel.getDecks().getConstructed(), new Supplier() { + @Override + public Deck get() { + return new Deck(); + } + })), + Draft(new DeckController(FModel.getDecks().getDraft(), new Supplier() { + @Override + public DeckGroup get() { + return new DeckGroup(""); + } + })), + Sealed(new DeckController(FModel.getDecks().getSealed(), new Supplier() { + @Override + public DeckGroup get() { + return new DeckGroup(""); + } + })), + Winston(new DeckController(FModel.getDecks().getWinston(), new Supplier() { + @Override + public DeckGroup get() { + return new DeckGroup(""); + } + })), + Commander(new DeckController(FModel.getDecks().getCommander(), new Supplier() { + @Override + public Deck get() { + return new Deck(); + } + })), + Archenemy(new DeckController(FModel.getDecks().getScheme(), new Supplier() { + @Override + public Deck get() { + return new Deck(); + } + })), + Planechase(new DeckController(FModel.getDecks().getPlane(), new Supplier() { + @Override + public Deck get() { + return new Deck(); + } + })), + Vanguard(new DeckController(FModel.getDecks().getConstructed(), new Supplier() { + @Override + public Deck get() { + return new Deck(); + } + })); + + private final DeckController controller; + + public DeckController getController() { + return controller; + } + + private EditorType(DeckController controller0) { + controller = controller0; + } } private static DeckEditorPage[] getPages(EditorType editorType) { @@ -93,9 +152,6 @@ public class FDeckEditor extends TabPageScreen { private DeckSectionPage sideboardPage; private OptionsPage optionsPage; - public FDeckEditor(EditorType editorType0) { - this(editorType0, null); - } public FDeckEditor(EditorType editorType0, Deck deck0) { super(getPages(editorType0)); editorType = editorType0; @@ -137,6 +193,20 @@ public class FDeckEditor extends TabPageScreen { if (editorType == EditorType.Sealed && deck.getMain().isEmpty()) { setSelectedPage(sideboardPage); } + + //set model for controller based on editor type + if (!StringUtils.isEmpty(deck.getName())) { + switch (editorType) { + case Draft: + case Sealed: + case Winston: + editorType.getController().setDeckBase(editorType.getController().currentFolder.get(deck.getName())); + break; + default: + editorType.getController().setDeckBase(deck); + break; + } + } } public EditorType getEditorType() { @@ -167,7 +237,91 @@ public class FDeckEditor extends TabPageScreen { return null; } - protected void save() { + protected void save(final Callback callback) { + final DeckController controller = editorType.getController(); + final String name = getOptionsPage().txtName.getText(); + final String deckStr = DeckProxy.getDeckString(controller.getModelPath(), name); + + // Warn if no name + if (StringUtils.isEmpty(name)) { + FOptionPane.showErrorDialog("Please name your deck using the 'Name' box.", "Save Error!"); + if (callback != null) { + callback.run(false); + } + return; + } + + // Confirm if overwrite + if (controller.fileExists(name)) { + //prompt only if name was changed + if (!StringUtils.equals(name, controller.getModelName())) { + FOptionPane.showConfirmDialog("There is already a deck named '" + name + "'. Overwrite?", + "Overwrite Deck?", new Callback() { + @Override + public void run(Boolean result) { + if (result) { + controller.save(); + afterSave(deckStr); + } + if (callback != null) { + callback.run(result); + } + } + }); + return; + } + controller.save(); + afterSave(deckStr); + if (callback != null) { + callback.run(true); + } + return; + } + + // Confirm if a new deck will be created + FOptionPane.showConfirmDialog("This will create a new deck named '" + + name + "'. Continue?", "Create Deck?", new Callback() { + @Override + public void run(Boolean result) { + if (result) { + controller.saveAs(name); + afterSave(deckStr); + } + if (callback != null) { + callback.run(result); + } + } + }); + } + + private void afterSave(String deckStr) { + if (editorType == EditorType.Constructed) { + DeckPreferences.setCurrentDeck(deckStr); + } + } + + @Override + public void onClose(final Callback canCloseCallback) { + if (editorType.getController().isSaved() || canCloseCallback == null) { + super.onClose(canCloseCallback); //can skip prompt if draft saved + return; + } + FOptionPane.showOptionDialog("Save changes to current deck?", "Save Changes?", + FOptionPane.QUESTION_ICON, new String[] {"Save", "Don't Save", "Cancel"}, new Callback() { + @Override + public void run(Integer result) { + if (result == 0) { + save(canCloseCallback); + } + else if (result == 1) { + editorType.getController().reload(); //reload if not saving changes + canCloseCallback.run(true); + } + else { + canCloseCallback.run(false); + } + } + }); } protected static abstract class DeckEditorPage extends TabPage { @@ -194,11 +348,13 @@ public class FDeckEditor extends TabPageScreen { public void addCard(PaperCard card) { cardManager.addItem(card, 1); + parentScreen.getEditorType().getController().notifyModelChanged(); updateCaption(); } public void removeCard(PaperCard card) { cardManager.removeItem(card, 1); + parentScreen.getEditorType().getController().notifyModelChanged(); updateCaption(); } @@ -363,7 +519,7 @@ public class FDeckEditor extends TabPageScreen { hideTab(); //hide this tab page when finished drafting parentScreen.getOptionsPage().showTab(); //show options page when finished drafting draft.finishedDrafting(); - parentScreen.save(); + parentScreen.save(null); } } } @@ -374,9 +530,10 @@ public class FDeckEditor extends TabPageScreen { private final FLabel lblName = add(new FLabel.Builder().text("Name:").build()); private final FTextField txtName = add(new FTextField()); private final FLabel btnSave = add(new FLabel.ButtonBuilder().text("Save Deck").icon(FSkinImage.SAVE).build()); - private final FLabel btnNew = add(new FLabel.ButtonBuilder().text("New Deck").icon(FSkinImage.NEW).build()); + private final FLabel btnAddLands = add(new FLabel.ButtonBuilder().text("Add Lands").icon(FSkinImage.LAND).build()); + /*private final FLabel btnNew = add(new FLabel.ButtonBuilder().text("New Deck").icon(FSkinImage.NEW).build()); private final FLabel btnOpen = add(new FLabel.ButtonBuilder().text("Open Deck").icon(FSkinImage.OPEN).build()); - private final FLabel btnSaveAs = add(new FLabel.ButtonBuilder().text("Save Deck As").icon(FSkinImage.SAVEAS).build()); + private final FLabel btnSaveAs = add(new FLabel.ButtonBuilder().text("Save Deck As").icon(FSkinImage.SAVEAS).build());*/ protected OptionsPage() { super("Options", FSkinImage.SETTINGS); @@ -386,6 +543,18 @@ public class FDeckEditor extends TabPageScreen { protected void initialize() { txtName.setGhostText("[New Deck]"); txtName.setText(parentScreen.getDeck().getName()); + + btnSave.setCommand(new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + parentScreen.save(null); + } + }); + btnAddLands.setCommand(new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + } + }); } @Override @@ -393,7 +562,6 @@ public class FDeckEditor extends TabPageScreen { float x = PADDING; float y = PADDING; float w = width - 2 * PADDING; - float h = height - 2 * PADDING; lblName.setBounds(x, y, lblName.getAutoSizeBounds().width, txtName.getHeight()); txtName.setBounds(x + lblName.getWidth(), y, w - lblName.getWidth(), txtName.getHeight()); @@ -404,11 +572,176 @@ public class FDeckEditor extends TabPageScreen { btnSave.setBounds(x, y, w, buttonHeight); y += dy; - btnNew.setBounds(x, y, w, buttonHeight); + btnAddLands.setBounds(x, y, w, buttonHeight); + y += dy; + /*btnNew.setBounds(x, y, w, buttonHeight); y += dy; btnOpen.setBounds(x, y, w, buttonHeight); y += dy; - btnSaveAs.setBounds(x, y, w, buttonHeight); + btnSaveAs.setBounds(x, y, w, buttonHeight);*/ + } + } + + public static class DeckController { + private T model; + private boolean saved; + private boolean modelInStorage; + private final IStorage rootFolder; + private IStorage currentFolder; + private String modelPath; + private final Supplier newModelCreator; + + protected DeckController(final IStorage folder0, final Supplier newModelCreator0) { + rootFolder = folder0; + currentFolder = rootFolder; + model = null; + saved = true; + modelInStorage = false; + modelPath = ""; + newModelCreator = newModelCreator0; + } + + public T getModel() { + return model; + } + + public String getModelPath() { + return modelPath; + } + + @SuppressWarnings("unchecked") + public void setDeckBase(final DeckBase deckBase) { + setModel((T)deckBase, true); + } + + public void setModel(final T document) { + setModel(document, false); + } + public void setModel(final T document, final boolean isStored) { + modelInStorage = isStored; + model = document; + + if (isStored) { + if (isModelInSyncWithFolder()) { + setSaved(true); + } + else { + notifyModelChanged(); + } + } + else { //TODO: Make this smarter + currentFolder = rootFolder; + modelPath = ""; + setSaved(true); + } + } + + private boolean isModelInSyncWithFolder() { + if (model.getName().isEmpty()) { + return true; + } + + final T modelStored = currentFolder.get(model.getName()); + // checks presence in dictionary only. + if (modelStored == model) { + return true; + } + if (modelStored == null) { + return false; + } + + return modelStored.equals(model); + } + + public void notifyModelChanged() { + if (saved) { + setSaved(false); + } + } + + private void setSaved(boolean val) { + saved = val; + } + + public void reload() { + String name = getModelName(); + if (name.isEmpty()) { + newModel(); + } + else { + load(name); + } + } + + public void load(final String path, final String name) { + if (StringUtils.isBlank(path)) { + currentFolder = rootFolder; + } + else { + currentFolder = rootFolder.tryGetFolder(path); + } + modelPath = path; + load(name); + } + + @SuppressWarnings("unchecked") + private void load(final String name) { + T newModel = currentFolder.get(name); + if (newModel != null) { + setModel((T) newModel.copyTo(name), true); + } + else { + setSaved(true); + } + } + + @SuppressWarnings("unchecked") + public void save() { + if (model == null) { + return; + } + + // copy to new instance before adding to current folder so further changes are auto-saved + currentFolder.add((T) model.copyTo(model.getName())); + modelInStorage = true; + setSaved(true); + } + + @SuppressWarnings("unchecked") + public void saveAs(final String name0) { + model = (T)model.copyTo(name0); + modelInStorage = false; + save(); + } + + public boolean isSaved() { + return saved; + } + + public boolean fileExists(final String deckName) { + return currentFolder.contains(deckName); + } + + public void importDeck(final T newDeck) { + setModel(newDeck); + } + + public void refreshModel() { + if (model == null) { + newModel(); + } + else { + setModel(model, modelInStorage); + } + } + + public void newModel() { + model = newModelCreator.get(); + setSaved(true); + } + + public String getModelName() { + return model != null ? model.getName() : ""; } } } diff --git a/forge-gui-mobile/src/forge/screens/draft/DraftScreen.java b/forge-gui-mobile/src/forge/screens/draft/DraftScreen.java index 46a38565445..ff813e13e58 100644 --- a/forge-gui-mobile/src/forge/screens/draft/DraftScreen.java +++ b/forge-gui-mobile/src/forge/screens/draft/DraftScreen.java @@ -36,7 +36,6 @@ public class DraftScreen extends LaunchScreen { public DraftScreen() { super("Booster Draft"); - lstDecks.setPool(DeckProxy.getDraftDecks(FModel.getDecks().getDraft())); lstDecks.setup(ItemManagerConfig.DRAFT_DECKS); lstDecks.setItemActivateHandler(new FEventHandler() { @Override @@ -82,6 +81,11 @@ public class DraftScreen extends LaunchScreen { }); } + @Override + public void onActivate() { + lstDecks.setPool(DeckProxy.getDraftDecks(FModel.getDecks().getDraft())); + } + private void editSelectedDeck() { final DeckProxy deck = lstDecks.getSelectedItem(); if (deck == null) { return; } @@ -129,8 +133,8 @@ public class DraftScreen extends LaunchScreen { }*/ final int aiIndex = (int) Math.floor(Math.random() * 7); - DeckGroup opponentDecks = FModel.getDecks().getDraft().get(humanDeck.getName()); - Deck aiDeck = opponentDecks.getAiDecks().get(aiIndex); + DeckGroup deckGroup = FModel.getDecks().getDraft().get(humanDeck.getName()); + Deck aiDeck = deckGroup.getAiDecks().get(aiIndex); if (aiDeck == null) { throw new IllegalStateException("Draft: Computer deck is null!"); } diff --git a/forge-gui-mobile/src/forge/screens/draft/DraftingProcessScreen.java b/forge-gui-mobile/src/forge/screens/draft/DraftingProcessScreen.java index 26c08ff9860..8106cc7b9da 100644 --- a/forge-gui-mobile/src/forge/screens/draft/DraftingProcessScreen.java +++ b/forge-gui-mobile/src/forge/screens/draft/DraftingProcessScreen.java @@ -11,11 +11,11 @@ import forge.toolbox.FOptionPane; import forge.util.Callback; public class DraftingProcessScreen extends FDeckEditor { - private boolean saved; + private boolean isDraftSaved; private final BoosterDraft draft; public DraftingProcessScreen(BoosterDraft draft0) { - super(EditorType.Draft); + super(EditorType.Draft, null); draft = draft0; getCatalogPage().refresh(); //must refresh after draft set } @@ -26,14 +26,17 @@ public class DraftingProcessScreen extends FDeckEditor { } @Override - protected void save() { - if (saved) { return; } + protected void save(final Callback callback) { + if (isDraftSaved) { //if draft itself is saved, let base class handle saving deck changes + super.save(callback); + return; + } FOptionPane.showInputDialog("Save this draft as:", "Save Draft", FOptionPane.QUESTION_ICON, new Callback() { @Override public void run(final String name) { if (StringUtils.isEmpty(name)) { - save(); //re-prompt if user doesn't pick a name + save(callback); //re-prompt if user doesn't pick a name return; } @@ -47,9 +50,12 @@ public class DraftingProcessScreen extends FDeckEditor { public void run(Boolean result) { if (result) { finishSave(name); + if (callback != null) { + callback.run(true); + } } else { - save(); //If no overwrite, recurse + save(callback); //If no overwrite, recurse } } }); @@ -58,12 +64,15 @@ public class DraftingProcessScreen extends FDeckEditor { } finishSave(name); + if (callback != null) { + callback.run(true); + } } }); } private void finishSave(String name) { - saved = true; + isDraftSaved = true; // Construct computer's decks and save draft final Deck[] computer = draft.getDecks(); @@ -73,11 +82,12 @@ public class DraftingProcessScreen extends FDeckEditor { finishedDraft.addAiDecks(computer); FModel.getDecks().getDraft().add(finishedDraft); + this.getEditorType().getController().setDeckBase(finishedDraft); } @Override public void onClose(Callback canCloseCallback) { - if (saved || canCloseCallback == null) { + if (isDraftSaved || canCloseCallback == null) { super.onClose(canCloseCallback); //can skip prompt if draft saved return; } diff --git a/forge-gui-mobile/src/forge/screens/sealed/SealedScreen.java b/forge-gui-mobile/src/forge/screens/sealed/SealedScreen.java index a3901cc77f1..241dde98147 100644 --- a/forge-gui-mobile/src/forge/screens/sealed/SealedScreen.java +++ b/forge-gui-mobile/src/forge/screens/sealed/SealedScreen.java @@ -30,7 +30,6 @@ public class SealedScreen extends LaunchScreen { public SealedScreen() { super("Sealed Deck"); - lstDecks.setPool(DeckProxy.getAllSealedDecks(FModel.getDecks().getSealed())); lstDecks.setup(ItemManagerConfig.SEALED_DECKS); lstDecks.setItemActivateHandler(new FEventHandler() { @Override @@ -68,6 +67,11 @@ public class SealedScreen extends LaunchScreen { }); } + @Override + public void onActivate() { + lstDecks.setPool(DeckProxy.getAllSealedDecks(FModel.getDecks().getSealed())); + } + private void editSelectedDeck() { final DeckProxy deck = lstDecks.getSelectedItem(); if (deck == null) { return; }