Add Workshop screen

This commit is contained in:
drdev
2013-11-17 08:02:40 +00:00
parent 284e2257f3
commit b0160287ba
26 changed files with 1556 additions and 52 deletions

View File

@@ -17,7 +17,9 @@
*/
package forge.card;
import java.io.File;
import java.util.List;
import forge.card.mana.ManaCost;
/**
@@ -34,8 +36,8 @@ public final class CardRules implements ICardCharacteristics {
//private final Map<String, CardInSet> setsPrinted = new TreeMap<String, CardInSet>(String.CASE_INSENSITIVE_ORDER);
private CardAiHints aiHints;
private ColorSet colorIdentity = null;
private File sourceFile;
public CardRules(ICardFace[] faces, CardSplitType altMode, CardAiHints cah) {
splitType = altMode;
@@ -65,8 +67,7 @@ public final class CardRules implements ICardCharacteristics {
colorIdentity = ColorSet.fromMask(colMask);
}
private byte calculateColorIdentity(ICardFace face)
{
private byte calculateColorIdentity(ICardFace face) {
byte res = face.getColor().getColor();
boolean isReminder = false;
boolean isSymbol = false;
@@ -216,7 +217,14 @@ public final class CardRules implements ICardCharacteristics {
}
public ColorSet getColorIdentity() {
return colorIdentity;
return this.colorIdentity;
}
public File getSourceFile() {
return this.sourceFile;
}
public void setSourceFile(File sourceFile0) {
this.sourceFile = sourceFile0;
}
}

View File

@@ -47,8 +47,6 @@ public class CardRulesReader {
private boolean removedFromRandomDecks = false;
private DeckHints hints = null;
private DeckHints needs = null;
// Reset all fields to parse next card (to avoid allocating new
// CardRulesReader N times)

View File

@@ -329,15 +329,17 @@ public class CardStorageReader {
*
* @return a new Card instance
*/
protected final CardRules loadCard(final CardRulesReader reader, final File pathToTxtFile) {
protected final CardRules loadCard(final CardRulesReader reader, final File file) {
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(pathToTxtFile);
return this.loadCard(reader, fileInputStream);
fileInputStream = new FileInputStream(file);
CardRules rules = this.loadCard(reader, fileInputStream);
rules.setSourceFile(file);
return rules;
} catch (final FileNotFoundException ex) {
BugReporter.reportException(ex, "File \"%s\" exception", pathToTxtFile.getAbsolutePath());
BugReporter.reportException(ex, "File \"%s\" exception", file.getAbsolutePath());
throw new RuntimeException("CardReader : run error -- file exception -- filename is "
+ pathToTxtFile.getPath(), ex);
+ file.getPath(), ex);
} finally {
try {
fileInputStream.close();

View File

@@ -40,6 +40,8 @@ import javax.swing.PopupFactory;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.apache.commons.lang.CharUtils;
import org.apache.commons.lang.StringUtils;
@@ -85,7 +87,7 @@ public enum CDeckEditorUI implements ICDoc, IMenuProvider {
SINGLETON_INSTANCE;
private final HashMap<FScreen, ACEditorBase<? extends InventoryItem, ? extends DeckBase>> screenChildControllers;
private ACEditorBase<? extends InventoryItem, ? extends DeckBase> childController;
private ACEditorBase<? extends InventoryItem, ? extends DeckBase> childController;
private boolean isFindingAsYouType = false;
private CDeckEditorUI() {
@@ -358,7 +360,7 @@ public enum CDeckEditorUI implements ICDoc, IMenuProvider {
removeSelectedCards(toAlternate, qty);
}
};
catTable.addMouseListener(new FMouseAdapter() {
@Override
public void onLeftDoubleClick(MouseEvent e) {
@@ -407,6 +409,24 @@ public enum CDeckEditorUI implements ICDoc, IMenuProvider {
catTable.addKeyListener(catFind);
deckTable.addKeyListener(deckFind);
//set card when selection changes
catView.addSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
setCard(catView.getSelectedItem());
}
});
deckView.addSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
setCard(deckView.getSelectedItem());
}
});
catView.setAllowMultipleSelections(true);
deckView.setAllowMultipleSelections(true);
childController.listenersHooked = true;
}

View File

@@ -40,6 +40,9 @@ import forge.gui.match.views.VMessage;
import forge.gui.match.views.VPicture;
import forge.gui.match.views.VPlayers;
import forge.gui.match.views.VStack;
import forge.gui.workshop.views.VCardDesigner;
import forge.gui.workshop.views.VCardScript;
import forge.gui.workshop.views.VWorkshopCatalog;
/**
* These are the identifiers for tabs found in the drag layout.
@@ -59,6 +62,10 @@ public enum EDocID { /** */
EDITOR_CATALOG (VCardCatalog.SINGLETON_INSTANCE), /** */
EDITOR_CURRENTDECK (VCurrentDeck.SINGLETON_INSTANCE), /** */
EDITOR_DECKGEN (VDeckgen.SINGLETON_INSTANCE), /** */
WORKSHOP_CATALOG (VWorkshopCatalog.SINGLETON_INSTANCE), /** */
WORKSHOP_CARDDESIGNER (VCardDesigner.SINGLETON_INSTANCE), /** */
WORKSHOP_CARDSCRIPT (VCardScript.SINGLETON_INSTANCE), /** */
HOME_QUESTCHALLENGES (VSubmenuChallenges.SINGLETON_INSTANCE), /** */
HOME_QUESTDUELS (VSubmenuDuels.SINGLETON_INSTANCE), /** */

View File

