wip: tagger

This commit is contained in:
Failure 2025-08-13 00:23:35 -07:00
parent f95769bf58
commit b823f4dcc7
7 changed files with 381 additions and 6 deletions

View file

@ -97,6 +97,10 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
cardSelectorScrollPane.setOpaque(false);
cardSelectorScrollPane.getViewport().setOpaque(false);
taggerScrollPane.setOpaque(false);
taggerScrollPane.getViewport().setOpaque(false);
cbSortBy.setModel(new DefaultComboBoxModel<>(SortBy.values()));
cbSortBy.setSelectedItem(sortSetting.getSortBy());
jTextFieldSearch.addActionListener(searchAction);
@ -106,11 +110,15 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
tbColor.setOpaque(true); // false = transparent
tbTypes.setBackground(PreferencesDialog.getCurrentTheme().getDeckEditorToolbarBackgroundColor());
tbTypes.setOpaque(true); // false = transparent
taggerScrollPane.setBackground(PreferencesDialog.getCurrentTheme().getDeckEditorToolbarBackgroundColor());
taggerScrollPane.setOpaque(true);
cardSelectorBottomPanel.setBackground(PreferencesDialog.getCurrentTheme().getDeckEditorToolbarBackgroundColor());
cardSelectorBottomPanel.setOpaque(true); // false = transparent
}
private void initListViewComponents() {
taggerTable = new JTable();
mainTable = new JTable();
mainModel = new TableModel();
@ -136,6 +144,11 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
// mainTable.setToolTipText(cardSelectorScrollPane.getToolTipText());
cardSelectorScrollPane.setViewportView(mainTable);
taggerScrollPane.setViewportView(taggerTable);
taggerTable.setOpaque(false);
mainTable.setOpaque(false);
cbSortBy.setEnabled(false);
chkPiles.setEnabled(false);
@ -631,6 +644,9 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
cardCountLabel = new javax.swing.JLabel();
cardCount = new javax.swing.JLabel();
taggerScrollPane = new javax.swing.JScrollPane();
tablePanel = new javax.swing.JSplitPane(JSplitPane.HORIZONTAL_SPLIT, cardSelectorScrollPane, taggerScrollPane);
tbColor.setFloatable(false);
tbColor.setRollover(true);
tbColor.setToolTipText("Hold the ALT-key while clicking to deselect all other colors or hold the CTRL-key to select only all other colors.");
@ -1105,6 +1121,8 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
cardSelectorBottomPanel.setOpaque(false);
cardSelectorBottomPanel.setPreferredSize(new java.awt.Dimension(897, 40));
tablePanel.setOpaque(false);
tablePanel.setPreferredSize(new java.awt.Dimension(600, 40));
jButtonAddToMain.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/deck_in.png"))); // NOI18N
jButtonAddToMain.setToolTipText("<html>Add selected cards to deck.<br/>\nAlternative: <strong>Double click</strong> the card in card selector to move a card to the deck.");
@ -1250,6 +1268,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
cardCount.setText("0");
javax.swing.GroupLayout cardSelectorBottomPanelLayout = new javax.swing.GroupLayout(cardSelectorBottomPanel);
cardSelectorBottomPanel.setLayout(cardSelectorBottomPanelLayout);
cardSelectorBottomPanelLayout.setHorizontalGroup(
cardSelectorBottomPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -1319,9 +1338,10 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(tbColor, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(tbTypes, javax.swing.GroupLayout.DEFAULT_SIZE, 1057, Short.MAX_VALUE)
.addComponent(cardSelectorScrollPane)
.addComponent(tablePanel)
.addComponent(cardSelectorBottomPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1057, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
@ -1329,7 +1349,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
.addGap(0, 0, 0)
.addComponent(tbTypes, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0)
.addComponent(cardSelectorScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 237, Short.MAX_VALUE)
.addComponent(tablePanel, javax.swing.GroupLayout.DEFAULT_SIZE, 237, Short.MAX_VALUE)
.addGap(0, 0, 0)
.addComponent(cardSelectorBottomPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 31, javax.swing.GroupLayout.PREFERRED_SIZE))
);
@ -1690,6 +1710,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
private TableModel mainModel;
private JTable mainTable;
private JTable taggerTable;
private ICardGrid currentView;
private final CheckBoxList listCodeSelected;
@ -1751,6 +1772,10 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
private javax.swing.JToolBar tbTypes;
private javax.swing.JToggleButton tbUncommon;
private javax.swing.JToggleButton tbWhite;
private javax.swing.JScrollPane taggerScrollPane;
private javax.swing.JSplitPane tablePanel;
// End of variables declaration//GEN-END:variables
private final mage.client.cards.CardGrid cardGrid; // grid for piles view mode (example: selected cards in drafting)

View file

@ -0,0 +1,344 @@
package mage.client.deckeditor.table;
import mage.client.MageFrame;
import mage.client.cards.BigCard;
import mage.client.cards.CardEventSource;
import mage.client.cards.ICardGrid;
import mage.client.deckeditor.SortSetting;
import mage.client.plugins.impl.Plugins;
import mage.client.util.ClientDefaultSettings;
import mage.client.util.ClientEventType;
import mage.client.util.Event;
import mage.client.util.Listener;
import mage.client.util.gui.GuiDisplayUtil;
import mage.constants.EnlargeMode;
import mage.cards.RateCard;
import mage.view.CardView;
import mage.view.CardsView;
import org.apache.log4j.Logger;
import org.jdesktop.swingx.JXPanel;
import org.mage.card.arcane.ManaSymbols;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumnModel;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.List;
import java.util.*;
import java.util.Map.Entry;
/**
* Table Model for card list.
*
* @author nantuko
*/
public class TaggerModel extends AbstractTableModel {
private static final long serialVersionUID = -528008802935423048L;
private static final Logger log = Logger.getLogger(TableModel.class);
protected final CardEventSource cardEventSource = new CardEventSource();
protected BigCard bigCard;
protected UUID gameId;
private final Map<UUID, CardView> cards = new LinkedHashMap<>();
private final Map<String, Integer> cardsNoCopies = new LinkedHashMap<>();
private final List<CardView> view = new ArrayList<>();
private Dimension cardDimension;
private boolean displayNoCopies = false;
private UpdateCountsCallback updateCountsCallback;
private final String[] column = {"Qty", "Name", "Cost", "Color", "Type", "Stats", "Rarity", "Set", "Card number", "Draft Rating", "Color Identity"};
public final int COLUMN_INDEX_COST = 2;
public final int COLUMN_INDEX_RATING = 9;
public final int COLUMN_INDEX_COLOR_IDENTITY = 10;
private SortSetting sortSetting;
private int recentSortedColumn;
private boolean recentAscending;
private boolean numberEditable;
public TaggerModel() {
this.numberEditable = false;
}
public void clear() {
this.clearCardEventListeners();
this.clearCards();
this.view.clear();
}
public void clearCards() {
view.clear();
cards.clear();
}
@Override
public int getRowCount() {
return view.size();
}
@Override
public int getColumnCount() {
return column.length;
}
@Override
public String getColumnName(int n) {
return column[n];
}
@Override
public Object getValueAt(int row, int column) {
return getColumn(view.get(row), column);
}
private Object getColumn(Object obj, int column) {
CardView c = (CardView) obj;
switch (column) {
case 0:
if (displayNoCopies) {
String key = c.getName() + c.getExpansionSetCode() + c.getCardNumber();
Integer count = cardsNoCopies.get(key);
return count != null ? count : "";
}
return "";
case 1:
return c.getDisplayFullName(); // show full name in deck editor table, e.g. adventure with spell name
case 2:
// new svg images version
return ManaSymbols.getClearManaCost(c.getManaCostStr());
/*
// old html images version
String manaCost = "";
for (String m : c.getManaCost()) {
manaCost += m;
}
String castingCost = UI.getDisplayManaCost(manaCost);
castingCost = ManaSymbols.replaceSymbolsWithHTML(castingCost, ManaSymbols.Type.TABLE);
return "<html>" + castingCost + "</html>";
return castingCost;
*/
case 3:
return c.getColorText();
case 4:
return c.getTypeText();
case 5:
return c.isCreature() ? c.getPower() + '/'
+ c.getToughness() : "-";
case 6:
return c.getRarity() == null ? "" : c.getRarity().toString();
case 7:
return c.getExpansionSetCode();
case 8:
return c.getCardNumber();
case 9:
return RateCard.rateCard(c, Collections.emptyList());
case 10:
return ManaSymbols.getClearManaCost(c.getOriginalColorIdentity());
default:
return "error";
}
}
private void addCard(CardView card, BigCard bigCard, UUID gameId) {
if (cardDimension == null) {
cardDimension = new Dimension(ClientDefaultSettings.dimensions.getFrameWidth(),
ClientDefaultSettings.dimensions.getFrameHeight());
}
cards.put(card.getId(), card);
if (displayNoCopies) {
String key = card.getName() + card.getExpansionSetCode() + card.getCardNumber();
Integer count = 1;
if (cardsNoCopies.containsKey(key)) {
count = cardsNoCopies.get(key) + 1;
} else {
view.add(card);
}
cardsNoCopies.put(key, count);
} else {
view.add(card);
}
}
@Override
public void drawCards(SortSetting sortSetting) {
fireTableDataChanged();
}
public void removeCard(UUID cardId) {
cards.remove(cardId);
view.removeIf(cardView -> cardView.getId().equals(cardId));
}
@Override
public void addCardEventListener(Listener<Event> listener) {
cardEventSource.addListener(listener);
}
@Override
public void clearCardEventListeners() {
cardEventSource.clearListeners();
}
public void setNumber(int index, int number) {
CardView card = view.get(index);
cardEventSource.fireEvent(card, ClientEventType.SET_NUMBER, number);
}
public void doubleClick(int index, MouseEvent e, boolean forceFakeAltDown) {
CardView card = view.get(index);
cardEventSource.fireEvent(card, ClientEventType.CARD_DOUBLE_CLICK, e, forceFakeAltDown);
}
public void removeFromMainEvent(int index) {
cardEventSource.fireEvent(ClientEventType.DECK_REMOVE_SELECTION_MAIN);
}
public void removeFromSideEvent(int index) {
cardEventSource.fireEvent(ClientEventType.DECK_REMOVE_SELECTION_SIDEBOARD);
}
public void addListeners(final JTable table) {
// updates card detail, listens to any key strokes
table.addKeyListener(new KeyListener() {
@Override
public void keyPressed(KeyEvent ev) {
}
@Override
public void keyTyped(KeyEvent ev) {
}
@Override
public void keyReleased(KeyEvent ev) {
int row = table.getSelectedRow();
if (row != -1) {
showImage(row);
}
}
});
// updates card detail, listens to any mouse clicks
table.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if (!SwingUtilities.isLeftMouseButton(e)) {
return;
}
int row = table.getSelectedRow();
if (row != -1) {
showImage(row);
}
}
});
// sorts
MouseListener mouse = new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if (!SwingUtilities.isLeftMouseButton(e)) {
return;
}
TableColumnModel columnModel = table.getColumnModel();
int viewColumn = columnModel.getColumnIndexAtX(e.getX());
int column = table.convertColumnIndexToModel(viewColumn);
if (column != -1) {
// sort ascending
boolean asc = true;
if (recentSortedColumn == column) {
asc = !recentAscending;
}
sortSetting.setSortIndex(column);
sortSetting.setAscending(asc);
sort(column, asc);
fireTableDataChanged();
}
}
};
table.getTableHeader().addMouseListener(mouse);
}
private void showImage(int row) {
CardView card = view.get(row);
if (!card.getId().equals(bigCard.getCardId())) {
if (!MageFrame.isLite()) {
Image image = Plugins.instance.getOriginalImage(card);
if (image instanceof BufferedImage) {
// XXX: scaled to fit width
bigCard.setCard(card.getId(), EnlargeMode.NORMAL, image, new ArrayList<>(), false);
} else {
drawCardText(card);
}
} else {
drawCardText(card);
}
}
}
private void drawCardText(CardView card) {
JXPanel panel = GuiDisplayUtil.getDescription(card, bigCard.getWidth(), bigCard.getHeight());
panel.setVisible(true);
bigCard.hideTextComponent();
bigCard.addJXPanel(card.getId(), panel);
}
public List<CardView> getCardsView() {
return view;
}
public boolean sort(int column, boolean ascending) {
// used by addCard() to resort the cards
recentSortedColumn = column;
recentAscending = ascending;
MageCardComparator sorter = new MageCardComparator(column, ascending);
view.sort(sorter);
fireTableDataChanged();
return true;
}
public int getRecentSortedColumn() {
return recentSortedColumn;
}
public boolean isRecentAscending() {
return recentAscending;
}
public void setDisplayNoCopies(boolean value) {
this.displayNoCopies = value;
}
public void setUpdateCountsCallback(UpdateCountsCallback callback) {
this.updateCountsCallback = callback;
}
public void setNumberEditable(boolean numberEditable) {
this.numberEditable = numberEditable;
}
@Override
public int cardsSize() {
return cards.size();
}
@Override
public boolean isCellEditable(int row, int col) {
if (numberEditable && col == 0) {
return true;
}
return super.isCellEditable(row, col);
}
}

