diff --git a/.gitattributes b/.gitattributes
index 74f7e73cd45..261b4f13026 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -13468,6 +13468,7 @@ forge-gui/res/defaults/gauntlet/LOCKED_Swimming[!!-~]With[!!-~]Sharks.dat -text
forge-gui/res/defaults/home.xml svneol=native#text/xml
forge-gui/res/defaults/match.xml svneol=native#text/xml
forge-gui/res/defaults/window.xml -text
+forge-gui/res/defaults/workshop.xml -text
forge-gui/res/draft/cube_juzamjedi.draft -text
forge-gui/res/draft/cube_skiera.draft -text
forge-gui/res/draft/rankings.txt -text
@@ -15457,6 +15458,15 @@ forge-gui/src/main/java/forge/gui/toolbox/special/PhaseIndicator.java -text
forge-gui/src/main/java/forge/gui/toolbox/special/PhaseLabel.java -text
forge-gui/src/main/java/forge/gui/toolbox/special/PlayerDetailsPanel.java -text
forge-gui/src/main/java/forge/gui/toolbox/special/package-info.java -text
+forge-gui/src/main/java/forge/gui/workshop/CWorkshopUI.java -text
+forge-gui/src/main/java/forge/gui/workshop/SWorkshopIO.java -text
+forge-gui/src/main/java/forge/gui/workshop/VWorkshopUI.java -text
+forge-gui/src/main/java/forge/gui/workshop/controllers/CCardDesigner.java -text
+forge-gui/src/main/java/forge/gui/workshop/controllers/CCardScript.java -text
+forge-gui/src/main/java/forge/gui/workshop/controllers/CWorkshopCatalog.java -text
+forge-gui/src/main/java/forge/gui/workshop/views/VCardDesigner.java -text
+forge-gui/src/main/java/forge/gui/workshop/views/VCardScript.java -text
+forge-gui/src/main/java/forge/gui/workshop/views/VWorkshopCatalog.java -text
forge-gui/src/main/java/forge/item/BoosterPack.java -text
forge-gui/src/main/java/forge/item/FatPack.java -text
forge-gui/src/main/java/forge/item/IPaperCard.java -text
diff --git a/forge-gui/res/defaults/workshop.xml b/forge-gui/res/defaults/workshop.xml
new file mode 100644
index 00000000000..8d63d994d70
--- /dev/null
+++ b/forge-gui/res/defaults/workshop.xml
@@ -0,0 +1,18 @@
+
+
+ |
+ WORKSHOP_CATALOG
+ |
+
+ WORKSHOP_CARDDESIGNER
+ |
+
+ WORKSHOP_CARDSCRIPT
+ |
+
+ CARD_DETAIL
+ |
+
+ CARD_PICTURE
+ |
+
diff --git a/forge-gui/src/main/java/forge/card/CardRules.java b/forge-gui/src/main/java/forge/card/CardRules.java
index 411f59b026c..6e40c0b556b 100644
--- a/forge-gui/src/main/java/forge/card/CardRules.java
+++ b/forge-gui/src/main/java/forge/card/CardRules.java
@@ -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 setsPrinted = new TreeMap(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;
}
}
diff --git a/forge-gui/src/main/java/forge/card/CardRulesReader.java b/forge-gui/src/main/java/forge/card/CardRulesReader.java
index d434c80cc0b..58af9ff48aa 100644
--- a/forge-gui/src/main/java/forge/card/CardRulesReader.java
+++ b/forge-gui/src/main/java/forge/card/CardRulesReader.java
@@ -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)
diff --git a/forge-gui/src/main/java/forge/card/cardfactory/CardStorageReader.java b/forge-gui/src/main/java/forge/card/cardfactory/CardStorageReader.java
index c6b8ef73a88..3e1d98f1a4e 100644
--- a/forge-gui/src/main/java/forge/card/cardfactory/CardStorageReader.java
+++ b/forge-gui/src/main/java/forge/card/cardfactory/CardStorageReader.java
@@ -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();
diff --git a/forge-gui/src/main/java/forge/gui/deckeditor/CDeckEditorUI.java b/forge-gui/src/main/java/forge/gui/deckeditor/CDeckEditorUI.java
index f55f4aaed6f..87dfd2ce4f8 100644
--- a/forge-gui/src/main/java/forge/gui/deckeditor/CDeckEditorUI.java
+++ b/forge-gui/src/main/java/forge/gui/deckeditor/CDeckEditorUI.java
@@ -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> 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;
}
diff --git a/forge-gui/src/main/java/forge/gui/framework/EDocID.java b/forge-gui/src/main/java/forge/gui/framework/EDocID.java
index 540e98ba0c1..1e0bd95a82c 100644
--- a/forge-gui/src/main/java/forge/gui/framework/EDocID.java
+++ b/forge-gui/src/main/java/forge/gui/framework/EDocID.java
@@ -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), /** */
diff --git a/forge-gui/src/main/java/forge/gui/framework/FScreen.java b/forge-gui/src/main/java/forge/gui/framework/FScreen.java
index aeefa7c26ed..78ace213e9b 100644
--- a/forge-gui/src/main/java/forge/gui/framework/FScreen.java
+++ b/forge-gui/src/main/java/forge/gui/framework/FScreen.java
@@ -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,
diff --git a/forge-gui/src/main/java/forge/gui/home/settings/CSubmenuPreferences.java b/forge-gui/src/main/java/forge/gui/home/settings/CSubmenuPreferences.java
index 1853889133b..5d1dac1e72c 100644
--- a/forge-gui/src/main/java/forge/gui/home/settings/CSubmenuPreferences.java
+++ b/forge-gui/src/main/java/forge/gui/home/settings/CSubmenuPreferences.java
@@ -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" +
diff --git a/forge-gui/src/main/java/forge/gui/home/settings/VSubmenuPreferences.java b/forge-gui/src/main/java/forge/gui/home/settings/VSubmenuPreferences.java
index 8e55e7cd05c..daa6dbfd2e7 100644
--- a/forge-gui/src/main/java/forge/gui/home/settings/VSubmenuPreferences.java
+++ b/forge-gui/src/main/java/forge/gui/home/settings/VSubmenuPreferences.java
@@ -62,6 +62,7 @@ public enum VSubmenuPreferences implements IVSubmenu {
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 {
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 {
public final FLabel getBtnDeleteEditorUI() {
return btnDeleteEditorUI;
}
+
+ public final FLabel getBtnDeleteWorkshopUI() {
+ return btnDeleteWorkshopUI;
+ }
/* (non-Javadoc)
* @see forge.gui.framework.IVDoc#getDocumentID()
diff --git a/forge-gui/src/main/java/forge/gui/home/settings/VSubmenuReleaseNotes.java b/forge-gui/src/main/java/forge/gui/home/settings/VSubmenuReleaseNotes.java
index 29d2c6c6a82..43c8b1376d7 100644
--- a/forge-gui/src/main/java/forge/gui/home/settings/VSubmenuReleaseNotes.java
+++ b/forge-gui/src/main/java/forge/gui/home/settings/VSubmenuReleaseNotes.java
@@ -74,8 +74,6 @@ public enum VSubmenuReleaseNotes implements IVSubmenu {
scroller = new JScrollPane(tar);
pnlMain.add(scroller, "w 100%!, h 100%!");
-
-
}
/* (non-Javadoc)
diff --git a/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/ItemManager.java b/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/ItemManager.java
index 4515b52d22e..17926e816ac 100644
--- a/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/ItemManager.java
+++ b/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/ItemManager.java
@@ -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 extends JPanel {
private final List> orderedFilters = new ArrayList>();
private boolean wantUnique = false;
private boolean alwaysNonUnique = false;
+ private boolean allowMultipleSelections = false;
private final Class genericType;
private final Map statLabels;
+ private final ArrayList selectionListeners = new ArrayList();
private final FLabel btnAddFilter = new FLabel.ButtonBuilder()
.text("Add")
@@ -94,6 +98,7 @@ public abstract class ItemManager extends JPanel {
//build table view
this.table = new ItemTable(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 extends JPanel {
}
@Override
- public void doLayout()
- {
+ public void doLayout() {
//int number = 0;
LayoutHelper helper = new LayoutHelper(this);
/*for (ItemFilter filter : this.orderedFilters) {
@@ -240,7 +244,7 @@ public abstract class ItemManager extends JPanel {
*
* @return InventoryItem
*/
- public InventoryItem getSelectedItem() {
+ public T getSelectedItem() {
return this.table.getSelectedItem();
}
@@ -250,7 +254,7 @@ public abstract class ItemManager extends JPanel {
*
* @return List
*/
- public List getSelectedItems() {
+ public List getSelectedItems() {
return this.table.getSelectedItems();
}
@@ -471,7 +475,7 @@ public abstract class ItemManager 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 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 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 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 getSelectionListeners() {
+ return selectionListeners;
+ }
}
diff --git a/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/table/ItemTable.java b/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/table/ItemTable.java
index dabafb3769b..9084178a8c1 100644
--- a/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/table/ItemTable.java
+++ b/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/table/ItemTable.java
@@ -58,6 +58,10 @@ public final class ItemTable extends JTable {
private final FSkin.JTableSkin> skin;
private final ItemManager itemManager;
private final ItemTableModel tableModel;
+
+ public ItemManager getItemManager() {
+ return this.itemManager;
+ }
public ItemTableModel getTableModel() {
return this.tableModel;
@@ -283,7 +287,7 @@ public final class ItemTable 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 extends JTable {
*
* @return List
*/
- public List getSelectedItems() {
- List items = new ArrayList();
+ public List getSelectedItems() {
+ List items = new ArrayList();
for (int row : getSelectedRows()) {
items.add(tableModel.rowToItem(row).getKey());
}
diff --git a/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/table/ItemTableModel.java b/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/table/ItemTableModel.java
index bbdfd337161..d5fb6ae5653 100644
--- a/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/table/ItemTableModel.java
+++ b/forge-gui/src/main/java/forge/gui/toolbox/itemmanager/table/ItemTableModel.java
@@ -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 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 table) {
final int row = table.getSelectedRow();
if (row != -1) {
- Entry 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 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 extends AbstractTable
private final FocusAdapter focusAdapter = new FocusAdapter() {
@Override
public void focusGained(final FocusEvent e) {
- ItemTableModel.this.showSelectedItem(table);
+ ItemTableModel.this.onSelectionChange(table);
}
};
diff --git a/forge-gui/src/main/java/forge/gui/workshop/CWorkshopUI.java b/forge-gui/src/main/java/forge/gui/workshop/CWorkshopUI.java
new file mode 100644
index 00000000000..29ae40e001b
--- /dev/null
+++ b/forge-gui/src/main/java/forge/gui/workshop/CWorkshopUI.java
@@ -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 .
+ */
+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.
+ *
+ *
(C at beginning of class name denotes a control class.)
+ */
+public enum CWorkshopUI implements ICDoc, IMenuProvider {
+ /** */
+ SINGLETON_INSTANCE;
+
+ private CWorkshopUI() {
+ }
+
+ /* (non-Javadoc)
+ * @see forge.gui.menubar.IMenuProvider#getMenus()
+ */
+ @Override
+ public List 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 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() { }
+}
+
diff --git a/forge-gui/src/main/java/forge/gui/workshop/SWorkshopIO.java b/forge-gui/src/main/java/forge/gui/workshop/SWorkshopIO.java
new file mode 100644
index 00000000000..d32e12a514b
--- /dev/null
+++ b/forge-gui/src/main/java/forge/gui/workshop/SWorkshopIO.java
@@ -0,0 +1,9 @@
+package forge.gui.workshop;
+
+/**
+ * Handles worksho saving and loading.
+ *
+ *
(S at beginning of class name denotes a static factory.)
+ */
+public class SWorkshopIO {
+}
diff --git a/forge-gui/src/main/java/forge/gui/workshop/VWorkshopUI.java b/forge-gui/src/main/java/forge/gui/workshop/VWorkshopUI.java
new file mode 100644
index 00000000000..561026d0e3d
--- /dev/null
+++ b/forge-gui/src/main/java/forge/gui/workshop/VWorkshopUI.java
@@ -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.
+ *
+ *
(V at beginning of class name denotes a view class.)
+ *
+ */
+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;
+ }
+}
diff --git a/forge-gui/src/main/java/forge/gui/workshop/controllers/CCardDesigner.java b/forge-gui/src/main/java/forge/gui/workshop/controllers/CCardDesigner.java
new file mode 100644
index 00000000000..f249f4a60f1
--- /dev/null
+++ b/forge-gui/src/main/java/forge/gui/workshop/controllers/CCardDesigner.java
@@ -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.
+ *
+ *
(C at beginning of class name denotes a control class.)
+ *
+ */
+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() {
+ }
+}
diff --git a/forge-gui/src/main/java/forge/gui/workshop/controllers/CCardScript.java b/forge-gui/src/main/java/forge/gui/workshop/controllers/CCardScript.java
new file mode 100644
index 00000000000..a2076b6823e
--- /dev/null
+++ b/forge-gui/src/main/java/forge/gui/workshop/controllers/CCardScript.java
@@ -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.
+ *
+ *
(C at beginning of class name denotes a control class.)
+ *
+ */
+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() {
+ }
+}
diff --git a/forge-gui/src/main/java/forge/gui/workshop/controllers/CWorkshopCatalog.java b/forge-gui/src/main/java/forge/gui/workshop/controllers/CWorkshopCatalog.java
new file mode 100644
index 00000000000..9d05454913d
--- /dev/null
+++ b/forge-gui/src/main/java/forge/gui/workshop/controllers/CWorkshopCatalog.java
@@ -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.
+ *
+ *
(C at beginning of class name denotes a control class.)
+ *
+ */
+public enum CWorkshopCatalog implements ICDoc {
+ /** */
+ SINGLETON_INSTANCE;
+
+ 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 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 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 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 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> 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> cardPredicates = new ArrayList>();
+ 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 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> itemPredicates = new ArrayList>();
+ 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 boolean isActive(Set activeSet, T key) {
+ return activeSet.contains(key);
+ }
+
+ @SuppressWarnings("serial")
+ private void addRestriction(Pair extends JComponent, Predicate> restriction, final Set activeSet, final T key) {
+ final Predicate 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> buildRangeRestriction(RangeTypes t) {
+ final Pair 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> 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> buildFormatRestriction(String displayName, GameFormat format, boolean allowReprints) {
+ 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 = 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());
+
+ if (allowReprints) {
+ tooltip.append("
Allowing identical cards from other sets");
+ }
+ }
+
+ List bannedCards = 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 Pair.of(
+ VWorkshopCatalog.SINGLETON_INSTANCE.buildPlainRestrictionWidget(displayName, tooltip.toString()),
+ allowReprints ? format.getFilterRules() : format.getFilterPrinted());
+ }
+
+ private Pair> buildSetRestriction(String displayName, List setCodes, boolean allowReprints) {
+ return buildFormatRestriction(displayName, new GameFormat(null, setCodes, null), allowReprints);
+ }
+}
diff --git a/forge-gui/src/main/java/forge/gui/workshop/views/VCardDesigner.java b/forge-gui/src/main/java/forge/gui/workshop/views/VCardDesigner.java
new file mode 100644
index 00000000000..0c5f8b25b5e
--- /dev/null
+++ b/forge-gui/src/main/java/forge/gui/workshop/views/VCardDesigner.java
@@ -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.
+ *
+ *
(V at beginning of class name denotes a view class.)
+ */
+public enum VCardDesigner implements IVDoc {
+ /** */
+ 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");
+ }
+}
diff --git a/forge-gui/src/main/java/forge/gui/workshop/views/VCardScript.java b/forge-gui/src/main/java/forge/gui/workshop/views/VCardScript.java
new file mode 100644
index 00000000000..fb42e74a99a
--- /dev/null
+++ b/forge-gui/src/main/java/forge/gui/workshop/views/VCardScript.java
@@ -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.
+ *
+ *
(V at beginning of class name denotes a view class.)
+ */
+public enum VCardScript implements IVDoc {
+ /** */
+ 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 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%");
+ }
+}
diff --git a/forge-gui/src/main/java/forge/gui/workshop/views/VWorkshopCatalog.java b/forge-gui/src/main/java/forge/gui/workshop/views/VWorkshopCatalog.java
new file mode 100644
index 00000000000..a98bb94443e
--- /dev/null
+++ b/forge-gui/src/main/java/forge/gui/workshop/views/VWorkshopCatalog.java
@@ -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.
+ *
+ *
(V at beginning of class name denotes a view class.)
+ *
+ */
+public enum VWorkshopCatalog implements IVDoc {
+ /** */
+ 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 statLabels =
+ new HashMap();
+
+ // 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 cbSearchMode = new FComboBoxWrapper();
+ 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> spinners = new HashMap>();
+
+ //========== 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 getCbSearchMode() { return cbSearchMode; }
+ public JTextField getTxfSearch() { return txfSearch; }
+
+ public CardManager getCardManager() {
+ return cardManager;
+ }
+ public Map getStatLabels() {
+ return statLabels;
+ }
+ public Map> 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 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();
+ }
+}
diff --git a/forge-gui/src/main/java/forge/properties/NewConstants.java b/forge-gui/src/main/java/forge/properties/NewConstants.java
index 99ca31dc0c1..5782cb043fc 100644
--- a/forge-gui/src/main/java/forge/properties/NewConstants.java
+++ b/forge-gui/src/main/java/forge/properties/NewConstants.java
@@ -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/");
diff --git a/forge-gui/src/main/java/forge/util/FileUtil.java b/forge-gui/src/main/java/forge/util/FileUtil.java
index 9d906f154c4..c5cfc260bb0 100644
--- a/forge-gui/src/main/java/forge/util/FileUtil.java
+++ b/forge-gui/src/main/java/forge/util/FileUtil.java
@@ -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 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
diff --git a/forge-gui/src/main/java/forge/view/FNavigationBar.java b/forge-gui/src/main/java/forge/view/FNavigationBar.java
index 1e328f34787..cd87063610a 100644
--- a/forge-gui/src/main/java/forge/view/FNavigationBar.java
+++ b/forge-gui/src/main/java/forge/view/FNavigationBar.java
@@ -89,6 +89,7 @@ public class FNavigationBar extends FTitleBarBase {
addNavigationTab(FScreen.HOME_SCREEN);
addNavigationTab(FScreen.DECK_EDITOR_CONSTRUCTED);
+ addNavigationTab(FScreen.WORKSHOP_SCREEN);
super.addControls();