@@ -15,6 +15,8 @@ import forge.gui.match.CMatchUI;
import forge.gui.match.VMatchUI;
import forge.gui.toolbox.FSkin;
import forge.gui.toolbox.FSkin.SkinImage;
import forge.gui.workshop.CWorkshopUI;
import forge.gui.workshop.VWorkshopUI;
import forge.properties.FileLocation;
import forge.properties.NewConstants;
@@ -35,10 +37,18 @@ public enum FScreen {
VMatchUI.SINGLETON_INSTANCE,
CMatchUI.SINGLETON_INSTANCE,
"Game",
FSkin.getIcon(FSkin.DockIcons.ICO_ALPHASTRIKE),
FSkin.getIcon(FSkin.DockIcons.ICO_ALPHASTRIKE), //TODO: Create icon for match screen
true,
"Concede Game",
NewConstants.MATCH_LAYOUT_FILE),
WORKSHOP_SCREEN(
VWorkshopUI.SINGLETON_INSTANCE,
CWorkshopUI.SINGLETON_INSTANCE,
"Workshop",
FSkin.getIcon(FSkin.DockIcons.ICO_SETTINGS), //TODO: Create icon for workshop screen
false,
"Back to Home",
NewConstants.WORKSHOP_LAYOUT_FILE),
DECK_EDITOR_CONSTRUCTED(
VDeckEditorUI.SINGLETON_INSTANCE,
CDeckEditorUI.SINGLETON_INSTANCE,

View File

@@ -106,6 +106,13 @@ public enum CSubmenuPreferences implements ICDoc {
CSubmenuPreferences.this.resetDeckEditorLayout();
}
});
view.getBtnDeleteWorkshopUI().setCommand(new Command() {
@Override
public void run() {
CSubmenuPreferences.this.resetWorkshopLayout();
}
});
view.getBtnDeleteMatchUI().setCommand(new Command() {
@Override
@@ -178,6 +185,19 @@ public enum CSubmenuPreferences implements ICDoc {
}
}
private void resetWorkshopLayout() {
String userPrompt =
"This will reset the Workshop screen layout.\n" +
"All tabbed views will be restored to their default positions.\n\n" +
"Reset layout?";
int reply = JOptionPane.showConfirmDialog(JOptionPane.getRootFrame(), userPrompt, "Reset Workshop Layout", JOptionPane.YES_NO_OPTION);
if (reply == JOptionPane.YES_OPTION) {
if (FScreen.WORKSHOP_SCREEN.deleteLayoutFile()) {
JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "Workshop layout has been reset.");
}
}
}
private void resetMatchScreenLayout() {
String userPrompt =
"This will reset the layout of the Match screen.\n" +

View File

@@ -62,6 +62,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
private final FLabel btnReset = new FLabel.Builder().opaque(true).hoverable(true).text("Reset to Default Settings").build();
private final FLabel btnDeleteMatchUI = new FLabel.Builder().opaque(true).hoverable(true).text("Reset Match Layout").build();
private final FLabel btnDeleteEditorUI = new FLabel.Builder().opaque(true).hoverable(true).text("Reset Editor Layout").build();
private final FLabel btnDeleteWorkshopUI = new FLabel.Builder().opaque(true).hoverable(true).text("Reset Workshop Layout").build();
private final FLabel btnPlayerName = new FLabel.Builder().opaque(true).hoverable(true).text("").build();
private final JCheckBox cbRemoveSmall = new OptionsCheckBox("Remove Small Creatures");
@@ -103,18 +104,16 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
final String sectionConstraints = "w 80%!, h 42px!, gap 10% 0 10px 10px, span 2 1";
final String regularConstraints = "w 80%!, h 22px!, gap 10% 0 0 10px, span 2 1";
// Troubleshooting
pnlPrefs.add(new SectionLabel("Troubleshooting"), sectionConstraints);
//pnlPrefs.add(new SectionLabel(" "), sectionConstraints);
pnlPrefs.add(btnReset, regularConstraints + ", h 30px!");
final String twoButtonConstraints = "w 38%!, h 30px!, gap 10% 0 0 10px";
pnlPrefs.add(btnDeleteMatchUI, twoButtonConstraints);
pnlPrefs.add(btnDeleteEditorUI, "w 38%!, h 30px!, gap 0 0 0 10px");
// Reset button
// Reset buttons
final String twoButtonConstraints1 = "w 38%!, h 30px!, gap 10% 0 0 10px";
final String twoButtonConstraints2 = "w 38%!, h 30px!, gap 0 0 0 10px";
pnlPrefs.add(btnReset, twoButtonConstraints1);
pnlPrefs.add(btnDeleteMatchUI, twoButtonConstraints2);
pnlPrefs.add(btnDeleteEditorUI, twoButtonConstraints1);
pnlPrefs.add(btnDeleteWorkshopUI, twoButtonConstraints2);
// General Configuration
pnlPrefs.add(new SectionLabel("General Configuration"), sectionConstraints + ", gaptop 2%");
@@ -508,6 +507,10 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
public final FLabel getBtnDeleteEditorUI() {
return btnDeleteEditorUI;
}
public final FLabel getBtnDeleteWorkshopUI() {
return btnDeleteWorkshopUI;
}
/* (non-Javadoc)
* @see forge.gui.framework.IVDoc#getDocumentID()

View File

@@ -74,8 +74,6 @@ public enum VSubmenuReleaseNotes implements IVSubmenu<CSubmenuReleaseNotes> {
scroller = new JScrollPane(tar);
pnlMain.add(scroller, "w 100%!, h 100%!");
}
/* (non-Javadoc)

View File

@@ -29,6 +29,8 @@ import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionListener;
import com.google.common.base.Predicate;
@@ -68,8 +70,10 @@ public abstract class ItemManager<T extends InventoryItem> extends JPanel {
private final List<ItemFilter<T>> orderedFilters = new ArrayList<ItemFilter<T>>();
private boolean wantUnique = false;
private boolean alwaysNonUnique = false;
private boolean allowMultipleSelections = false;
private final Class<T> genericType;
private final Map<SItemManagerUtil.StatTypes, FLabel> statLabels;
private final ArrayList<ListSelectionListener> selectionListeners = new ArrayList<ListSelectionListener>();
private final FLabel btnAddFilter = new FLabel.ButtonBuilder()
.text("Add")
@@ -94,6 +98,7 @@ public abstract class ItemManager<T extends InventoryItem> extends JPanel {
//build table view
this.table = new ItemTable<T>(this, this.model);
this.table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
this.tableScroller = new JScrollPane(this.table);
this.tableScroller.setOpaque(false);
this.tableScroller.getViewport().setOpaque(false);
@@ -133,8 +138,7 @@ public abstract class ItemManager<T extends InventoryItem> extends JPanel {
}
@Override
public void doLayout()
{
public void doLayout() {
//int number = 0;
LayoutHelper helper = new LayoutHelper(this);
/*for (ItemFilter<T> filter : this.orderedFilters) {
@@ -240,7 +244,7 @@ public abstract class ItemManager<T extends InventoryItem> extends JPanel {
*
* @return InventoryItem
*/
public InventoryItem getSelectedItem() {
public T getSelectedItem() {
return this.table.getSelectedItem();
}
@@ -250,7 +254,7 @@ public abstract class ItemManager<T extends InventoryItem> extends JPanel {
*
* @return List<InventoryItem>
*/
public List<InventoryItem> getSelectedItems() {
public List<T> getSelectedItems() {
return this.table.getSelectedItems();
}
@@ -471,7 +475,7 @@ public abstract class ItemManager<T extends InventoryItem> extends JPanel {
*
* setWantUnique.
*
* @param unique if true, the editor will be set to the "unique item names only" mode.
* @param unique - if true, the editor will be set to the "unique item names only" mode.
*/
public void setWantUnique(boolean unique) {
this.wantUnique = this.alwaysNonUnique ? false : unique;
@@ -481,7 +485,7 @@ public abstract class ItemManager<T extends InventoryItem> extends JPanel {
*
* getAlwaysNonUnique.
*
* @return if ture, this editor must always show non-unique items (e.g. quest editor).
* @return if true, this editor must always show non-unique items (e.g. quest editor).
*/
public boolean getAlwaysNonUnique() {
return this.alwaysNonUnique;
@@ -491,11 +495,33 @@ public abstract class ItemManager<T extends InventoryItem> extends JPanel {
*
* setAlwaysNonUnique.
*
* @param nonUniqueOnly if true, this editor must always show non-unique items (e.g. quest editor).
* @param nonUniqueOnly - if true, this editor must always show non-unique items (e.g. quest editor).
*/
public void setAlwaysNonUnique(boolean nonUniqueOnly) {
this.alwaysNonUnique = nonUniqueOnly;
}
/**
*
* getAllowMultipleSelections.
*
* @return if true, multiple items can be selected at once
*/
public boolean getAllowMultipleSelections() {
return this.allowMultipleSelections;
}
/**
*
* getAllowMultipleSelections.
*
* @return allowMultipleSelections0 - if true, multiple items can be selected at once
*/
public void setAllowMultipleSelections(boolean allowMultipleSelections0) {
if (this.allowMultipleSelections == allowMultipleSelections0) { return; }
this.allowMultipleSelections = allowMultipleSelections0;
this.table.setSelectionMode(allowMultipleSelections0 ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION : ListSelectionModel.SINGLE_SELECTION);
}
/**
*
@@ -509,4 +535,17 @@ public abstract class ItemManager<T extends InventoryItem> extends JPanel {
this.table.changeSelection(0, 0, false, false);
}
}
public void addSelectionListener(ListSelectionListener listener) {
selectionListeners.remove(listener); //ensure listener not added multiple times
selectionListeners.add(listener);
}
public void removeSelectionListener(ListSelectionListener listener) {
selectionListeners.remove(listener);
}
public Iterable<ListSelectionListener> getSelectionListeners() {
return selectionListeners;
}
}

View File

@@ -58,6 +58,10 @@ public final class ItemTable<T extends InventoryItem> extends JTable {
private final FSkin.JTableSkin<ItemTable<T>> skin;
private final ItemManager<T> itemManager;
private final ItemTableModel<T> tableModel;
public ItemManager<T> getItemManager() {
return this.itemManager;
}
public ItemTableModel<T> getTableModel() {
return this.tableModel;
@@ -283,7 +287,7 @@ public final class ItemTable<T extends InventoryItem> extends JTable {
*
* @return InventoryItem
*/
public InventoryItem getSelectedItem() {
public T getSelectedItem() {
final int iRow = getSelectedRow();
return iRow >= 0 ? this.tableModel.rowToItem(iRow).getKey() : null;
}
@@ -294,8 +298,8 @@ public final class ItemTable<T extends InventoryItem> extends JTable {
*
* @return List<InventoryItem>
*/
public List<InventoryItem> getSelectedItems() {
List<InventoryItem> items = new ArrayList<InventoryItem>();
public List<T> getSelectedItems() {
List<T> items = new ArrayList<T>();
for (int row : getSelectedRows()) {
items.add(tableModel.rowToItem(row).getKey());
}

View File

@@ -28,7 +28,6 @@ import java.util.Enumeration;
import java.util.List;
import java.util.Map.Entry;
import javax.swing.JTable;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
@@ -38,7 +37,6 @@ import javax.swing.table.TableColumnModel;
import org.apache.commons.lang3.ArrayUtils;
import forge.gui.deckeditor.CDeckEditorUI;
import forge.gui.toolbox.FMouseAdapter;
import forge.gui.toolbox.itemmanager.ItemManagerModel;
import forge.gui.toolbox.itemmanager.SItemManagerIO;
@@ -125,17 +123,13 @@ public final class ItemTableModel<T extends InventoryItem> extends AbstractTable
return (row >= 0) && (row < model.size()) ? model.get(row) : null;
}
/**
* Show selected card.
*
* @param table
* the table
*/
public void showSelectedItem(final JTable table) {
public void onSelectionChange(final ItemTable<T> table) {
final int row = table.getSelectedRow();
if (row != -1) {
Entry<T, Integer> card = this.rowToItem(row);
CDeckEditorUI.SINGLETON_INSTANCE.setCard(null != card ? card.getKey() : null);
ListSelectionEvent event = new ListSelectionEvent(table.getItemManager(), row, row, false);
for (ListSelectionListener listener : table.getItemManager().getSelectionListeners()) {
listener.valueChanged(event);
}
}
}
@@ -143,7 +137,7 @@ public final class ItemTableModel<T extends InventoryItem> extends AbstractTable
@Override
public void valueChanged(final ListSelectionEvent arg0) {
if (table.isFocusOwner()) {
ItemTableModel.this.showSelectedItem(table);
ItemTableModel.this.onSelectionChange(table);
}
}
};
@@ -151,7 +145,7 @@ public final class ItemTableModel<T extends InventoryItem> extends AbstractTable
private final FocusAdapter focusAdapter = new FocusAdapter() {
@Override
public void focusGained(final FocusEvent e) {
ItemTableModel.this.showSelectedItem(table);
ItemTableModel.this.onSelectionChange(table);
}
};

View File

@@ -0,0 +1,89 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.gui.workshop;
import java.util.List;
import javax.swing.JMenu;
import forge.Command;
import forge.Singletons;
import forge.gui.framework.ICDoc;
import forge.gui.menus.IMenuProvider;
import forge.gui.toolbox.itemmanager.CardManager;
import forge.gui.toolbox.itemmanager.SItemManagerIO;
import forge.gui.toolbox.itemmanager.SItemManagerIO.EditorPreference;
import forge.gui.toolbox.itemmanager.table.ItemTable;
import forge.gui.workshop.controllers.CWorkshopCatalog;
import forge.gui.workshop.views.VWorkshopCatalog;
import forge.item.PaperCard;
/**
* Constructs instance of workshop UI controller, used as a single point of
* top-level control for child UIs. Tasks targeting the view of individual
* components are found in a separate controller for that component and
* should not be included here.
*
* <br><br><i>(C at beginning of class name denotes a control class.)</i>
*/
public enum CWorkshopUI implements ICDoc, IMenuProvider {
/** */
SINGLETON_INSTANCE;
private CWorkshopUI() {
}
/* (non-Javadoc)
* @see forge.gui.menubar.IMenuProvider#getMenus()
*/
@Override
public List<JMenu> getMenus() {
return null; //TODO: Create Workshop menus
}
/* (non-Javadoc)
* @see forge.gui.framework.ICDoc#getCommandOnSelect()
*/
@Override
public Command getCommandOnSelect() {
return null;
}
/* (non-Javadoc)
* @see forge.gui.framework.ICDoc#initialize()
*/
@Override
public void initialize() {
Singletons.getControl().getForgeMenu().setProvider(this);
final CardManager cardManager = VWorkshopCatalog.SINGLETON_INSTANCE.getCardManager();
final ItemTable<PaperCard> cardTable = cardManager.getTable();
boolean wantElastic = SItemManagerIO.getPref(EditorPreference.elastic_columns);
boolean wantUnique = SItemManagerIO.getPref(EditorPreference.display_unique_only);
cardTable.setWantElasticColumns(wantElastic);
cardManager.setWantUnique(wantUnique);
CWorkshopCatalog.SINGLETON_INSTANCE.applyCurrentFilter();
}
/* (non-Javadoc)
* @see forge.gui.framework.ICDoc#update()
*/
@Override
public void update() { }
}

View File

@@ -0,0 +1,9 @@
package forge.gui.workshop;
/**
* Handles worksho saving and loading.
*
* <br><br><i>(S at beginning of class name denotes a static factory.)</i>
*/
public class SWorkshopIO {
}

View File

@@ -0,0 +1,62 @@
package forge.gui.workshop;
import javax.swing.SwingUtilities;
import forge.Singletons;
import forge.gui.framework.FScreen;
import forge.gui.framework.IVTopLevelUI;
import forge.gui.workshop.views.VWorkshopCatalog;
/**
/**
* Top level view class; instantiates and assembles
* tabs used in deck editor UI drag layout.<br>
*
* <br><br><i>(V at beginning of class name denotes a view class.)</i>
*
*/
public enum VWorkshopUI implements IVTopLevelUI {
/** */
SINGLETON_INSTANCE;
//========== Overridden methods
/* (non-Javadoc)
* @see forge.gui.framework.IVTopLevelUI#instantiate()
*/
@Override
public void instantiate() {
}
/* (non-Javadoc)
* @see forge.gui.framework.IVTopLevelUI#populate()
*/
@Override
public void populate() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
VWorkshopCatalog.SINGLETON_INSTANCE.getCardManager().focus();
}
});
}
/* (non-Javadoc)
* @see forge.gui.framework.IVTopLevelUI#onSwitching(forge.gui.framework.FScreen)
*/
@Override
public boolean onSwitching(FScreen fromScreen, FScreen toScreen) {
//TODO: ensure card saved before switching
return true;
}
/* (non-Javadoc)
* @see forge.gui.framework.IVTopLevelUI#onClosing()
*/
@Override
public boolean onClosing(FScreen screen) {
//don't close tab, but return to home screen if this called
Singletons.getControl().setCurrentScreen(FScreen.HOME_SCREEN);
return false;
}
}

View File

@@ -0,0 +1,50 @@
package forge.gui.workshop.controllers;
import forge.Command;
import forge.gui.framework.ICDoc;
import forge.gui.workshop.views.VCardDesigner;
/**
* Controls the "card designer" panel in the workshop UI.
*
* <br><br><i>(C at beginning of class name denotes a control class.)</i>
*
*/
public enum CCardDesigner implements ICDoc {
/** */
SINGLETON_INSTANCE;
private CCardDesigner() {
VCardDesigner.SINGLETON_INSTANCE.getBtnSaveCard().setCommand(new Runnable() {
@Override
public void run() {
CCardScript.SINGLETON_INSTANCE.saveChanges();
}
});
}
//========== Overridden methods
/* (non-Javadoc)
* @see forge.gui.framework.ICDoc#getCommandOnSelect()
*/
@Override
public Command getCommandOnSelect() {
return null;
}
/* (non-Javadoc)
* @see forge.gui.framework.ICDoc#initialize()
*/
@Override
public void initialize() {
}
/* (non-Javadoc)
* @see forge.gui.framework.ICDoc#update()
*/
@Override
public void update() {
}
}

View File

@@ -0,0 +1,126 @@
package forge.gui.workshop.controllers;
import java.io.File;
import java.io.PrintWriter;
import javax.swing.JTextArea;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import forge.Command;
import forge.error.BugReporter;
import forge.gui.framework.ICDoc;
import forge.gui.workshop.views.VCardDesigner;
import forge.gui.workshop.views.VCardScript;
import forge.item.PaperCard;
import forge.util.FileUtil;
/**
* Controls the "card script" panel in the workshop UI.
*
* <br><br><i>(C at beginning of class name denotes a control class.)</i>
*
*/
public enum CCardScript implements ICDoc {
/** */
SINGLETON_INSTANCE;
private PaperCard currentCard;
private String baseText;
private boolean isTextDirty;
private CCardScript() {
VCardScript.SINGLETON_INSTANCE.getTarScript().getDocument().addDocumentListener(new DocumentListener() {
@Override
public void removeUpdate(DocumentEvent arg0) {
updateDirtyFlag();
}
@Override
public void insertUpdate(DocumentEvent arg0) {
updateDirtyFlag();
}
@Override
public void changedUpdate(DocumentEvent arg0) {
//Plain text components do not fire these events
}
});
}
private void updateDirtyFlag() {
isTextDirty = !VCardScript.SINGLETON_INSTANCE.getTarScript().getText().equals(baseText);
VCardDesigner.SINGLETON_INSTANCE.getBtnSaveCard().setEnabled(isTextDirty);
VCardScript.SINGLETON_INSTANCE.getTabLabel().setText((isTextDirty ? "*" : "") + "Card Script");
}
public void showCard(PaperCard card) {
if (this.currentCard == card) { return; }
this.currentCard = card;
String text = "";
boolean editable = false;
File sourceFile = card.getRules().getSourceFile();
if (sourceFile != null) {
try {
text = FileUtil.readFileToString(sourceFile);
editable = true;
}
catch (final Exception ex) {
text = "Couldn't read file - " + sourceFile + "\n\nException:\n" + ex.toString();
}
}
this.baseText = text;
JTextArea tarScript = VCardScript.SINGLETON_INSTANCE.getTarScript();
tarScript.setText(text);
tarScript.setEditable(editable);
tarScript.setCaretPosition(0); //keep scrolled to top
}
public void saveChanges() {
if (this.currentCard == null || !this.isTextDirty) { return; } //not need if text hasn't been changed
File sourceFile = this.currentCard.getRules().getSourceFile();
if (sourceFile == null) { return; }
try {
String text = VCardScript.SINGLETON_INSTANCE.getTarScript().getText();
PrintWriter p = new PrintWriter(sourceFile);
p.print(text);
p.close();
this.baseText = text;
updateDirtyFlag();
} catch (final Exception ex) {
BugReporter.reportException(ex);
throw new RuntimeException("FileUtil : writeFile() error, problem writing file - " + sourceFile + " : " + ex);
}
}
//========== Overridden methods
/* (non-Javadoc)
* @see forge.gui.framework.ICDoc#getCommandOnSelect()
*/
@Override
public Command getCommandOnSelect() {
return null;
}
/* (non-Javadoc)
* @see forge.gui.framework.ICDoc#initialize()
*/
@Override
public void initialize() {
}
/* (non-Javadoc)
* @see forge.gui.framework.ICDoc#update()
*/
@Override
public void update() {
}
}

View File

@@ -0,0 +1,555 @@
package forge.gui.workshop.controllers;
import java.awt.Toolkit;
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.Map;
import java.util.Set;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JSpinner;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.apache.commons.lang3.tuple.Pair;
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.game.GameFormat;
import forge.gui.GuiUtils;
import forge.gui.workshop.views.VWorkshopCatalog;
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.gui.toolbox.itemmanager.SFilterUtil;
import forge.gui.toolbox.itemmanager.SItemManagerUtil;
import forge.gui.toolbox.itemmanager.SItemManagerUtil.StatTypes;
import forge.gui.toolbox.itemmanager.table.SColumnUtil;
import forge.gui.toolbox.itemmanager.table.TableColumnInfo;
import forge.gui.toolbox.itemmanager.table.SColumnUtil.ColumnName;
import forge.item.InventoryItem;
import forge.item.PaperCard;
import forge.item.ItemPredicate;
import forge.quest.QuestWorld;
import forge.quest.data.GameFormatQuest;
/**
* Controls the "card catalog" panel in the workshop UI.
*
* <br><br><i>(C at beginning of class name denotes a control class.)</i>
*
*/
public enum CWorkshopCatalog implements ICDoc {
/** */
SINGLETON_INSTANCE;
private final Set<Predicate<PaperCard>> activePredicates = new HashSet<Predicate<PaperCard>>();
private final Set<GameFormat> activeFormats = new HashSet<GameFormat>();
private final Set<QuestWorld> activeWorlds = new HashSet<QuestWorld>();
private final Set<RangeTypes> activeRanges = EnumSet.noneOf(RangeTypes.class);
private boolean disableFiltering = false;
private CWorkshopCatalog() {
}
//========== Overridden methods
/* (non-Javadoc)
* @see forge.gui.framework.ICDoc#getCommandOnSelect()
*/
@Override
public Command getCommandOnSelect() {
return null;
}
/* (non-Javadoc)
* @see forge.gui.framework.ICDoc#initialize()
*/
@Override
@SuppressWarnings("serial")
public void initialize() {
final Command updateFilterCommand = new Command() {
@Override
public void run() {
if (!disableFiltering) {
applyCurrentFilter();
}
}
};
for (Map.Entry<SItemManagerUtil.StatTypes, FLabel> entry : VWorkshopCatalog.SINGLETON_INSTANCE.getStatLabels().entrySet()) {
final FLabel statLabel = entry.getValue();
statLabel.setCommand(updateFilterCommand);
//hook so right-clicking a filter in a group toggles itself off and toggles on all other filters in group
final SItemManagerUtil.StatTypes st = entry.getKey();
final int group = st.group;
if (group > 0) {
statLabel.setRightClickCommand(new Command() {
@Override
public void run() {
if (!disableFiltering) {
disableFiltering = true;
boolean foundSelected = false;
for (SItemManagerUtil.StatTypes s : SItemManagerUtil.StatTypes.values()) {
if (s.group == group && s != st) {
FLabel lbl = VWorkshopCatalog.SINGLETON_INSTANCE.getCardManager().getStatLabel(s);
if (lbl.getSelected()) {
foundSelected = true;
lbl.setSelected(false);
}
}
}
if (!statLabel.getSelected()) {
statLabel.setSelected(true);
}
else if (!foundSelected) {
//if statLabel only label in group selected, re-select all other labels in group
for (SItemManagerUtil.StatTypes s : SItemManagerUtil.StatTypes.values()) {
if (s.group == group && s != st) {
FLabel lbl = VWorkshopCatalog.SINGLETON_INSTANCE.getCardManager().getStatLabel(s);
if (!lbl.getSelected()) {
lbl.setSelected(true);
}
}
}
}
disableFiltering = false;
applyCurrentFilter();
}
}
});
}
}
VWorkshopCatalog.SINGLETON_INSTANCE.getStatLabels().get(SItemManagerUtil.StatTypes.TOTAL).setCommand(new Command() {
private boolean lastToggle = true;
@Override
public void run() {
disableFiltering = true;
lastToggle = !lastToggle;
for (SItemManagerUtil.StatTypes s : SItemManagerUtil.StatTypes.values()) {
if (SItemManagerUtil.StatTypes.TOTAL != s) {
VWorkshopCatalog.SINGLETON_INSTANCE.getCardManager().getStatLabel(s).setSelected(lastToggle);
}
}
disableFiltering = false;
applyCurrentFilter();
}
});
// assemble add restriction menu
final Command addRestrictionCommand = new Command() {
@Override
public void run() {
JPopupMenu popup = new JPopupMenu("RestrictionPopupMenu");
GuiUtils.addMenuItem(popup, "Current text search",
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
new Runnable() {
@Override
public void run() {
addRestriction(buildSearchRestriction(), null, null);
}
}, canSearch());
JMenu fmt = new JMenu("Format");
for (final GameFormat f : Singletons.getModel().getFormats()) {
GuiUtils.addMenuItem(fmt, f.getName(), null, new Runnable() {
@Override
public void run() {
addRestriction(buildFormatRestriction(f.toString(), f, true), activeFormats, f);
}
}, !isActive(activeFormats, f));
}
popup.add(fmt);
GuiUtils.addMenuItem(popup, "Sets...", null, new Runnable() {
@Override
public void run() {
final DialogChooseSets dialog = new DialogChooseSets(null, null, true);
dialog.setOkCallback(new Runnable() {
@Override
public void run() {
List<String> setCodes = dialog.getSelectedSets();
if (setCodes.isEmpty()) {
return;
}
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(buildSetRestriction(label.toString(), setCodes, dialog.getWantReprints()), null, null);
}
});
}
});
JMenu range = new JMenu("Value range");
for (final RangeTypes t : RangeTypes.values()) {
GuiUtils.addMenuItem(range, t.toLabelString() + " restriction", null, new Runnable() {
@Override
public void run() {
addRestriction(buildRangeRestriction(t), activeRanges, t);
}
}, !isActive(activeRanges, t));
}
popup.add(range);
JMenu world = new JMenu("Quest world");
for (final QuestWorld w : Singletons.getModel().getWorlds()) {
GameFormatQuest format = w.getFormat();
if (null == format) {
// assumes that no world other than the main world will have a null format
format = Singletons.getModel().getQuest().getMainFormat();
}
final GameFormatQuest f = format;
GuiUtils.addMenuItem(world, w.getName(), null, new Runnable() {
@Override
public void run() {
addRestriction(buildFormatRestriction(w.getName(), f, true), activeWorlds, w);
}
}, !isActive(activeWorlds, w) && null != f);
}
popup.add(world);
popup.show(VWorkshopCatalog.SINGLETON_INSTANCE.getBtnAddRestriction(), 0,
VWorkshopCatalog.SINGLETON_INSTANCE.getBtnAddRestriction().getHeight());
}
};
FLabel btnAddRestriction = VWorkshopCatalog.SINGLETON_INSTANCE.getBtnAddRestriction();
btnAddRestriction.setCommand(addRestrictionCommand);
btnAddRestriction.setRightClickCommand(addRestrictionCommand); //show menu on right-click too
VWorkshopCatalog.SINGLETON_INSTANCE.getCbSearchMode().addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent arg0) {
applyCurrentFilter();
}
});
Runnable addSearchRestriction = new Runnable() {
@Override
public void run() {
if (canSearch()) {
addRestriction(buildSearchRestriction(), null, null);
}
}
};
// add search restriction on ctrl-enter from either the textbox or combobox
VWorkshopCatalog.SINGLETON_INSTANCE.getCbSearchMode().addKeyListener(new _OnCtrlEnter(addSearchRestriction));
VWorkshopCatalog.SINGLETON_INSTANCE.getTxfSearch().addKeyListener(new _OnCtrlEnter(addSearchRestriction) {
private boolean keypressPending;
@Override
public void keyReleased(KeyEvent e) {
if (KeyEvent.VK_ENTER == e.getKeyCode() && 0 == e.getModifiers()) {
// set focus to table when a plain enter is typed into the text filter box
VWorkshopCatalog.SINGLETON_INSTANCE.getCardManager().getTable().requestFocusInWindow();
} else if (keypressPending) {
// do this in keyReleased instead of keyTyped since the textbox text isn't updated until the key is released
// but depend on keypressPending since otherwise we pick up hotkeys and other unwanted stuff
applyCurrentFilter();
}
}
@Override
public void keyPressed(KeyEvent e) {
super.keyPressed(e);
keypressPending = KeyEvent.VK_ENTER != e.getKeyCode();
}
});
VWorkshopCatalog.SINGLETON_INSTANCE.getLblName().setCommand(updateFilterCommand);
VWorkshopCatalog.SINGLETON_INSTANCE.getLblType().setCommand(updateFilterCommand);
VWorkshopCatalog.SINGLETON_INSTANCE.getLblText().setCommand(updateFilterCommand);
// ensure mins can's exceed maxes and maxes can't fall below mins
for (Pair<FSpinner, FSpinner> sPair : VWorkshopCatalog.SINGLETON_INSTANCE.getSpinners().values()) {
final FSpinner min = sPair.getLeft();
final FSpinner max = sPair.getRight();
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();
}
});
}
}
private class _OnCtrlEnter extends KeyAdapter {
private final Runnable action;
_OnCtrlEnter(Runnable action) {
this.action = action;
}
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == 10) {
if (e.isControlDown() || e.isMetaDown()) {
action.run();
}
}
}
}
/* (non-Javadoc)
* @see forge.gui.framework.ICDoc#update()
*/
@Override
public void update() {
final List<TableColumnInfo<InventoryItem>> lstCatalogCols = SColumnUtil.getCatalogDefaultColumns();
lstCatalogCols.remove(SColumnUtil.getColumn(ColumnName.CAT_QUANTITY));
VWorkshopCatalog.SINGLETON_INSTANCE.getCardManager().getTable().setup(lstCatalogCols);
}
public void applyCurrentFilter() {
// The main trick here is to apply a CardPrinted predicate
// to the table. CardRules will lead to difficulties.
List<Predicate<? super PaperCard>> cardPredicates = new ArrayList<Predicate<? super PaperCard>>();
cardPredicates.add(Predicates.instanceOf(PaperCard.class));
cardPredicates.add(SFilterUtil.buildColorAndTypeFilter(VWorkshopCatalog.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(VWorkshopCatalog.SINGLETON_INSTANCE.getSpinners(), t));
}
}
// get the current contents of the search box
cardPredicates.add(SFilterUtil.buildTextFilter(
VWorkshopCatalog.SINGLETON_INSTANCE.getTxfSearch().getText(),
0 != VWorkshopCatalog.SINGLETON_INSTANCE.getCbSearchMode().getSelectedIndex(),
VWorkshopCatalog.SINGLETON_INSTANCE.getLblName().getSelected(),
VWorkshopCatalog.SINGLETON_INSTANCE.getLblType().getSelected(),
VWorkshopCatalog.SINGLETON_INSTANCE.getLblText().getSelected()));
Predicate<PaperCard> cardFilter = Predicates.and(cardPredicates);
// show packs and decks in the card shop according to the toggle setting
// this is special-cased apart from the buildColorAndTypeFilter() above
if (VWorkshopCatalog.SINGLETON_INSTANCE.getCardManager().getStatLabel(StatTypes.PACK).getSelected()) {
List<Predicate<? super PaperCard>> itemPredicates = new ArrayList<Predicate<? super PaperCard>>();
itemPredicates.add(cardFilter);
itemPredicates.add(ItemPredicate.Presets.IS_PACK);
itemPredicates.add(ItemPredicate.Presets.IS_DECK);
cardFilter = Predicates.or(itemPredicates);
}
// Apply to table
VWorkshopCatalog.SINGLETON_INSTANCE.getCardManager().setFilterPredicate(cardFilter);
}
private boolean canSearch() {
return !VWorkshopCatalog.SINGLETON_INSTANCE.getTxfSearch().getText().isEmpty() &&
(VWorkshopCatalog.SINGLETON_INSTANCE.getLblName().getSelected() ||
VWorkshopCatalog.SINGLETON_INSTANCE.getLblType().getSelected() ||
VWorkshopCatalog.SINGLETON_INSTANCE.getLblText().getSelected());
}
private <T> boolean isActive(Set<T> activeSet, T key) {
return activeSet.contains(key);
}
@SuppressWarnings("serial")
private <T> void addRestriction(Pair<? extends JComponent, Predicate<PaperCard>> restriction, final Set<T> activeSet, final T key) {
final Predicate<PaperCard> predicate = restriction.getRight();
if (null != predicate && activePredicates.contains(predicate)) {
return;
}
VWorkshopCatalog.SINGLETON_INSTANCE.addRestrictionWidget(restriction.getLeft(), new Command() {
@Override
public void run() {
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<JPanel, Predicate<PaperCard>> buildRangeRestriction(RangeTypes t) {
final Pair<FSpinner, FSpinner> s = VWorkshopCatalog.SINGLETON_INSTANCE.getSpinners().get(t);
s.getLeft().setValue(0);
s.getRight().setValue(10);
// set focus to lower bound widget
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
((JSpinner.DefaultEditor)s.getLeft().getEditor()).getTextField().requestFocusInWindow();
}
});
return Pair.of(VWorkshopCatalog.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<FLabel, Predicate<PaperCard>> buildSearchRestriction() {
boolean isInverse =
VWorkshopCatalog.SEARCH_MODE_INVERSE_INDEX == VWorkshopCatalog.SINGLETON_INSTANCE.getCbSearchMode().getSelectedIndex();
String text = VWorkshopCatalog.SINGLETON_INSTANCE.getTxfSearch().getText();
boolean wantName = VWorkshopCatalog.SINGLETON_INSTANCE.getLblName().getSelected();
boolean wantType = VWorkshopCatalog.SINGLETON_INSTANCE.getLblType().getSelected();
boolean wantText = VWorkshopCatalog.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);
}
VWorkshopCatalog.SINGLETON_INSTANCE.getTxfSearch().setText("");
return Pair.of(
VWorkshopCatalog.SINGLETON_INSTANCE.buildPlainRestrictionWidget(shortText, fullText),
SFilterUtil.buildTextFilter(text, isInverse, wantName, wantType, wantText));
}
private Pair<FLabel, Predicate<PaperCard>> buildFormatRestriction(String displayName, GameFormat format, boolean allowReprints) {
EditionCollection editions = Singletons.getModel().getEditions();
StringBuilder tooltip = new StringBuilder("<html>Sets:");
int lastLen = 0;
int lineLen = 0;
// use HTML tooltips so we can insert line breaks
List<String> sets = 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("<br>");
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());
if (allowReprints) {
tooltip.append("<br><br>Allowing identical cards from other sets");
}
}
List<String> bannedCards = format.getBannedCardNames();
if (null != bannedCards && !bannedCards.isEmpty()) {
tooltip.append("<br><br>Banned:");
lastLen += lineLen;
lineLen = 0;
for (String cardName : bannedCards) {
// don't let a single line get too long
if (50 < lineLen) {
tooltip.append("<br>");
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("</html>");
return Pair.of(
VWorkshopCatalog.SINGLETON_INSTANCE.buildPlainRestrictionWidget(displayName, tooltip.toString()),
allowReprints ? format.getFilterRules() : format.getFilterPrinted());
}
private Pair<FLabel, Predicate<PaperCard>> buildSetRestriction(String displayName, List<String> setCodes, boolean allowReprints) {
return buildFormatRestriction(displayName, new GameFormat(null, setCodes, null), allowReprints);
}
}

View File

@@ -0,0 +1,102 @@
package forge.gui.workshop.views;
import java.awt.Dimension;
import javax.swing.JPanel;
import javax.swing.SpringLayout;
import forge.gui.framework.DragCell;
import forge.gui.framework.DragTab;
import forge.gui.framework.EDocID;
import forge.gui.framework.IVDoc;
import forge.gui.toolbox.FLabel;
import forge.gui.toolbox.FSkin;
import forge.gui.workshop.controllers.CCardDesigner;
/**
* Assembles Swing components of workshop card designer tab.
*
* <br><br><i>(V at beginning of class name denotes a view class.)</i>
*/
public enum VCardDesigner implements IVDoc<CCardDesigner> {
/** */
SINGLETON_INSTANCE;
// Fields used with interface IVDoc
private DragCell parentCell;
private final DragTab tab = new DragTab("Card Designer");
private FLabel btnSaveCard = new FLabel.Builder()
.opaque(true).hoverable(true)
.text("Save and Apply Card Changes")
.icon(FSkin.getIcon(FSkin.InterfaceIcons.ICO_SAVE))
.enabled(false) //disabled by default until card changes made
.build();
//========== Constructor
private VCardDesigner() {
}
public FLabel getBtnSaveCard() {
return btnSaveCard;
}
//========== Overridden methods
/* (non-Javadoc)
* @see forge.gui.framework.IVDoc#getDocumentID()
*/
@Override
public EDocID getDocumentID() {
return EDocID.WORKSHOP_CARDDESIGNER;
}
/* (non-Javadoc)
* @see forge.gui.framework.IVDoc#getTabLabel()
*/
@Override
public DragTab getTabLabel() {
return tab;
}
/* (non-Javadoc)
* @see forge.gui.framework.IVDoc#getLayoutControl()
*/
@Override
public CCardDesigner getLayoutControl() {
return CCardDesigner.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() {
JPanel body = parentCell.getBody();
SpringLayout layout = new SpringLayout();
body.setLayout(layout);
layout.putConstraint(SpringLayout.SOUTH, btnSaveCard, -6, SpringLayout.SOUTH, body);
layout.putConstraint(SpringLayout.WEST, btnSaveCard, 6, SpringLayout.WEST, body);
layout.putConstraint(SpringLayout.EAST, btnSaveCard, -6, SpringLayout.EAST, body);
btnSaveCard.setPreferredSize(new Dimension(60, 30));
body.add(btnSaveCard);
//body.setLayout(new MigLayout("insets 1, gap 0, wrap"));
//body.add(btnSaveCard, "w 100% - 12, h 30px!, ay bottom, gap 6");
}
}

View File

@@ -0,0 +1,101 @@
package forge.gui.workshop.views;
import java.awt.Insets;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import net.miginfocom.swing.MigLayout;
import forge.gui.framework.DragCell;
import forge.gui.framework.DragTab;
import forge.gui.framework.EDocID;
import forge.gui.framework.IVDoc;
import forge.gui.toolbox.FSkin;
import forge.gui.workshop.controllers.CCardScript;
/**
* Assembles Swing components of workshop card script tab.
*
* <br><br><i>(V at beginning of class name denotes a view class.)</i>
*/
public enum VCardScript implements IVDoc<CCardScript> {
/** */
SINGLETON_INSTANCE;
// Fields used with interface IVDoc
private DragCell parentCell;
private final DragTab tab = new DragTab("Card Script");
private final JTextArea tarScript = new JTextArea();
private final JScrollPane scroller;
//========== Constructor
private VCardScript() {
FSkin.JTextComponentSkin<JTextArea> txtScriptSkin = FSkin.get(tarScript);
txtScriptSkin.setFont(FSkin.getFixedFont(16));
txtScriptSkin.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
txtScriptSkin.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2));
txtScriptSkin.setCaretColor(FSkin.getColor(FSkin.Colors.CLR_TEXT));
tarScript.setMargin(new Insets(3, 3, 3, 3));
scroller = new JScrollPane(tarScript);
scroller.setBorder(null);
scroller.setOpaque(false);
}
public JTextArea getTarScript() {
return tarScript;
}
//========== Overridden methods
/* (non-Javadoc)
* @see forge.gui.framework.IVDoc#getDocumentID()
*/
@Override
public EDocID getDocumentID() {
return EDocID.WORKSHOP_CARDSCRIPT;
}
/* (non-Javadoc)
* @see forge.gui.framework.IVDoc#getTabLabel()
*/
@Override
public DragTab getTabLabel() {
return tab;
}
/* (non-Javadoc)
* @see forge.gui.framework.IVDoc#getLayoutControl()
*/
@Override
public CCardScript getLayoutControl() {
return CCardScript.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() {
JPanel body = parentCell.getBody();
body.setLayout(new MigLayout("insets 1, gap 0, wrap"));
body.add(scroller, "w 100%, h 100%");
}
}

View File

@@ -0,0 +1,270 @@
package forge.gui.workshop.views;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import net.miginfocom.swing.MigLayout;
import org.apache.commons.lang3.tuple.Pair;
import forge.Command;
import forge.card.CardDb;
import forge.gui.WrapLayout;
import forge.gui.deckeditor.views.VCardCatalog.RangeTypes;
import forge.gui.framework.DragCell;
import forge.gui.framework.DragTab;
import forge.gui.framework.EDocID;
import forge.gui.framework.IVDoc;
import forge.gui.match.controllers.CDetail;
import forge.gui.match.controllers.CPicture;
import forge.gui.toolbox.FComboBoxWrapper;
import forge.gui.toolbox.FLabel;
import forge.gui.toolbox.FSkin;
import forge.gui.toolbox.FSpinner;
import forge.gui.toolbox.FTextField;
import forge.gui.toolbox.itemmanager.CardManager;
import forge.gui.toolbox.itemmanager.ItemManagerContainer;
import forge.gui.toolbox.itemmanager.SItemManagerUtil;
import forge.gui.workshop.controllers.CCardScript;
import forge.gui.workshop.controllers.CWorkshopCatalog;
import forge.item.ItemPool;
import forge.item.PaperCard;
/**
* Assembles Swing components of card catalog in workshop.
*
* <br><br><i>(V at beginning of class name denotes a view class.)</i>
*
*/
public enum VWorkshopCatalog implements IVDoc<CWorkshopCatalog> {
/** */
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/filter toggles
private final Dimension labelSize = new Dimension(60, 24);
private final JPanel pnlStats = new JPanel(new WrapLayout(FlowLayout.LEFT));
private final Map<SItemManagerUtil.StatTypes, FLabel> statLabels =
new HashMap<SItemManagerUtil.StatTypes, FLabel>();
// restriction button and search widgets
private final JPanel pnlSearch = new JPanel(new MigLayout("insets 0, gap 5px, center"));
private final FLabel btnAddRestriction = new FLabel.ButtonBuilder()
.text("Add filter")
.tooltip("Click to add custom filters to the card list")
.reactOnMouseDown().build();
private final FComboBoxWrapper<String> cbSearchMode = new FComboBoxWrapper<String>();
private final JTextField txfSearch = new FTextField.Builder().ghostText("Search").build();
private final FLabel lblName = new FLabel.Builder().text("Name").hoverable().selectable().selected().build();
private final FLabel lblType = new FLabel.Builder().text("Type").hoverable().selectable().selected().build();
private final FLabel lblText = new FLabel.Builder().text("Text").hoverable().selectable().selected().build();
private final JPanel pnlRestrictions = new JPanel(new WrapLayout(FlowLayout.LEFT, 10, 5));
private final ItemManagerContainer cardManagerContainer = new ItemManagerContainer();
private final CardManager cardManager;
private final Map<RangeTypes, Pair<FSpinner, FSpinner>> spinners = new HashMap<RangeTypes, Pair<FSpinner, FSpinner>>();
//========== Constructor
/** */
private VWorkshopCatalog() {
pnlStats.setOpaque(false);
for (SItemManagerUtil.StatTypes s : SItemManagerUtil.StatTypes.values()) {
FLabel label = buildToggleLabel(s, SItemManagerUtil.StatTypes.TOTAL != s);
statLabels.put(s, label);
JComponent component = label;
if (SItemManagerUtil.StatTypes.TOTAL == s) {
label.setToolTipText("Total cards (click to toggle all filters)");
} else if (SItemManagerUtil.StatTypes.PACK == s) {
// wrap in a constant-size panel so we can change its visibility without affecting layout
component = new JPanel(new MigLayout("insets 0, gap 0"));
component.setPreferredSize(labelSize);
component.setMinimumSize(labelSize);
component.setOpaque(false);
label.setVisible(false);
component.add(label);
}
pnlStats.add(component);
}
pnlSearch.setOpaque(false);
pnlSearch.add(btnAddRestriction, "center, w pref+8, h pref+8");
pnlSearch.add(txfSearch, "pushx, growx");
cbSearchMode.addItem("in");
cbSearchMode.addItem("not in");
cbSearchMode.addTo(pnlSearch, "center");
pnlSearch.add(lblName, "w pref+8, h pref+8");
pnlSearch.add(lblType, "w pref+8, h pref+8");
pnlSearch.add(lblText, "w pref+8, h pref+8");
pnlRestrictions.setOpaque(false);
// fill spinner map
for (RangeTypes t : RangeTypes.values()) {
FSpinner lowerBound = new FSpinner.Builder().maxValue(10).build();
FSpinner upperBound = new FSpinner.Builder().maxValue(10).build();
_setupSpinner(lowerBound);
_setupSpinner(upperBound);
spinners.put(t, Pair.of(lowerBound, upperBound));
}
this.cardManager = new CardManager(this.statLabels, true);
this.cardManager.setPool(ItemPool.createFrom(CardDb.instance().getAllCards(), PaperCard.class), true);
this.cardManagerContainer.setItemManager(this.cardManager);
this.cardManager.addSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
PaperCard card = cardManager.getSelectedItem();
CDetail.SINGLETON_INSTANCE.showCard(card);
CPicture.SINGLETON_INSTANCE.showImage(card);
CCardScript.SINGLETON_INSTANCE.showCard(card);
}
});
}
private void _setupSpinner (JSpinner spinner) {
spinner.setFocusable(false); // only the spinner text field should be focusable, not the up/down widget
}
//========== Overridden from IVDoc
@Override
public EDocID getDocumentID() {
return EDocID.WORKSHOP_CATALOG;
}
@Override
public DragTab getTabLabel() {
return tab;
}
@Override
public CWorkshopCatalog getLayoutControl() {
return CWorkshopCatalog.SINGLETON_INSTANCE;
}
@Override
public void setParentCell(DragCell cell0) {
this.parentCell = cell0;
}
@Override
public DragCell getParentCell() {
return this.parentCell;
}
@Override
public void populate() {
JPanel parentBody = parentCell.getBody();
parentBody.setLayout(new MigLayout("insets 0, gap 0, wrap, hidemode 3"));
parentBody.add(pnlStats, "w 100:520:520, center");
parentBody.add(pnlSearch, "w 96%, gap 1% 1%");
parentBody.add(pnlRestrictions, "w 96%, gapleft 1%, gapright push");
parentBody.add(cardManagerContainer, "w 98%!, h 100% - 35, gap 1% 0 0 1%");
}
//========== Accessor/mutator methods
public FLabel getLblName() { return lblName; }
public FLabel getLblType() { return lblType; }
public FLabel getLblText() { return lblText; }
public FLabel getBtnAddRestriction() { return btnAddRestriction; }
public FComboBoxWrapper<String> getCbSearchMode() { return cbSearchMode; }
public JTextField getTxfSearch() { return txfSearch; }
public CardManager getCardManager() {
return cardManager;
}
public Map<SItemManagerUtil.StatTypes, FLabel> getStatLabels() {
return statLabels;
}
public Map<RangeTypes, Pair<FSpinner, FSpinner>> getSpinners() {
return spinners;
}
//========== Other methods
private FLabel buildToggleLabel(SItemManagerUtil.StatTypes s, boolean selectable) {
String tooltip;
if (selectable) { //construct tooltip for selectable toggle labels, indicating click and right-click behavior
String labelString = s.toLabelString();
tooltip = labelString + " (click to toggle the filter, right-click to show only " + labelString.toLowerCase() + ")";
}
else { tooltip = ""; }
FLabel label = new FLabel.Builder()
.icon(s.img).iconScaleAuto(false)
.fontSize(11)
.tooltip(tooltip)
.hoverable().selectable(selectable).selected(selectable)
.build();
label.setPreferredSize(labelSize);
label.setMinimumSize(labelSize);
return label;
}
@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);
FSkin.get(pnl).setMatteBorder(1, 2, 1, 2, FSkin.getColor(FSkin.Colors.CLR_TEXT));
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 run() {
pnlRestrictions.remove(pnl);
refreshRestrictionWidgets();
onRemove.run();
}
}).build(), "top");
pnlRestrictions.add(pnl, "h 30!");
refreshRestrictionWidgets();
}
public void refreshRestrictionWidgets() {
Container parent = pnlRestrictions.getParent();
pnlRestrictions.validate();
parent.validate();
parent.repaint();
}
public JPanel buildRangeRestrictionWidget(RangeTypes t) {
JPanel pnl = new JPanel(new MigLayout("insets 0, gap 2"));
pnl.setOpaque(false);
Pair<FSpinner, FSpinner> s = spinners.get(t);
pnl.add(s.getLeft(), "w 45!, h 26!, center");
pnl.add(new FLabel.Builder().text("<=").fontSize(11).build(), "h 26!, center");
pnl.add(new FLabel.Builder().text(t.toLabelString()).fontSize(11).build(), "h 26!, center");
pnl.add(new FLabel.Builder().text("<=").fontSize(11).build(), "h 26!, center");
pnl.add(s.getRight(), "w 45!, h 26!, center");
return pnl;
}
public FLabel buildPlainRestrictionWidget(String label, String tooltip) {
return new FLabel.Builder().text(label).tooltip(tooltip).fontSize(11).build();
}
}