View file

@ -893,7 +893,7 @@ public class TablesPanel extends javax.swing.JPanel {
formatFilterList.add(RowFilter.regexFilter("^Oathbreaker", TablesTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatLimited.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Limited", TablesTableModel.COLUMN_DECK_TYPE));
formatFilterList.add(RowFilter.regexFilter("^(?:(?:Unl)|L)imited", TablesTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatOther.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Momir Basic|^Constructed - Pauper|^Constructed - Frontier|^Constructed - Extended|^Constructed - Eternal|^Constructed - Historical|^Constructed - Super|^Constructed - Freeform|^Constructed - Freeform Unlimited|^Australian Highlander|^European Highlander|^Canadian Highlander|^Constructed - Old|^Constructed - Historic", TablesTableModel.COLUMN_DECK_TYPE));

View file

@ -32,7 +32,7 @@ public class ScryfallApiCard {
transient public String imageLarge = "";
// potentially interesting fields, can be used in other places
//public UUID oracle_id; // TODO: implement card hint with oracle/cr ruling texts (see Rulings bulk data)
public String oracle_id; // TODO: implement card hint with oracle/cr ruling texts (see Rulings bulk data)
//public Integer edhrec_rank; // TODO: use it to rating cards for AI and draft bots
//public Object legalities; // TODO: add verify check for bans list
//public Boolean full_art; // TODO: add verify check for full art usage in sets

View file

@ -6,6 +6,7 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.stream.JsonReader;
import mage.MageException;
import mage.cards.repository.CardRepository;
import mage.client.remote.XmageURLConnection;
import mage.client.util.CardLanguage;
import mage.util.JsonUtil;
@ -485,6 +486,9 @@ public class ScryfallImageSource implements CardImageSource {
continue;
}
// I LOVE POTENTIAL SQL INJECTION!!!!!
CardRepository.instance.execSQL("UPDATE card SET oracleId = '"+ card.oracle_id +"' WHERE setCode = '"+ card.set +"' AND cardNumber = '"+ card.collector_number +"'");
// keep only usefully languages
// memory optimization: fewer items, from 470 MB to 96 MB

View file

@ -40,6 +40,8 @@ public class CardInfo {
protected String setCode;
@DatabaseField(indexName = "setCode_cardNumber_index")
protected String cardNumber;
@DatabaseField(indexName = "oracleId_index", canBeNull = true)
protected String oracleId;
/**
* Fast access to numerical card number (number without prefix/postfix: 123b -> 123)
*/

View file

@ -38,7 +38,7 @@ public enum CardRepository {
// TODO: delete db version from cards and expansions due un-used (cause dbs re-created on each update now)
private static final String VERSION_ENTITY_NAME = "card";
private static final long CARD_DB_VERSION = 54; // raise this if db structure was changed
private static final long CARD_DB_VERSION = 55; // raise this if db structure was changed
private static final long CARD_CONTENT_VERSION = 241; // raise this if new cards were added to the server
private Dao<CardInfo, Object> cardsDao;