diff --git a/Mage.Client/src/main/java/mage/client/cards/CardDraggerGlassPane.java b/Mage.Client/src/main/java/mage/client/cards/CardDraggerGlassPane.java new file mode 100644 index 00000000000..ac5efde71cd --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/cards/CardDraggerGlassPane.java @@ -0,0 +1,170 @@ +package mage.client.cards; + +import mage.cards.MageCard; +import mage.client.plugins.impl.Plugins; +import mage.view.CardView; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.util.ArrayList; +import java.util.Collection; + +/** + * Created by StravantUser on 2016-09-22. + */ +public class CardDraggerGlassPane extends JPanel implements MouseListener, MouseMotionListener { + private DragCardSource source; + private Component dragComponent; + private JRootPane currentRoot; + private Component oldGlassPane; + private ArrayList currentCards; + private MageCard dragView; + private DragCardTarget currentDragTarget; + private boolean isDragging; + + public CardDraggerGlassPane(DragCardSource source) { + this.source = source; + + // Listen on self + setLayout(null); + setOpaque(false); + setVisible(true); + } + + public void beginDrag(Component c, MouseEvent e) { + // Start drag + if (isDragging) { + return; + } + isDragging = true; + + // Record what we are dragging on + dragComponent = c; + currentRoot = SwingUtilities.getRootPane(c); + + // Hook up events + c.addMouseListener(this); + c.addMouseMotionListener(this); + + // Switch glass pane to us + oldGlassPane = currentRoot.getGlassPane(); + setVisible(false); + currentRoot.setGlassPane(this); + setVisible(true); + revalidate(); + + // Event to local space + e = SwingUtilities.convertMouseEvent(c, e, this); + + // Get the cards to drag + currentCards = new ArrayList<>(source.dragCardList()); + + // Make a view for the first one and add it to us + dragView = Plugins.getInstance().getMageCard(currentCards.get(0), null, new Dimension(100, 140), null, true); + for (MouseListener l: dragView.getMouseListeners()) { + dragView.removeMouseListener(l); + } + for (MouseMotionListener l : dragView.getMouseMotionListeners()) { + dragView.removeMouseMotionListener(l); + } + this.add(dragView); + dragView.setLocation(e.getX(), e.getY()); + + // Notify the sounce + source.dragCardBegin(); + + // Update the target + currentDragTarget = null; + updateCurrentTarget(SwingUtilities.convertMouseEvent(c, e, currentRoot), false); + } + + // e is relative to currentRoot + private void updateCurrentTarget(MouseEvent e, boolean isEnding) { + Component mouseOver = SwingUtilities.getDeepestComponentAt(currentRoot.getContentPane(), e.getX(), e.getY()); + while (mouseOver != null) { + if (mouseOver instanceof DragCardTarget) { + DragCardTarget target = (DragCardTarget)mouseOver; + MouseEvent targetEvent = SwingUtilities.convertMouseEvent(currentRoot, e, mouseOver); + if (target != currentDragTarget) { + if (currentDragTarget != null) { + MouseEvent oldTargetEvent = SwingUtilities.convertMouseEvent(currentRoot, e, (Component) currentDragTarget); + currentDragTarget.dragCardExit(oldTargetEvent); + } + currentDragTarget = target; + currentDragTarget.dragCardEnter(targetEvent); + } + if (isEnding) { + currentDragTarget.dragCardExit(targetEvent); + currentDragTarget.dragCardDrop(targetEvent, source, currentCards); + } else { + currentDragTarget.dragCardMove(targetEvent); + } + return; + } + mouseOver = mouseOver.getParent(); + } + if (currentDragTarget != null) { + MouseEvent oldTargetEvent = SwingUtilities.convertMouseEvent(currentRoot, e, (Component)currentDragTarget); + currentDragTarget.dragCardExit(oldTargetEvent); + } + currentDragTarget = null; + } + + public boolean isDragging() { + return isDragging; + } + + /** + * Mouse released -> we are done the drag + */ + @Override + public void mouseReleased(MouseEvent e) { + // No longer dragging + isDragging = false; + + // Remove listeners + dragComponent.removeMouseListener(this); + dragComponent.removeMouseMotionListener(this); + + // Convert the event into root coords + e = SwingUtilities.convertMouseEvent(dragComponent, e, currentRoot); + + // Switch back glass pane + currentRoot.setGlassPane(oldGlassPane); + + // Remove the drag card + this.remove(dragView); + + // Update the target, and do the drop + updateCurrentTarget(e, true); + + // Let the drag source know + source.dragCardEnd(currentDragTarget); + } + + @Override + public void mouseDragged(MouseEvent e) { + // Update the view + MouseEvent glassE = SwingUtilities.convertMouseEvent(dragComponent, e, this); + dragView.setLocation(glassE.getX(), glassE.getY()); + dragView.repaint(); + + // Convert the event into root coords and update target + e = SwingUtilities.convertMouseEvent(dragComponent, e, currentRoot); + updateCurrentTarget(e, false); + } + + @Override + public void mouseClicked(MouseEvent e) {} + @Override + public void mousePressed(MouseEvent e) {} + @Override + public void mouseEntered(MouseEvent e) {} + @Override + public void mouseExited(MouseEvent e) {} + @Override + public void mouseMoved(MouseEvent e) {} +} diff --git a/Mage.Client/src/main/java/mage/client/cards/DragCardGrid.java b/Mage.Client/src/main/java/mage/client/cards/DragCardGrid.java new file mode 100644 index 00000000000..1a193e6f983 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/cards/DragCardGrid.java @@ -0,0 +1,949 @@ +package mage.client.cards; + +import mage.cards.MageCard; +import mage.cards.decks.Deck; +import mage.cards.decks.importer.DeckImporterUtil; +import mage.client.MageFrame; +import mage.client.plugins.impl.Plugins; +import mage.client.util.CardViewColorComparator; +import mage.client.util.CardViewCostComparator; +import mage.client.util.CardViewRarityComparator; +import mage.client.util.GUISizeHelper; +import mage.constants.CardType; +import mage.game.GameException; +import mage.interfaces.plugin.CardPlugin; +import mage.view.CardView; +import mage.view.CardsView; +import org.apache.log4j.Logger; +import org.mage.card.arcane.CardRenderer; +import org.mage.plugins.card.CardPluginImpl; + +import javax.swing.*; +import javax.swing.event.PopupMenuEvent; +import javax.swing.event.PopupMenuListener; +import java.awt.*; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.FlavorMap; +import java.awt.dnd.*; +import java.awt.event.*; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Array; +import java.util.*; + +/** + * Created by StravantUser on 2016-09-20. + */ +public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarget { + private static Logger LOGGER = Logger.getLogger(DragCardGrid.class); + + @Override + public Collection dragCardList() { + ArrayList selectedCards = new ArrayList<>(); + for (CardView card : allCards) { + if (card.isSelected()) { + selectedCards.add(card); + } + } + return selectedCards; + } + + @Override + public void dragCardBegin() { + LOGGER.info("Begin drag"); + } + + @Override + public void dragCardEnd(DragCardTarget target) { + LOGGER.info("End drag (" + target + ")"); + if (target == this) { + // Already handled by dragged onto handler + } else { + // Remove dragged cards + for (ArrayList> gridRow : cardGrid) { + for (ArrayList stack : gridRow) { + for (int i = 0; i < stack.size(); ++i) { + CardView view = stack.get(i); + if (view.isSelected()) { + stack.set(i, null); + } + } + } + } + trimGrid(); + layoutGrid(); + cardScroll.repaint(); + } + } + + @Override + public void dragCardEnter(MouseEvent e) { + insertArrow.setVisible(true); + } + + @Override + public void dragCardMove(MouseEvent e) { + e = SwingUtilities.convertMouseEvent(this, e, cardContent); + showDropPosition(e.getX(), e.getY()); + } + + private void showDropPosition(int x, int y) { + // Clamp to region + if (x < 0) { + x = 0; + } + if (y < 0) { + y = 0; + } + + // Determine column + int cardWidth = getCardWidth(); + int cardHeight = getCardHeight(); + int cardTopHeight = CardRenderer.getCardTopHeight(cardWidth); + int dx = x % (cardWidth + GRID_PADDING); + int col = x / (cardWidth + GRID_PADDING); + int gridWidth = cardGrid.isEmpty() ? 0 : cardGrid.get(0).size(); + + if (dx < GRID_PADDING && col < gridWidth) { + // Which row to add to? + int curY = COUNT_LABEL_HEIGHT; + int rowIndex = 0; + for (int i = 0; i < cardGrid.size(); ++i) { + int maxStack = maxStackSize.get(i); + int rowHeight = cardTopHeight*(maxStack-1) + cardHeight; + int rowBottom = curY + rowHeight + COUNT_LABEL_HEIGHT; + + // Break out if we're in that row + if (y < rowBottom) { + // Set the row + rowIndex = i; + break; + } else { + rowIndex = i+1; + curY = rowBottom; + } + } + + // Insert between two columns + insertArrow.setIcon(INSERT_COL_ICON); + insertArrow.setSize(64, 64); + insertArrow.setLocation((cardWidth + GRID_PADDING)*col + GRID_PADDING/2 - 32, curY); + } else { + // Clamp to a new col one after the current last one + col = Math.min(col, gridWidth); + + // Determine place in the col + int curY = COUNT_LABEL_HEIGHT; + int rowIndex = 0; + int offsetIntoStack = 0; + for (int i = 0; i < cardGrid.size(); ++i) { + int maxStack = maxStackSize.get(i); + int rowHeight = cardTopHeight*(maxStack-1) + cardHeight; + int rowBottom = curY + rowHeight + COUNT_LABEL_HEIGHT; + + // Break out if we're in that row + if (y < rowBottom) { + // Set the row + rowIndex = i; + offsetIntoStack = y - curY; + break; + } else { + rowIndex = i+1; + offsetIntoStack = y - rowBottom; + curY = rowBottom; + } + } + + // Get the appropirate stack + ArrayList stack; + if (rowIndex < cardGrid.size() && col < cardGrid.get(0).size()) { + stack = cardGrid.get(rowIndex).get(col); + } else { + stack = new ArrayList<>(); + } + + // Figure out position in the stack based on the offsetIntoRow + int stackInsertIndex = (offsetIntoStack + cardTopHeight/2) / cardTopHeight; + stackInsertIndex = Math.max(0, Math.min(stackInsertIndex, stack.size())); + + // Position arrow + insertArrow.setIcon(INSERT_ROW_ICON); + insertArrow.setSize(64, 32); + insertArrow.setLocation((cardWidth + GRID_PADDING)*col + GRID_PADDING + cardWidth/2 - 32, curY + stackInsertIndex*cardTopHeight - 32); + } + } + + @Override + public void dragCardExit(MouseEvent e) { + insertArrow.setVisible(false); + } + + @Override + public void dragCardDrop(MouseEvent e, DragCardSource source, Collection cards) { + e = SwingUtilities.convertMouseEvent(this, e, cardContent); + int x = e.getX(); + int y = e.getY(); + + // Clamp to region + if (x < 0) { + x = 0; + } + if (y < 0) { + y = 0; + } + + // If we're dragging onto ourself, erase the old cards (just null them out, we will + // compact the grid removing the null gaps / empty rows & cols later) + if (source == this) { + for (ArrayList> gridRow : cardGrid) { + for (ArrayList stack : gridRow) { + for (int i = 0; i < stack.size(); ++i) { + if (cards.contains(stack.get(i))) { + stack.set(i, null); + } + } + } + } + } + + // Determine column + int cardWidth = getCardWidth(); + int cardHeight = getCardHeight(); + int cardTopHeight = CardRenderer.getCardTopHeight(cardWidth); + int dx = x % (cardWidth + GRID_PADDING); + int col = x / (cardWidth + GRID_PADDING); + int gridWidth = cardGrid.isEmpty() ? 0 : cardGrid.get(0).size(); + + if (dx < GRID_PADDING && col < gridWidth) { + // Which row to add to? + int curY = COUNT_LABEL_HEIGHT; + int rowIndex = 0; + for (int i = 0; i < cardGrid.size(); ++i) { + int maxStack = maxStackSize.get(i); + int rowHeight = cardTopHeight*(maxStack-1) + cardHeight; + int rowBottom = curY + rowHeight + COUNT_LABEL_HEIGHT; + + // Break out if we're in that row + if (y < rowBottom) { + // Set the row + rowIndex = i; + break; + } else { + rowIndex = i+1; + curY = rowBottom; + } + } + + // Add a new row if needed + if (rowIndex >= cardGrid.size()) { + ArrayList> newRow = new ArrayList<>(); + if (!cardGrid.isEmpty()) { + for (int colIndex = 0; colIndex < cardGrid.get(0).size(); ++colIndex) { + newRow.add(new ArrayList()); + } + } + cardGrid.add(newRow); + maxStackSize.add(0); + } + + // Insert the new column to add to + for (int i = 0; i < cardGrid.size(); ++i) { + cardGrid.get(i).add(col, new ArrayList()); + } + + // Add the cards + cardGrid.get(rowIndex).get(col).addAll(cards); + } else { + // Clamp to a new col one after the current last one + col = Math.min(col, gridWidth); + + // Determine place in the col + int curY = COUNT_LABEL_HEIGHT; + int rowIndex = 0; + int offsetIntoStack = 0; + for (int i = 0; i < cardGrid.size(); ++i) { + int maxStack = maxStackSize.get(i); + int rowHeight = cardTopHeight*(maxStack-1) + cardHeight; + int rowBottom = curY + rowHeight + COUNT_LABEL_HEIGHT; + + // Break out if we're in that row + if (y < rowBottom) { + // Set the row + rowIndex = i; + offsetIntoStack = y - curY; + break; + } else { + rowIndex = i+1; + offsetIntoStack = y - rowBottom; + curY = rowBottom; + } + } + + // Add a new row if needed + if (rowIndex >= cardGrid.size()) { + ArrayList> newRow = new ArrayList<>(); + if (!cardGrid.isEmpty()) { + for (int colIndex = 0; colIndex < cardGrid.get(0).size(); ++colIndex) { + newRow.add(new ArrayList()); + } + } + cardGrid.add(newRow); + maxStackSize.add(0); + } + + // Add a new col if needed + if (col >= cardGrid.get(0).size()) { + for (int i = 0; i < cardGrid.size(); ++i) { + cardGrid.get(i).add(new ArrayList()); + } + } + + // Get the appropirate stack + ArrayList stack = cardGrid.get(rowIndex).get(col); + + // Figure out position in the stack based on the offsetIntoRow + int stackInsertIndex = (offsetIntoStack + cardTopHeight/2) / cardTopHeight; + stackInsertIndex = Math.max(0, Math.min(stackInsertIndex, stack.size())); + + // Insert the cards + stack.addAll(stackInsertIndex, cards); + } + + // Remove empty rows / cols / spaces in stacks + if (source == this) { + trimGrid(); + layoutGrid(); + cardScroll.repaint(); + } + } + + public enum Sort { + NONE(new Comparator() { + @Override + public int compare(CardView o1, CardView o2) { + // Always equal, sort into the first row + return 0; + } + }), + CMC(new CardViewCostComparator()), + COLOR(new CardViewColorComparator()), + RARITY(new CardViewRarityComparator()); + + Sort(Comparator comparator) { + this.comparator = comparator; + } + + public Comparator getComparator() { + return comparator; + } + + private Comparator comparator; + } + + + + // Constants + public static int CARD_WIDTH = 150; + public static int COUNT_LABEL_HEIGHT = 20; + public static int GRID_PADDING = 10; + + private static ImageIcon INSERT_ROW_ICON = new ImageIcon(DragCardGrid.class.getClassLoader().getResource("editor_insert_row.png")); + private static ImageIcon INSERT_COL_ICON = new ImageIcon(DragCardGrid.class.getClassLoader().getResource("editor_insert_col.png")); + + // All of the current card views + private Map cardViews = new LinkedHashMap<>(); + private ArrayList allCards = new ArrayList<>(); + + // Top bar with dropdowns for sort / filter / etc + JButton sortButton; + JButton filterButton; + + // Popup for toolbar + JPopupMenu filterPopup; + JPopupMenu sortPopup; + + // Main two controls holding the scrollable card grid + JScrollPane cardScroll; + JLayeredPane cardContent; + + // Drag onto insert arrow + JLabel insertArrow; + + // Card area selection panel + SelectionBox selectionPanel; + int selectionDragStartX; + int selectionDragStartY; + + // Dragging + private CardDraggerGlassPane dragger = new CardDraggerGlassPane(this); + + // The grid of cards + // The outermost array contains multiple rows of stacks of cards + // The next inner array represents a row of stacks of cards + // The innermost array represents a single vertical stack of cards + private ArrayList>> cardGrid; + private ArrayList maxStackSize = new ArrayList<>(); + private ArrayList> stackCountLabels = new ArrayList<>(); + private Sort cardSort = Sort.CMC; + private boolean separateCreatures = true; + + // Constructor + public DragCardGrid() { + // Make sure that the card grid is populated with at least one (empty) stack to begin with + cardGrid = new ArrayList<>(); + + // Component init + setLayout(new BorderLayout()); + + // Toolbar + sortButton = new JButton("Sort"); + filterButton = new JButton("Filter"); + + // Tmp load button + JButton loadButton = new JButton("Load"); + loadButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + loadDeck(); + } + }); + + JPanel toolbar = new JPanel(new BorderLayout()); + JPanel toolbarInner = new JPanel(); + toolbar.setBackground(new Color(250, 250, 250, 150)); + toolbar.setOpaque(true); + toolbarInner.setOpaque(false); + toolbarInner.add(sortButton); + toolbarInner.add(filterButton); + toolbarInner.add(loadButton); + toolbar.add(toolbarInner, BorderLayout.WEST); + this.add(toolbar, BorderLayout.NORTH); + + // Content + cardContent = new JLayeredPane(); + cardContent.setLayout(null); + cardContent.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + beginSelectionDrag(e.getX(), e.getY()); + updateSelectionDrag(e.getX(), e.getY()); + } + @Override + public void mouseReleased(MouseEvent e) { + updateSelectionDrag(e.getX(), e.getY()); + endSelectionDrag(e.getX(), e.getY()); + } + }); + cardContent.addMouseMotionListener(new MouseAdapter() { + @Override + public void mouseDragged(MouseEvent e) { + updateSelectionDrag(e.getX(), e.getY()); + } + }); + cardScroll = new JScrollPane(cardContent, + ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, + ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); + this.add(cardScroll, BorderLayout.CENTER); + + // Insert arrow + insertArrow = new JLabel(); + insertArrow.setSize(20, 20); + insertArrow.setVisible(false); + cardContent.add(insertArrow, new Integer(1000)); + + // Selection panel + selectionPanel = new SelectionBox(); + selectionPanel.setVisible(false); + cardContent.add(selectionPanel, new Integer(1001)); + + // Sort popup + sortPopup = new JPopupMenu(); + sortPopup.setPreferredSize(new Dimension(300, 300)); + makeButtonPopup(sortButton, sortPopup); + + // Filter popup + filterPopup = new JPopupMenu(); + filterPopup.setPreferredSize(new Dimension(300, 300)); + makeButtonPopup(filterButton, filterPopup); + + + + + } + + /** + * Selection drag handling + */ + private void beginSelectionDrag(int x, int y) { + // Show the selection panel + selectionPanel.setVisible(true); + selectionPanel.setLocation(x, y); + cardScroll.revalidate(); + + // Store the drag start location + selectionDragStartX = x; + selectionDragStartY = y; + } + + private void updateSelectionDrag(int x, int y) { + // Coords + int cardWidth = getCardWidth(); + int cardHeight = getCardHeight(); + int cardTopHeight = CardRenderer.getCardTopHeight(cardWidth); + int x1 = Math.min(x, selectionDragStartX); + int x2 = Math.max(x, selectionDragStartX); + int y1 = Math.min(y, selectionDragStartY); + int y2 = Math.max(y, selectionDragStartY); + + // Update selection panel size + selectionPanel.setLocation(x1, y1); + selectionPanel.setSize(x2 - x1, y2 - y1); + + // First and last cols + int col1 = x1 / (cardWidth + GRID_PADDING); + int col2 = x2 / (cardWidth + GRID_PADDING); + int offsetIntoCol2 = x2 % (cardWidth + GRID_PADDING); + if (offsetIntoCol2 < GRID_PADDING) { + --col2; + } + + int curY = COUNT_LABEL_HEIGHT; + for (int rowIndex = 0; rowIndex < cardGrid.size(); ++rowIndex) { + int stackStartIndex; + if (y1 < curY) { + stackStartIndex = 0; + } else { + stackStartIndex = (y1 - curY) / cardTopHeight; + } + int stackEndIndex; + if (y2 < curY) { + stackEndIndex = -1; + } else { + stackEndIndex = (y2 - curY) / cardTopHeight; + } + ArrayList> gridRow = cardGrid.get(rowIndex); + for (int col = 0; col < gridRow.size(); ++col) { + ArrayList stack = gridRow.get(col); + int stackBottomBegin = curY + cardTopHeight*(stack.size()); + int stackBottomEnd = curY + cardTopHeight*(stack.size()-1) + cardHeight; + for (int i = 0; i < stack.size(); ++i) { + CardView card = stack.get(i); + MageCard view = cardViews.get(card.getId()); + boolean inBoundsX = (col >= col1 && col <= col2); + boolean inBoundsY = (i >= stackStartIndex && i <= stackEndIndex); + boolean lastCard = (i == stack.size()-1); + if (inBoundsX && (inBoundsY || (lastCard && (y2 >= stackBottomBegin && y1 <= stackBottomEnd)))) { + if (!card.isSelected()) { + card.setSelected(true); + view.update(card); + } + } else { + if (card.isSelected()) { + card.setSelected(false); + view.update(card); + } + } + } + } + curY += cardTopHeight*(maxStackSize.get(rowIndex)-1) + cardHeight + COUNT_LABEL_HEIGHT; + } + } + + private void endSelectionDrag(int x, int y) { + // Hide the selection panel + selectionPanel.setVisible(false); + } + + + private void loadDeck() { + JFileChooser fcSelectDeck = new JFileChooser(); + String lastFolder = MageFrame.getPreferences().get("lastDeckFolder", ""); + if (!lastFolder.isEmpty()) { + fcSelectDeck.setCurrentDirectory(new File(lastFolder)); + } + int ret = fcSelectDeck.showOpenDialog(DragCardGrid.this); + if (ret == JFileChooser.APPROVE_OPTION) { + File file = fcSelectDeck.getSelectedFile(); + try { + setCursor(new Cursor(Cursor.WAIT_CURSOR)); + Deck deck = Deck.load(DeckImporterUtil.importDeck(file.getPath()), true, true); + Logger.getLogger(DragCardGrid.class).info("Loaded " + deck.getCards().size()); + setCards(new CardsView(deck.getCards())); + } catch (GameException ex) { + JOptionPane.showMessageDialog(MageFrame.getDesktop(), ex.getMessage(), "Error loading deck", JOptionPane.ERROR_MESSAGE); + } catch (Exception ex) { + ex.printStackTrace(); + } finally { + setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + } + try { + if (file != null) { + MageFrame.getPreferences().put("lastDeckFolder", file.getCanonicalPath()); + } + } catch (IOException ex) { + } + } + fcSelectDeck.setSelectedFile(null); + } + + // Update the contents of the card grid + public void setCards(CardsView cardsView) { + // Remove all of the cards not in the cardsView + boolean didModify = false; // Until contested + for (int i = 0; i < cardGrid.size(); ++i) { + ArrayList> gridRow = cardGrid.get(i); + for (int j = 0; j < gridRow.size(); ++j) { + ArrayList stack = gridRow.get(j); + for (int k = 0; k < stack.size(); ++k) { + CardView card = stack.get(k); + if (!cardsView.containsKey(card.getId())) { + // Remove it + removeCardView(card); + stack.remove(k--); + + // Mark + didModify = true; + } + } + } + } + + // Add any new card views + for (CardView newCard: cardsView.values()) { + if (!cardViews.containsKey(newCard.getId())) { + // Is a new card + addCardView(newCard); + + try { + // Put it into the appropirate place in the grid given the current sort + sortIntoGrid(newCard); + } catch (Exception e) { + e.printStackTrace(); + } + // Mark + didModify = true; + } + } + + // Modifications? + if (didModify) { + // Trim extra rows / columns from the grid + trimGrid(); + + // Update layout + layoutGrid(); + + // Update draw + cardScroll.revalidate(); + repaint(); + } + } + + private void addCardView(final CardView card) { + allCards.add(card); + + // Create the card view + final MageCard cardPanel = Plugins.getInstance().getMageCard(card, null, new Dimension(100, 140), null, true); + cardPanel.update(card); + + cardPanel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + cardClicked(card, e); + } + }); + cardPanel.addMouseMotionListener(new MouseAdapter() { + @Override + public void mouseDragged(MouseEvent e) { + if (!dragger.isDragging()) { + // If the card isn't already selected, make sure it is + if (!card.isSelected()) { + cardClicked(card, e); + } + dragger.beginDrag(cardPanel, e); + } + } + }); + + // And add it + cardContent.add(cardPanel); + cardViews.put(card.getId(), cardPanel); + } + + private void cardClicked(CardView targetCard, MouseEvent e) { + // Set the selected card to the target card + for (CardView card : allCards) { + if (card == targetCard) { + if (!card.isSelected()) { + card.setSelected(true); + cardViews.get(card.getId()).update(card); + } + } else { + if (card.isSelected()) { + card.setSelected(false); + cardViews.get(card.getId()).update(card); + } + } + } + } + + private void removeCardView(CardView card) { + allCards.remove(card); + cardContent.remove(cardViews.get(card.getId())); + cardViews.remove(card.getId()); + } + + /** + * Add a card to the cardGrid, in the position that the current sort dictates + * @param newCard + */ + private void sortIntoGrid(CardView newCard) { + // Ensure row 1 exists + if (cardGrid.size() == 0) { + cardGrid.add(0, new ArrayList>()); + maxStackSize.add(0, 0); + } + // What row to add it to? + ArrayList> targetRow; + if (separateCreatures && !newCard.getCardTypes().contains(CardType.CREATURE)) { + // Ensure row 2 exists + if (cardGrid.size() < 2) { + cardGrid.add(1, new ArrayList>()); + maxStackSize.add(1, 0); + // Populate with stacks matching the first row + for (int i = 0; i < cardGrid.get(0).size(); ++i) { + cardGrid.get(1).add(new ArrayList()); + } + } + targetRow = cardGrid.get(1); + } else { + targetRow = cardGrid.get(0); + } + + // Find the right column to insert into + boolean didInsert = false; + for (int currentColumn = 0; currentColumn < cardGrid.get(0).size(); ++currentColumn) { + // Find an item from this column + CardView cardInColumn = null; + for (ArrayList> gridRow : cardGrid) { + for (CardView card : gridRow.get(currentColumn)) { + cardInColumn = card; + break; + } + } + + // No card in this column? + if (cardInColumn == null) { + // Error, should not have an empty column + LOGGER.error("Empty column!"); + } else { + int res = cardSort.getComparator().compare(newCard, cardInColumn); + if (res <= 0) { + // Insert into this col, but if less, then we need to create a new col here first + if (res < 0) { + for (int rowIndex = 0; rowIndex < cardGrid.size(); ++rowIndex) { + cardGrid.get(rowIndex).add(currentColumn, new ArrayList()); + } + } + targetRow.get(currentColumn).add(newCard); + didInsert = true; + break; + } else { + // Nothing to do, go to next iteration + } + } + } + + // If nothing else, insert in a new column after everything else + if (!didInsert) { + for (int rowIndex = 0; rowIndex < cardGrid.size(); ++rowIndex) { + cardGrid.get(rowIndex).add(new ArrayList()); + } + targetRow.get(targetRow.size()-1).add(newCard); + } + } + + /** + * Delete any empty columns / rows from the grid, and eleminate any empty space in stacks + */ + private void trimGrid() { + // Compact stacks and rows + for (int rowIndex = 0; rowIndex < cardGrid.size(); ++rowIndex) { + ArrayList> gridRow = cardGrid.get(rowIndex); + int rowMaxStackSize = 0; + for (ArrayList stack : gridRow) { + // Clear out nulls in the stack + for (int i = 0; i < stack.size(); ++i) { + if (stack.get(i) == null) { + stack.remove(i--); + } + } + // Is the stack still non-empty? + rowMaxStackSize = Math.max(rowMaxStackSize, stack.size()); + } + // Is the row empty? If so remove it + if (rowMaxStackSize == 0) { + cardGrid.remove(rowIndex); + maxStackSize.remove(rowIndex); + --rowIndex; + } else { + maxStackSize.set(rowIndex, rowMaxStackSize); + } + } + + // Remove empty columns + if (!cardGrid.isEmpty()) { + for (int colIndex = 0; colIndex < cardGrid.get(0).size(); ++colIndex) { + boolean hasContent = false; // Until contested + for (int rowIndex = 0; rowIndex < cardGrid.size(); ++rowIndex) { + if (!cardGrid.get(rowIndex).get(colIndex).isEmpty()) { + hasContent = true; + break; + } + } + if (!hasContent) { + for (int rowIndex = 0; rowIndex < cardGrid.size(); ++rowIndex) { + cardGrid.get(rowIndex).remove(colIndex); + } + --colIndex; + } + } + } + + // Clean up extra column header count labels + while (stackCountLabels.size() > cardGrid.size()) { + ArrayList labels = stackCountLabels.remove(cardGrid.size()); + for (JLabel label : labels) { + cardContent.remove(label); + } + } + int colCount = cardGrid.isEmpty() ? 0 : cardGrid.get(0).size(); + for (ArrayList labels : stackCountLabels) { + while (labels.size() > colCount) { + cardContent.remove(labels.remove(colCount)); + } + } + } + + private int getCardWidth() { + return CARD_WIDTH; + } + + private int getCardHeight() { + return (int)(1.4*getCardWidth()); + } + + /** + * Position all of the card views correctly + */ + private void layoutGrid() { + // Basic dimensions + int cardWidth = getCardWidth(); + int cardHeight = getCardHeight(); + int cardTopHeight = CardRenderer.getCardTopHeight(cardWidth); + + // Layout one at a time + int layerIndex = 0; + int currentY = COUNT_LABEL_HEIGHT; + int maxWidth = 0; + for (int rowIndex = 0; rowIndex < cardGrid.size(); ++rowIndex) { + int rowMaxStackSize = 0; + ArrayList> gridRow = cardGrid.get(rowIndex); + for (int colIndex = 0; colIndex < gridRow.size(); ++colIndex) { + ArrayList stack = gridRow.get(colIndex); + + // Stack count label + if (stackCountLabels.size() <= rowIndex) { + stackCountLabels.add(new ArrayList()); + } + if (stackCountLabels.get(rowIndex).size() <= colIndex) { + JLabel countLabel = new JLabel("", SwingConstants.CENTER); + cardContent.add(countLabel, new Integer(0)); + stackCountLabels.get(rowIndex).add(countLabel); + } + JLabel countLabel = stackCountLabels.get(rowIndex).get(colIndex); + if (stack.isEmpty()) { + countLabel.setVisible(false); + } else { + countLabel.setText("" + stack.size()); + countLabel.setLocation(GRID_PADDING + (cardWidth + GRID_PADDING) * colIndex, currentY - COUNT_LABEL_HEIGHT); + countLabel.setSize(cardWidth, COUNT_LABEL_HEIGHT); + countLabel.setVisible(true); + } + + // Max stack size + rowMaxStackSize = Math.max(rowMaxStackSize, stack.size()); + + // Layout cards in stack + for (int i = 0; i < stack.size(); ++i) { + CardView card = stack.get(i); + MageCard view = cardViews.get(card.getId()); + int x = GRID_PADDING + (cardWidth + GRID_PADDING) * colIndex; + int y = currentY + i * cardTopHeight; + view.setCardBounds(x, y, cardWidth, cardHeight); + cardContent.setLayer(view, layerIndex++); + } + } + + // Update the max stack size for this row and the max width + maxWidth = Math.max(maxWidth, GRID_PADDING + (GRID_PADDING + cardWidth) * gridRow.size()); + maxStackSize.set(rowIndex, rowMaxStackSize); + currentY += (cardTopHeight * (rowMaxStackSize - 1) + cardHeight) + COUNT_LABEL_HEIGHT; + } + + // Resize card container + cardContent.setPreferredSize(new Dimension(maxWidth, currentY - COUNT_LABEL_HEIGHT + GRID_PADDING)); + //cardContent.setSize(maxWidth, currentY - COUNT_LABEL_HEIGHT + GRID_PADDING); + } + + private static void makeButtonPopup(final AbstractButton button, final JPopupMenu popup) { + button.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + popup.show(button, 0, button.getHeight()); + } + }); + popup.addPopupMenuListener(new PopupMenuListener() { + @Override + public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { + button.setSelected(false); + } + + @Override + public void popupMenuWillBecomeVisible(PopupMenuEvent e) {} + @Override + public void popupMenuCanceled(PopupMenuEvent e) {} + }); + } + + public static void main(String[] args) { + GUISizeHelper.calculateGUISizes(); + Plugins.getInstance().loadPlugins(); + JFrame frame = new JFrame(); + frame.setTitle("Test"); + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + frame.setBackground(Color.BLUE); + DragCardGrid grid = new DragCardGrid(); + grid.setPreferredSize(new Dimension(800, 600)); + frame.add(grid, BorderLayout.CENTER); + frame.pack(); + frame.setVisible(true); + } +} + +class SelectionBox extends JComponent { + public SelectionBox() { + setOpaque(false); + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + g = g.create(); + g.setColor(new Color(100, 100, 200, 128)); + g.fillRect(0, 0, getWidth(), getHeight()); + g.setColor(new Color(0, 0, 255)); + g.drawRect(0, 0, getWidth()-1, getHeight()-1); + g.dispose(); + } +} \ No newline at end of file diff --git a/Mage.Client/src/main/java/mage/client/cards/DragCardSource.java b/Mage.Client/src/main/java/mage/client/cards/DragCardSource.java new file mode 100644 index 00000000000..eb71b9a89de --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/cards/DragCardSource.java @@ -0,0 +1,14 @@ +package mage.client.cards; + +import mage.view.CardView; + +import java.util.Collection; + +/** + * Created by StravantUser on 2016-09-22. + */ +public interface DragCardSource { + Collection dragCardList(); + void dragCardBegin(); + void dragCardEnd(DragCardTarget target); +} diff --git a/Mage.Client/src/main/java/mage/client/cards/DragCardTarget.java b/Mage.Client/src/main/java/mage/client/cards/DragCardTarget.java new file mode 100644 index 00000000000..70138889c4c --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/cards/DragCardTarget.java @@ -0,0 +1,17 @@ +package mage.client.cards; + +import mage.view.CardView; + +import java.awt.*; +import java.awt.event.MouseEvent; +import java.util.Collection; + +/** + * Created by StravantUser on 2016-09-22. + */ +public interface DragCardTarget { + void dragCardEnter(MouseEvent e); + void dragCardMove(MouseEvent e); + void dragCardExit(MouseEvent e); + void dragCardDrop(MouseEvent e, DragCardSource source, Collection cards); +} diff --git a/Mage.Client/src/main/resources/editor_insert_col.png b/Mage.Client/src/main/resources/editor_insert_col.png new file mode 100644 index 00000000000..5c087eebd5a Binary files /dev/null and b/Mage.Client/src/main/resources/editor_insert_col.png differ diff --git a/Mage.Client/src/main/resources/editor_insert_row.png b/Mage.Client/src/main/resources/editor_insert_row.png new file mode 100644 index 00000000000..9aea52eae11 Binary files /dev/null and b/Mage.Client/src/main/resources/editor_insert_row.png differ diff --git a/db/cards.h2.mv.db b/db/cards.h2.mv.db new file mode 100644 index 00000000000..0aa139fdd8d Binary files /dev/null and b/db/cards.h2.mv.db differ diff --git a/db/cards.h2.trace.db b/db/cards.h2.trace.db new file mode 100644 index 00000000000..b34c2d002e7 --- /dev/null +++ b/db/cards.h2.trace.db @@ -0,0 +1,171 @@ +09-21 19:22:40 jdbc[3]: exception +org.h2.jdbc.JdbcSQLException: Index "CLASSNAME_INDEX" not found; SQL statement: +DROP INDEX `className_index` [42112-187] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:345) + at org.h2.message.DbException.get(DbException.java:179) + at org.h2.message.DbException.get(DbException.java:155) + at org.h2.command.ddl.DropIndex.update(DropIndex.java:49) + at org.h2.command.CommandContainer.update(CommandContainer.java:78) + at org.h2.command.Command.executeUpdate(Command.java:254) + at org.h2.jdbc.JdbcPreparedStatement.execute(JdbcPreparedStatement.java:198) + at com.j256.ormlite.jdbc.JdbcCompiledStatement.runExecute(JdbcCompiledStatement.java:62) + at com.j256.ormlite.table.TableUtils.doStatements(TableUtils.java:462) + at com.j256.ormlite.table.TableUtils.doDropTable(TableUtils.java:273) + at com.j256.ormlite.table.TableUtils.dropTable(TableUtils.java:151) + at mage.cards.repository.CardRepository.(CardRepository.java:83) + at mage.cards.repository.CardRepository.(CardRepository.java:59) + at mage.cards.decks.importer.DckDeckImporter.readLine(DckDeckImporter.java:63) + at mage.cards.decks.importer.DeckImporter.importDeck(DeckImporter.java:61) + at mage.cards.decks.importer.DeckImporterUtil.importDeck(DeckImporterUtil.java:57) + at mage.client.cards.DragCardGrid$1.actionPerformed(DragCardGrid.java:78) + at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022) + at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348) + at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402) + at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259) + at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252) + at java.awt.Component.processMouseEvent(Component.java:6533) + at javax.swing.JComponent.processMouseEvent(JComponent.java:3324) + at java.awt.Component.processEvent(Component.java:6298) + at java.awt.Container.processEvent(Container.java:2236) + at java.awt.Component.dispatchEventImpl(Component.java:4889) + at java.awt.Container.dispatchEventImpl(Container.java:2294) + at java.awt.Component.dispatchEvent(Component.java:4711) + at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4888) + at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4525) + at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4466) + at java.awt.Container.dispatchEventImpl(Container.java:2280) + at java.awt.Window.dispatchEventImpl(Window.java:2746) + at java.awt.Component.dispatchEvent(Component.java:4711) + at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758) + at java.awt.EventQueue.access$500(EventQueue.java:97) + at java.awt.EventQueue$3.run(EventQueue.java:709) + at java.awt.EventQueue$3.run(EventQueue.java:703) + at java.security.AccessController.doPrivileged(Native Method) + at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76) + at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86) + at java.awt.EventQueue$4.run(EventQueue.java:731) + at java.awt.EventQueue$4.run(EventQueue.java:729) + at java.security.AccessController.doPrivileged(Native Method) + at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76) + at java.awt.EventQueue.dispatchEvent(EventQueue.java:728) + at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201) + at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116) + at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105) + at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) + at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93) + at java.awt.EventDispatchThread.run(EventDispatchThread.java:82) +09-21 19:22:40 jdbc[3]: exception +org.h2.jdbc.JdbcSQLException: Index "NAME_INDEX" not found; SQL statement: +DROP INDEX `name_index` [42112-187] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:345) + at org.h2.message.DbException.get(DbException.java:179) + at org.h2.message.DbException.get(DbException.java:155) + at org.h2.command.ddl.DropIndex.update(DropIndex.java:49) + at org.h2.command.CommandContainer.update(CommandContainer.java:78) + at org.h2.command.Command.executeUpdate(Command.java:254) + at org.h2.jdbc.JdbcPreparedStatement.execute(JdbcPreparedStatement.java:198) + at com.j256.ormlite.jdbc.JdbcCompiledStatement.runExecute(JdbcCompiledStatement.java:62) + at com.j256.ormlite.table.TableUtils.doStatements(TableUtils.java:462) + at com.j256.ormlite.table.TableUtils.doDropTable(TableUtils.java:273) + at com.j256.ormlite.table.TableUtils.dropTable(TableUtils.java:151) + at mage.cards.repository.CardRepository.(CardRepository.java:83) + at mage.cards.repository.CardRepository.(CardRepository.java:59) + at mage.cards.decks.importer.DckDeckImporter.readLine(DckDeckImporter.java:63) + at mage.cards.decks.importer.DeckImporter.importDeck(DeckImporter.java:61) + at mage.cards.decks.importer.DeckImporterUtil.importDeck(DeckImporterUtil.java:57) + at mage.client.cards.DragCardGrid$1.actionPerformed(DragCardGrid.java:78) + at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022) + at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348) + at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402) + at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259) + at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252) + at java.awt.Component.processMouseEvent(Component.java:6533) + at javax.swing.JComponent.processMouseEvent(JComponent.java:3324) + at java.awt.Component.processEvent(Component.java:6298) + at java.awt.Container.processEvent(Container.java:2236) + at java.awt.Component.dispatchEventImpl(Component.java:4889) + at java.awt.Container.dispatchEventImpl(Container.java:2294) + at java.awt.Component.dispatchEvent(Component.java:4711) + at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4888) + at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4525) + at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4466) + at java.awt.Container.dispatchEventImpl(Container.java:2280) + at java.awt.Window.dispatchEventImpl(Window.java:2746) + at java.awt.Component.dispatchEvent(Component.java:4711) + at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758) + at java.awt.EventQueue.access$500(EventQueue.java:97) + at java.awt.EventQueue$3.run(EventQueue.java:709) + at java.awt.EventQueue$3.run(EventQueue.java:703) + at java.security.AccessController.doPrivileged(Native Method) + at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76) + at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86) + at java.awt.EventQueue$4.run(EventQueue.java:731) + at java.awt.EventQueue$4.run(EventQueue.java:729) + at java.security.AccessController.doPrivileged(Native Method) + at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76) + at java.awt.EventQueue.dispatchEvent(EventQueue.java:728) + at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201) + at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116) + at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105) + at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) + at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93) + at java.awt.EventDispatchThread.run(EventDispatchThread.java:82) +09-21 19:22:40 jdbc[3]: exception +org.h2.jdbc.JdbcSQLException: Index "SETCODE_CARDNUMBER_INDEX" not found; SQL statement: +DROP INDEX `setCode_cardNumber_index` [42112-187] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:345) + at org.h2.message.DbException.get(DbException.java:179) + at org.h2.message.DbException.get(DbException.java:155) + at org.h2.command.ddl.DropIndex.update(DropIndex.java:49) + at org.h2.command.CommandContainer.update(CommandContainer.java:78) + at org.h2.command.Command.executeUpdate(Command.java:254) + at org.h2.jdbc.JdbcPreparedStatement.execute(JdbcPreparedStatement.java:198) + at com.j256.ormlite.jdbc.JdbcCompiledStatement.runExecute(JdbcCompiledStatement.java:62) + at com.j256.ormlite.table.TableUtils.doStatements(TableUtils.java:462) + at com.j256.ormlite.table.TableUtils.doDropTable(TableUtils.java:273) + at com.j256.ormlite.table.TableUtils.dropTable(TableUtils.java:151) + at mage.cards.repository.CardRepository.(CardRepository.java:83) + at mage.cards.repository.CardRepository.(CardRepository.java:59) + at mage.cards.decks.importer.DckDeckImporter.readLine(DckDeckImporter.java:63) + at mage.cards.decks.importer.DeckImporter.importDeck(DeckImporter.java:61) + at mage.cards.decks.importer.DeckImporterUtil.importDeck(DeckImporterUtil.java:57) + at mage.client.cards.DragCardGrid$1.actionPerformed(DragCardGrid.java:78) + at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022) + at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348) + at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402) + at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259) + at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252) + at java.awt.Component.processMouseEvent(Component.java:6533) + at javax.swing.JComponent.processMouseEvent(JComponent.java:3324) + at java.awt.Component.processEvent(Component.java:6298) + at java.awt.Container.processEvent(Container.java:2236) + at java.awt.Component.dispatchEventImpl(Component.java:4889) + at java.awt.Container.dispatchEventImpl(Container.java:2294) + at java.awt.Component.dispatchEvent(Component.java:4711) + at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4888) + at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4525) + at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4466) + at java.awt.Container.dispatchEventImpl(Container.java:2280) + at java.awt.Window.dispatchEventImpl(Window.java:2746) + at java.awt.Component.dispatchEvent(Component.java:4711) + at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758) + at java.awt.EventQueue.access$500(EventQueue.java:97) + at java.awt.EventQueue$3.run(EventQueue.java:709) + at java.awt.EventQueue$3.run(EventQueue.java:703) + at java.security.AccessController.doPrivileged(Native Method) + at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76) + at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86) + at java.awt.EventQueue$4.run(EventQueue.java:731) + at java.awt.EventQueue$4.run(EventQueue.java:729) + at java.security.AccessController.doPrivileged(Native Method) + at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76) + at java.awt.EventQueue.dispatchEvent(EventQueue.java:728) + at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201) + at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116) + at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105) + at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) + at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93) + at java.awt.EventDispatchThread.run(EventDispatchThread.java:82) +09-21 19:22:40 jdbc[3]: exception +org.h2.jdbc.JdbcSQLException: Table "CARD" not found; SQL statement: +DROP TABLE `card` [42102-187] diff --git a/mageclient.log b/mageclient.log new file mode 100644 index 00000000000..8d3f69adad3 --- /dev/null +++ b/mageclient.log @@ -0,0 +1,80 @@ +FATAL 2016-09-21 19:22:40,587 Could not find card '' at line 2: 3 [KTK:248] Windswept Heath +Could not find card '' at line 3: 4 [KTK:249] Wooded Foothills +Could not find card '' at line 4: 6 [BFZ:269a] Mountain +Could not find card '' at line 5: 2 [ORI:157] Pia and Kiran Nalaar +Could not find card '' at line 6: 4 [M13:170] Farseek +Could not find card '' at line 7: 2 [ZEN:172] Oracle of Mul Daya +Could not find card '' at line 8: 3 [FUT:139] Summoner's Pact +Could not find card '' at line 9: 2 [BFZ:272a] Forest +Could not find card '' at line 10: 4 [GPT:165] Stomping Ground +Could not find card '' at line 11: 4 [M11:192] Primeval Titan +Could not find card '' at line 12: 4 [ZEN:228] Valakut, the Molten Pinnacle +Could not find card '' at line 13: 4 [TSP:216] Search for Tomorrow +Could not find card '' at line 14: 4 [LEB:163] Lightning Bolt +Could not find card '' at line 15: 2 [BFZ:235] Cinder Glade +Could not find card '' at line 16: 4 [OGW:140] Oath of Nissa +Could not find card '' at line 17: 4 [CHK:239] Sakura-Tribe Elder +Could not find card '' at line 18: 4 [CHK:193] Through the Breach +Could not find card '' at line 19: SB: 1 [M15:194] Reclamation Sage +Could not find card '' at line 20: SB: 3 [M11:188] Obstinate Baloth +Could not find card '' at line 21: SB: 1 [M11:174] Gaea's Revenge +Could not find card '' at line 22: SB: 1 [TSP:143] Ancient Grudge +Could not find card '' at line 23: SB: 3 [THS:112] Anger of the Gods +Could not find card '' at line 24: SB: 1 [MM2:230] Spellskite +Could not find card '' at line 25: SB: 2 [MRD:150] Chalice of the Void +Could not find card '' at line 26: SB: 3 [EMA:231] Relic of Progenitus + =>[AWT-EventQueue-0] DeckImporter.importDeck +FATAL 2016-09-21 19:25:13,820 Could not find card '' at line 2: 3 [KTK:248] Windswept Heath +Could not find card '' at line 3: 4 [KTK:249] Wooded Foothills +Could not find card '' at line 4: 6 [BFZ:269a] Mountain +Could not find card '' at line 5: 2 [ORI:157] Pia and Kiran Nalaar +Could not find card '' at line 6: 4 [M13:170] Farseek +Could not find card '' at line 7: 2 [ZEN:172] Oracle of Mul Daya +Could not find card '' at line 8: 3 [FUT:139] Summoner's Pact +Could not find card '' at line 9: 2 [BFZ:272a] Forest +Could not find card '' at line 10: 4 [GPT:165] Stomping Ground +Could not find card '' at line 11: 4 [M11:192] Primeval Titan +Could not find card '' at line 12: 4 [ZEN:228] Valakut, the Molten Pinnacle +Could not find card '' at line 13: 4 [TSP:216] Search for Tomorrow +Could not find card '' at line 14: 4 [LEB:163] Lightning Bolt +Could not find card '' at line 15: 2 [BFZ:235] Cinder Glade +Could not find card '' at line 16: 4 [OGW:140] Oath of Nissa +Could not find card '' at line 17: 4 [CHK:239] Sakura-Tribe Elder +Could not find card '' at line 18: 4 [CHK:193] Through the Breach +Could not find card '' at line 19: SB: 1 [M15:194] Reclamation Sage +Could not find card '' at line 20: SB: 3 [M11:188] Obstinate Baloth +Could not find card '' at line 21: SB: 1 [M11:174] Gaea's Revenge +Could not find card '' at line 22: SB: 1 [TSP:143] Ancient Grudge +Could not find card '' at line 23: SB: 3 [THS:112] Anger of the Gods +Could not find card '' at line 24: SB: 1 [MM2:230] Spellskite +Could not find card '' at line 25: SB: 2 [MRD:150] Chalice of the Void +Could not find card '' at line 26: SB: 3 [EMA:231] Relic of Progenitus + =>[AWT-EventQueue-0] DeckImporter.importDeck +INFO 2016-09-21 19:25:13,827 Loaded 0 =>[AWT-EventQueue-0] DragCardGrid$1.actionPerformed +FATAL 2016-09-21 19:38:03,322 Could not find card '' at line 2: 3 [KTK:248] Windswept Heath +Could not find card '' at line 3: 4 [KTK:249] Wooded Foothills +Could not find card '' at line 4: 6 [BFZ:269a] Mountain +Could not find card '' at line 5: 2 [ORI:157] Pia and Kiran Nalaar +Could not find card '' at line 6: 4 [M13:170] Farseek +Could not find card '' at line 7: 2 [ZEN:172] Oracle of Mul Daya +Could not find card '' at line 8: 3 [FUT:139] Summoner's Pact +Could not find card '' at line 9: 2 [BFZ:272a] Forest +Could not find card '' at line 10: 4 [GPT:165] Stomping Ground +Could not find card '' at line 11: 4 [M11:192] Primeval Titan +Could not find card '' at line 12: 4 [ZEN:228] Valakut, the Molten Pinnacle +Could not find card '' at line 13: 4 [TSP:216] Search for Tomorrow +Could not find card '' at line 14: 4 [LEB:163] Lightning Bolt +Could not find card '' at line 15: 2 [BFZ:235] Cinder Glade +Could not find card '' at line 16: 4 [OGW:140] Oath of Nissa +Could not find card '' at line 17: 4 [CHK:239] Sakura-Tribe Elder +Could not find card '' at line 18: 4 [CHK:193] Through the Breach +Could not find card '' at line 19: SB: 1 [M15:194] Reclamation Sage +Could not find card '' at line 20: SB: 3 [M11:188] Obstinate Baloth +Could not find card '' at line 21: SB: 1 [M11:174] Gaea's Revenge +Could not find card '' at line 22: SB: 1 [TSP:143] Ancient Grudge +Could not find card '' at line 23: SB: 3 [THS:112] Anger of the Gods +Could not find card '' at line 24: SB: 1 [MM2:230] Spellskite +Could not find card '' at line 25: SB: 2 [MRD:150] Chalice of the Void +Could not find card '' at line 26: SB: 3 [EMA:231] Relic of Progenitus + =>[AWT-EventQueue-0] DeckImporter.importDeck +INFO 2016-09-21 19:38:03,330 Loaded 0 =>[AWT-EventQueue-0] DragCardGrid$1.actionPerformed