View File

@@ -88,6 +88,7 @@ public final class NewConstants {
public static final FileLocation EDITOR_PREFERENCES_FILE = new FileLocation(_DEFAULTS_DIR, USER_PREFS_DIR, "editor.preferences");
public static final FileLocation WINDOW_LAYOUT_FILE = new FileLocation(_DEFAULTS_DIR, USER_PREFS_DIR, "window.xml");
public static final FileLocation MATCH_LAYOUT_FILE = new FileLocation(_DEFAULTS_DIR, USER_PREFS_DIR, "match.xml");
public static final FileLocation WORKSHOP_LAYOUT_FILE = new FileLocation(_DEFAULTS_DIR, USER_PREFS_DIR, "workshop.xml");
public static final FileLocation EDITOR_LAYOUT_FILE = new FileLocation(_DEFAULTS_DIR, USER_PREFS_DIR, "editor.xml");
public static final FileLocation GAUNTLET_DIR = new FileLocation(_DEFAULTS_DIR, USER_DIR, "gauntlet/");

View File

@@ -115,15 +115,22 @@ public final class FileUtil {
} // writeAllDecks()
public static String readFileToString(String filename) {
return readFileToString(new File(filename));
}
public static String readFileToString(File file) {
StringBuilder s = new StringBuilder();
for (String line : readFile(filename)) {
s.append(line).append('\n');
for (String line : readFile(file)) {
if (s.length() > 0) {
s.append('\n');
}
s.append(line);
}
return s.toString();
}
public static List<String> readFile(final String filename) {
return FileUtil.readFile(new File(filename));
return readFile(new File(filename));
}
// reads line by line and adds each line to the ArrayList

View File

@@ -89,6 +89,7 @@ public class FNavigationBar extends FTitleBarBase {
addNavigationTab(FScreen.HOME_SCREEN);
addNavigationTab(FScreen.DECK_EDITOR_CONSTRUCTED);
addNavigationTab(FScreen.WORKSHOP_SCREEN);
super.addControls();