Merge pull request #1 from magefree/master

Implement "Pure Reflection" from Invasion.
This commit is contained in:
SpikesCafe-google 2018-01-07 19:25:02 -05:00 committed by GitHub
commit 8fc462a389
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
1256 changed files with 97818 additions and 6427 deletions

4
.gitignore vendored
View file

@ -4,7 +4,7 @@ syntax: glob
Mage.Client/*.dck
Mage.Client/db
Mage.Client/gamelogs
Mage.Client/mageclient.log
Mage.Client/*.log
Mage.Client/plugins/images
Mage.Client/plugins/plugin.data
Mage.Client/target
@ -44,6 +44,7 @@ Mage.Server.Plugins/Mage.Game.CommanderDuel/target
Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/target/
Mage.Server.Plugins/Mage.Game.FreeForAll/target
Mage.Server.Plugins/Mage.Game.MomirDuel/target
Mage.Server.Plugins/Mage.Game.MomirGame/target/
Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/target
Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/target
Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/target
@ -132,3 +133,4 @@ Mage.Client/serverlist.txt
client_secrets.json
dependency-reduced-pom.xml
mage-bundle

View file

@ -141,6 +141,18 @@
<artifactId>balloontip</artifactId>
<version>1.2.4.1</version>
</dependency>
<!-- svg support start -->
<dependency>
<groupId>batik</groupId>
<artifactId>batik-transcoder</artifactId>
<version>1.6-1</version>
</dependency>
<!-- svg support end -->
<dependency>
<groupId>org.ocpsoft.prettytime</groupId>
<artifactId>prettytime</artifactId>
<version>3.2.7.Final</version>
</dependency>
</dependencies>
<!-- to get the reference to local repository with com\googlecode\jspf\jspf-core\0.9.1\ -->

View file

@ -1,6 +1,5 @@
XMage.de 1 (Europe/Germany) fast :xmage.de:17171
woogerworks (North America/USA) :xmage.woogerworks.com:17171
xmage.lukeskywalk.com (North America) :xmage.lukeskywalk.com:17171
play.xmage.net (North America/Canada) :play.xmage.net:17171
XMageBr. (South America/Brazil) :magic.ncs3sistemas.com.br:17171
XMage.tahiti :xmage.tahiti.one:443

View file

@ -50,6 +50,7 @@ import mage.client.chat.ChatPanelBasic;
import mage.client.components.*;
import mage.client.components.ext.dlg.DialogManager;
import mage.client.components.tray.MageTray;
import mage.client.constants.Constants;
import mage.client.constants.Constants.DeckEditorMode;
import mage.client.deckeditor.DeckEditorPane;
import mage.client.deckeditor.collection.viewer.CollectionViewerPane;
@ -237,10 +238,10 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
SessionHandler.startSession(this);
callbackClient = new CallbackClientImpl(this);
connectDialog = new ConnectDialog();
desktopPane.add(connectDialog, JLayeredPane.POPUP_LAYER);
desktopPane.add(connectDialog, JLayeredPane.MODAL_LAYER);
errorDialog = new ErrorDialog();
errorDialog.setLocation(100, 100);
desktopPane.add(errorDialog, JLayeredPane.POPUP_LAYER);
desktopPane.add(errorDialog, JLayeredPane.MODAL_LAYER);
UI.addComponent(MageComponents.DESKTOP_PANE, desktopPane);
PING_TASK_EXECUTOR.scheduleAtFixedRate(() -> SessionHandler.ping(), 60, 60, TimeUnit.SECONDS);
@ -283,6 +284,9 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
balloonTip.setPositioner(new LeftAbovePositioner(0, 0));
balloonTip.setVisible(false);
// tooltips delay in ms
ToolTipManager.sharedInstance().setDismissDelay(Constants.TOOLTIPS_DELAY_MS);
mageToolbar.add(createSwitchPanelsButton(), 0);
mageToolbar.add(new javax.swing.JToolBar.Separator(), 1);
@ -427,17 +431,46 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
}
}
public static boolean isChrismasTime(Date currentTime){
// from december 15 to january 15
Calendar cal = new GregorianCalendar();
cal.setTime(currentTime);
int currentYear = cal.get(Calendar.YEAR);
if (cal.get(Calendar.MONTH) == Calendar.JANUARY){
currentYear = currentYear - 1;
}
Date chrisFrom = new GregorianCalendar(currentYear, Calendar.DECEMBER, 15).getTime();
Date chrisTo = new GregorianCalendar(currentYear + 1, Calendar.JANUARY, 15 + 1).getTime(); // end of the 15 day
return ((currentTime.equals(chrisFrom) || currentTime.after(chrisFrom))
&& currentTime.before(chrisTo));
}
private void addMageLabel() {
if (liteMode || grayMode) {
return;
}
String filename = "/label-xmage.png";
String filename;
float ratio;
if (isChrismasTime(Calendar.getInstance().getTime())){
// chrismass logo
LOGGER.info("Yo Ho Ho, Merry Christmas and a Happy New Year");
filename = "/label-xmage-christmas.png";
ratio = 539.0f / 318.0f;
}else{
// standard logo
filename = "/label-xmage.png";
ratio = 509.0f / 288.0f;
}
try {
InputStream is = this.getClass().getResourceAsStream(filename);
float ratio = 1179.0f / 678.0f;
titleRectangle = new Rectangle(540, (int) (640 / ratio));
if (is != null) {
titleRectangle = new Rectangle(540, (int) (640 / ratio));
BufferedImage image = ImageIO.read(is);
//ImageIcon resized = new ImageIcon(image.getScaledInstance(titleRectangle.width, titleRectangle.height, java.awt.Image.SCALE_SMOOTH));
title = new JLabel();
@ -919,7 +952,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
}//GEN-LAST:event_btnConnectActionPerformed
public void btnAboutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAboutActionPerformed
JInternalFrame[] windows = desktopPane.getAllFramesInLayer(JLayeredPane.POPUP_LAYER);
JInternalFrame[] windows = desktopPane.getAllFramesInLayer(JLayeredPane.MODAL_LAYER);
for (JInternalFrame window : windows) {
if (window instanceof AboutDialog) {
// don't open the window twice.
@ -927,7 +960,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
}
}
AboutDialog aboutDialog = new AboutDialog();
desktopPane.add(aboutDialog, JLayeredPane.POPUP_LAYER);
desktopPane.add(aboutDialog, JLayeredPane.MODAL_LAYER);
aboutDialog.showDialog(VERSION);
}//GEN-LAST:event_btnAboutActionPerformed
@ -1070,7 +1103,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
public void showUserRequestDialog(final UserRequestMessage userRequestMessage) {
final UserRequestDialog userRequestDialog = new UserRequestDialog();
userRequestDialog.setLocation(100, 100);
desktopPane.add(userRequestDialog, JLayeredPane.POPUP_LAYER);
desktopPane.add(userRequestDialog, JLayeredPane.MODAL_LAYER);
if (SwingUtilities.isEventDispatchThread()) {
userRequestDialog.showDialog(userRequestMessage);
} else {

View file

@ -562,7 +562,7 @@ public class Card extends MagePermanent implements MouseMotionListener, MouseLis
}
@Override
public void setTextOffset(int yOffset) {
public void setCardCaptionTopOffset(int yOffsetPercent) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}

View file

@ -53,7 +53,7 @@ public class CardArea extends JPanel implements MouseListener {
private boolean reloaded = false;
private final javax.swing.JLayeredPane cardArea;
private final javax.swing.JScrollPane scrollPane;
private int yTextOffset;
private int yCardCaptionOffsetPercent = 0; // card caption offset (use for moving card caption view center, below mana icons -- for more good UI)
private Dimension cardDimension;
private int verticalCardOffset;
@ -68,8 +68,6 @@ public class CardArea extends JPanel implements MouseListener {
setGUISize();
cardArea = new JLayeredPane();
scrollPane.setViewportView(cardArea);
yTextOffset = 10;
}
public void cleanUp() {
@ -103,10 +101,10 @@ public class CardArea extends JPanel implements MouseListener {
this.reloaded = true;
cardArea.removeAll();
if (showCards != null && showCards.size() < 10) {
yTextOffset = 10;
yCardCaptionOffsetPercent = 8; // TODO: need to test
loadCardsFew(showCards, bigCard, gameId);
} else {
yTextOffset = 0;
yCardCaptionOffsetPercent = 0;
loadCardsMany(showCards, bigCard, gameId);
}
cardArea.revalidate();
@ -118,8 +116,10 @@ public class CardArea extends JPanel implements MouseListener {
public void loadCardsNarrow(CardsView showCards, BigCard bigCard, UUID gameId) {
this.reloaded = true;
cardArea.removeAll();
yTextOffset = 0;
yCardCaptionOffsetPercent = 0; // TODO: need to test
loadCardsMany(showCards, bigCard, gameId);
cardArea.revalidate();
this.revalidate();
@ -152,7 +152,10 @@ public class CardArea extends JPanel implements MouseListener {
cardArea.moveToFront(cardPanel);
cardPanel.update(card);
cardPanel.setCardBounds(rectangle.x, rectangle.y, cardDimension.width, cardDimension.height);
cardPanel.setTextOffset(yTextOffset);
// new card have same settings as current view
cardPanel.setCardCaptionTopOffset(yCardCaptionOffsetPercent);
cardPanel.showCardTitle();
}

View file

@ -48,6 +48,7 @@ import mage.view.CardView;
import mage.view.CardsView;
import mage.view.SimpleCardView;
import org.mage.card.arcane.CardPanel;
import org.mage.card.arcane.ManaSymbolsCellRenderer;
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
@ -164,6 +165,9 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar
mainTable.getColumnModel().getColumn(6).setPreferredWidth(15);
mainTable.getColumnModel().getColumn(7).setPreferredWidth(15);
// new mana render (svg support)
mainTable.getColumnModel().getColumn(mainModel.COLUMN_INDEX_COST).setCellRenderer(new ManaSymbolsCellRenderer());
if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_DRAFT_VIEW, "cardView").equals("listView")) {
jToggleListView.setSelected(true);
panelCardArea.setViewportView(mainTable);

View file

@ -1726,7 +1726,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
// Create the card view
final MageCard cardPanel = Plugins.instance.getMageCard(card, lastBigCard, new Dimension(getCardWidth(), getCardHeight()), null, true, true);
cardPanel.update(card);
cardPanel.setTextOffset(0);
cardPanel.setCardCaptionTopOffset(0);
// Remove mouse wheel listeners so that scrolling works
// Scrolling works on all areas without cards or by using the scroll bar, that's enough

View file

@ -27,6 +27,7 @@
*/
package mage.client.constants;
import java.awt.*;
import java.io.File;
import javax.swing.BorderFactory;
import javax.swing.border.Border;
@ -68,22 +69,52 @@ public final class Constants {
public static final int POWBOX_TEXT_MAX_LEFT = 212;
public static final int DAMAGE_MAX_LEFT = 180;
// tooltip hints delay in ms (need more time to display long hints withour hiding)
public static final int TOOLTIPS_DELAY_MS = 60 * 1000;
public static final Border EMPTY_BORDER = BorderFactory.createEmptyBorder(2, 2, 2, 2);
public static final double SCALE_FACTOR = 0.5;
public static final String PLUGINS_DIRECTORY = "plugins/";
// cards render
public static final Rectangle CARD_SIZE_FULL = new Rectangle(101, 149);
public static final Rectangle THUMBNAIL_SIZE_FULL = new Rectangle(102, 146);
public static final String RESOURCE_PATH_MANA_LARGE = IO.imageBaseDir + "symbols" + File.separator + "large";
public static final String RESOURCE_PATH_MANA_MEDIUM = IO.imageBaseDir + "symbols" + File.separator + "medium";
public static final String RESOURCE_PATH_SET = IO.imageBaseDir + "sets" + File.separator;
public static final String RESOURCE_PATH_SET_SMALL = RESOURCE_PATH_SET + File.separator + "small" + File.separator;
public static final String BASE_SOUND_PATH = "sounds" + File.separator;
// resources - default images
public static final String RESOURCE_PATH_DEFAUL_IMAGES = File.separator + "default";
// resources - symbols
public static final String RESOURCE_PATH_SYMBOLS = File.separator + "symbols";
public static final String RESOURCE_SYMBOL_FOLDER_SMALL = "small";
public static final String RESOURCE_SYMBOL_FOLDER_MEDIUM = "medium";
public static final String RESOURCE_SYMBOL_FOLDER_LARGE = "large";
public static final String RESOURCE_SYMBOL_FOLDER_SVG = "svg";
public static final String RESOURCE_SYMBOL_FOLDER_PNG = "png";
public enum ResourceSymbolSize {
SMALL,
MEDIUM,
LARGE,
SVG,
PNG
}
// resources - sets
public static final String RESOURCE_PATH_SETS = File.separator + "sets";
public static final String RESOURCE_SET_FOLDER_SMALL = "small";
public static final String RESOURCE_SET_FOLDER_MEDIUM = ""; // empty, medium images laydown in "sets" folder, TODO: delete that and auto gen, use png for html, not gif
public static final String RESOURCE_SET_FOLDER_SVG = "svg";
public enum ResourceSetSize {
SMALL,
MEDIUM,
SVG
}
// sound
public static final String BASE_SOUND_PATH = "sounds" + File.separator; // TODO: check path with File.separator
public static final String BASE_MUSICS_PATH = "music" + File.separator;
public interface IO {
String imageBaseDir = "plugins" + File.separator + "images" + File.separator;
String DEFAULT_IMAGES_DIR = "plugins" + File.separator + "images" + File.separator;
String IMAGE_PROPERTIES_FILE = "image.url.properties";
}

View file

@ -42,6 +42,7 @@ import mage.cards.decks.Deck;
import mage.client.MageFrame;
import mage.client.dialog.PreferencesDialog;
import mage.client.util.gui.ColorsChooser;
import mage.client.util.gui.FastSearchUtil;
import mage.client.util.sets.ConstructedFormats;
/**
@ -106,21 +107,38 @@ public class DeckGeneratorDialog {
c.weightx = 0.10;
mainPanel.add(formatSetText, c);
// Format/set dropdown
// Format/set dropdown with search button
JPanel setPanel = new JPanel();
setPanel.setLayout(new javax.swing.BoxLayout(setPanel, javax.swing.BoxLayout.LINE_AXIS));
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 1;
c.gridy = 1;
c.ipadx = 30;
c.insets = new Insets(5, 10, 0, 10);
c.weightx = 0.90;
c.weightx = 0.80;
mainPanel.add(setPanel, c);
cbSets = new JComboBox<>(ConstructedFormats.getTypes());
cbSets.setSelectedIndex(0);
mainPanel.add(cbSets, c);
cbSets.setAlignmentX(0.0F);
setPanel.add(cbSets);
String prefSet = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_DECK_GENERATOR_SET, null);
if (prefSet != null) {
cbSets.setSelectedItem(prefSet);
}
JButton btn = new JButton();
btn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/search_32.png")));
btn.setToolTipText(FastSearchUtil.DEFAULT_EXPANSION_TOOLTIP_MESSAGE);
btn.setAlignmentX(1.0F);
btn.setPreferredSize(new java.awt.Dimension(32, 32));
btn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
FastSearchUtil.showFastSearchForStringComboBox(cbSets, FastSearchUtil.DEFAULT_EXPANSION_SEARCH_MESSAGE);
}
});
//setPanel.add(btn, c); // TODO: can't show pickdialog here... need to replace standard modal dialog (JOptionPane) to internal mage dialog
// Deck size label
c.fill = GridBagConstraints.HORIZONTAL;

View file

@ -204,6 +204,24 @@
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
<Component class="javax.swing.JButton" name="btnExpansionSearch">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/buttons/search_32.png"/>
</Property>
<Property name="toolTipText" type="java.lang.String" value="Fast search set or expansion"/>
<Property name="alignmentX" type="float" value="1.0"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="0"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[23, 23]"/>
</Property>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnExpansionSearchActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToolBar$Separator" name="jSeparator2">
</Component>
<Component class="javax.swing.JCheckBox" name="chkPennyDreadful">
@ -482,6 +500,109 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jToggleCardViewActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToolBar$Separator" name="jSeparator5">
</Component>
<Container class="javax.swing.JToolBar" name="tbRarities">
<Properties>
<Property name="floatable" type="boolean" value="false"/>
<Property name="rollover" type="boolean" value="true"/>
<Property name="toolTipText" type="java.lang.String" value="Hold the ALT-key while clicking to deselect all other card rarities or hold the CTRL-key to only select all other card rarities."/>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
<SubComponents>
<Component class="javax.swing.JToggleButton" name="tbCommon">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/buttons/rarity_common_20.png"/>
</Property>
<Property name="selected" type="boolean" value="true"/>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="&quot;&lt;html&gt;&lt;strong&gt;Common&lt;/strong&gt;&lt;br/&gt;&quot; &#xd;&#xa;+ tbRarities.getToolTipText()" type="code"/>
</Property>
<Property name="actionCommand" type="java.lang.String" value="Common"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="0"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="tbCommonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToggleButton" name="tbUncommon">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/buttons/rarity_uncommon_20.png"/>
</Property>
<Property name="selected" type="boolean" value="true"/>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="&quot;&lt;html&gt;&lt;strong&gt;Uncommon&lt;/strong&gt;&lt;br/&gt;&quot; &#xd;&#xa;+ tbUncommon.getToolTipText()" type="code"/>
</Property>
<Property name="actionCommand" type="java.lang.String" value="Uncommon"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="0"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="tbUncommonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToggleButton" name="tbRare">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/buttons/rarity_rare_20.png"/>
</Property>
<Property name="selected" type="boolean" value="true"/>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="&quot;&lt;html&gt;&lt;strong&gt;Rare&lt;/strong&gt;&lt;br/&gt;&quot; &#xd;&#xa;+ tbRarities.getToolTipText()" type="code"/>
</Property>
<Property name="actionCommand" type="java.lang.String" value="Rare"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="0"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="tbRareActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToggleButton" name="tbMythic">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/buttons/rarity_mythic_20.png"/>
</Property>
<Property name="selected" type="boolean" value="true"/>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="&quot;&lt;html&gt;&lt;strong&gt;Mythic&lt;/strong&gt;&lt;br/&gt;&quot; &#xd;&#xa;+ tbRarities.getToolTipText()" type="code"/>
</Property>
<Property name="actionCommand" type="java.lang.String" value="Mythic"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="0"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="tbMythicActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToggleButton" name="tbSpecial">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/buttons/rarity_special_20.png"/>
</Property>
<Property name="selected" type="boolean" value="true"/>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="&quot;&lt;html&gt;&lt;strong&gt;Special&lt;/strong&gt;&lt;br/&gt;&quot; &#xd;&#xa;+ tbRarities.getToolTipText()" type="code"/>
</Property>
<Property name="actionCommand" type="java.lang.String" value="Special"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="0"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="tbSpecialActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Container class="javax.swing.JScrollPane" name="cardSelectorScrollPane">

View file

@ -52,8 +52,10 @@ import mage.client.cards.*;
import mage.client.constants.Constants.SortBy;
import mage.client.deckeditor.table.TableModel;
import mage.client.util.GUISizeHelper;
import mage.client.util.gui.FastSearchUtil;
import mage.client.util.sets.ConstructedFormats;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.filter.FilterCard;
import mage.filter.predicate.Predicate;
import mage.filter.predicate.Predicates;
@ -64,6 +66,7 @@ import mage.filter.predicate.other.CardTextPredicate;
import mage.filter.predicate.other.ExpansionSetPredicate;
import mage.view.CardView;
import mage.view.CardsView;
import org.mage.card.arcane.ManaSymbolsCellRenderer;
/**
*
@ -133,6 +136,9 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
mainTable.getColumnModel().getColumn(6).setPreferredWidth(15);
mainTable.getColumnModel().getColumn(7).setPreferredWidth(15);
// new mana render (svg support)
mainTable.getColumnModel().getColumn(mainModel.COLUMN_INDEX_COST).setCellRenderer(new ManaSymbolsCellRenderer());
// mainTable.setToolTipText(cardSelectorScrollPane.getToolTipText());
cardSelectorScrollPane.setViewportView(mainTable);
mainTable.setOpaque(false);
@ -202,6 +208,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
this.btnBooster.setVisible(false);
this.btnClear.setVisible(false);
this.cbExpansionSet.setVisible(false);
this.btnExpansionSearch.setVisible(false);
this.limited = true;
this.cards.clear();
for (Card card : sideboard) {
@ -215,6 +222,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
this.btnBooster.setVisible(true);
this.btnClear.setVisible(true);
this.cbExpansionSet.setVisible(true);
this.btnExpansionSearch.setVisible(true);
// cbExpansionSet.setModel(new DefaultComboBoxModel<>(ConstructedFormats.getTypes()));
// Action event on Expansion set triggers loadCards method
cbExpansionSet.setSelectedIndex(0);
@ -321,6 +329,24 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
// criteria.types(CardType.TRIBAL);
// criteria.types(CardType.CONSPIRACY);
if (this.tbCommon.isSelected()) {
criteria.rarities(Rarity.COMMON);
criteria.rarities(Rarity.LAND);
}
if (this.tbUncommon.isSelected()) {
criteria.rarities(Rarity.UNCOMMON);
}
if (this.tbRare.isSelected()) {
criteria.rarities(Rarity.RARE);
}
if (this.tbMythic.isSelected()) {
criteria.rarities(Rarity.MYTHIC);
}
if (this.tbSpecial.isSelected()) {
criteria.rarities(Rarity.SPECIAL);
criteria.rarities(Rarity.BONUS);
}
if (this.cbExpansionSet.isVisible()) {
String expansionSelection = this.cbExpansionSet.getSelectedItem().toString();
if (!expansionSelection.equals("- All Sets")) {
@ -369,6 +395,19 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
filterCards();
}
private void filterCardsRarity(int modifiers, String actionCommand) {
// ALT or CTRL button was pushed
if ((modifiers & ActionEvent.ALT_MASK) == ActionEvent.ALT_MASK || (modifiers & ActionEvent.CTRL_MASK) == ActionEvent.CTRL_MASK) {
boolean invert = (modifiers & ActionEvent.ALT_MASK) == ActionEvent.ALT_MASK;
tbCommon.setSelected(inverter(invert, tbCommon.getActionCommand(), actionCommand));
tbUncommon.setSelected(inverter(invert, tbUncommon.getActionCommand(), actionCommand));
tbRare.setSelected(inverter(invert, tbRare.getActionCommand(), actionCommand));
tbMythic.setSelected(inverter(invert, tbMythic.getActionCommand(), actionCommand));
tbSpecial.setSelected(inverter(invert, tbSpecial.getActionCommand(), actionCommand));
}
filterCards();
}
private void filterCards() {
FilterCard filter = buildFilter();
try {
@ -467,6 +506,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
tbColorless = new javax.swing.JToggleButton();
jSeparator1 = new javax.swing.JToolBar.Separator();
cbExpansionSet = new javax.swing.JComboBox<>();
btnExpansionSearch = new javax.swing.JButton();
jSeparator2 = new javax.swing.JToolBar.Separator();
chkPennyDreadful = new javax.swing.JCheckBox();
btnBooster = new javax.swing.JButton();
@ -486,6 +526,13 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
jSeparator4 = new javax.swing.JToolBar.Separator();
jToggleListView = new javax.swing.JToggleButton();
jToggleCardView = new javax.swing.JToggleButton();
jSeparator5 = new javax.swing.JToolBar.Separator();
tbRarities = new javax.swing.JToolBar();
tbCommon = new javax.swing.JToggleButton();
tbUncommon = new javax.swing.JToggleButton();
tbRare = new javax.swing.JToggleButton();
tbMythic = new javax.swing.JToggleButton();
tbSpecial = new javax.swing.JToggleButton();
cardSelectorScrollPane = new javax.swing.JScrollPane();
cardSelectorBottomPanel = new javax.swing.JPanel();
jButtonAddToMain = new javax.swing.JButton();
@ -611,10 +658,23 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
}
});
tbColor.add(cbExpansionSet);
btnExpansionSearch.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/search_32.png"))); // NOI18N
btnExpansionSearch.setToolTipText("Fast search set or expansion");
btnExpansionSearch.setAlignmentX(1.0F);
btnExpansionSearch.setFocusable(false);
btnExpansionSearch.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
btnExpansionSearch.setPreferredSize(new java.awt.Dimension(23, 23));
btnExpansionSearch.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
btnExpansionSearch.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnExpansionSearchActionPerformed(evt);
}
});
tbColor.add(btnExpansionSearch);
tbColor.add(jSeparator2);
chkPennyDreadful.setText("Penny Dreadful");
chkPennyDreadful.setText("Penny Dreadful Only");
chkPennyDreadful.setToolTipText("Will only allow Penny Dreadful legal cards to be shown.");
chkPennyDreadful.setFocusable(false);
chkPennyDreadful.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT);
@ -624,15 +684,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
chkPilesActionPerformed(evt);
}
});
JPopupMenu filterByFormatPopup = new JPopupMenu();
filterByFormatPopup.add(chkPennyDreadful);
filterByFormatPopup.setLayout(new GridBagLayout());
ButtonGroup selectByTypeModeGroup = new ButtonGroup();
JButton filterByFormatButton = new JButton ("Filter by Format");
makeButtonPopup(filterByFormatButton, filterByFormatPopup);
tbColor.add(filterByFormatButton);
tbColor.add(chkPennyDreadful);
btnBooster.setText("Open Booster");
btnBooster.setToolTipText("(CURRENTLY NOT WORKING) Generates a booster of the selected set and adds the cards to the card selector.");
@ -828,6 +880,88 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
}
});
tbTypes.add(jToggleCardView);
tbTypes.add(jSeparator5);
tbRarities.setFloatable(false);
tbRarities.setRollover(true);
tbRarities.setToolTipText("Hold the ALT-key while clicking to deselect all other card rarities or hold the CTRL-key to only select all other card rarities.");
tbCommon.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/rarity_common_20.png"))); // NOI18N
tbCommon.setSelected(true);
tbCommon.setToolTipText("<html><strong>Common</strong><br/>"
+ tbRarities.getToolTipText());
tbCommon.setActionCommand("Common");
tbCommon.setFocusable(false);
tbCommon.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
tbCommon.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
tbCommon.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
tbCommonActionPerformed(evt);
}
});
tbRarities.add(tbCommon);
tbUncommon.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/rarity_uncommon_20.png"))); // NOI18N
tbUncommon.setSelected(true);
tbUncommon.setToolTipText("<html><strong>Uncommon</strong><br/>"
+ tbUncommon.getToolTipText());
tbUncommon.setActionCommand("Uncommon");
tbUncommon.setFocusable(false);
tbUncommon.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
tbUncommon.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
tbUncommon.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
tbUncommonActionPerformed(evt);
}
});
tbRarities.add(tbUncommon);
tbRare.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/rarity_rare_20.png"))); // NOI18N
tbRare.setSelected(true);
tbRare.setToolTipText("<html><strong>Rare</strong><br/>"
+ tbRarities.getToolTipText());
tbRare.setActionCommand("Rare");
tbRare.setFocusable(false);
tbRare.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
tbRare.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
tbRare.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
tbRareActionPerformed(evt);
}
});
tbRarities.add(tbRare);
tbMythic.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/rarity_mythic_20.png"))); // NOI18N
tbMythic.setSelected(true);
tbMythic.setToolTipText("<html><strong>Mythic</strong><br/>"
+ tbRarities.getToolTipText());
tbMythic.setActionCommand("Mythic");
tbMythic.setFocusable(false);
tbMythic.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
tbMythic.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
tbMythic.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
tbMythicActionPerformed(evt);
}
});
tbRarities.add(tbMythic);
tbSpecial.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/rarity_special_20.png"))); // NOI18N
tbSpecial.setSelected(true);
tbSpecial.setToolTipText("<html><strong>Special</strong><br/>"
+ tbRarities.getToolTipText());
tbSpecial.setActionCommand("Special");
tbSpecial.setFocusable(false);
tbSpecial.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
tbSpecial.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
tbSpecial.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
tbSpecialActionPerformed(evt);
}
});
tbRarities.add(tbSpecial);
tbTypes.add(tbRarities);
cardSelectorScrollPane.setToolTipText("<HTML>Double click to add the card to the main deck.<br/>\nALT + Double click to add the card to the sideboard.");
@ -1207,6 +1341,30 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
// TODO add your handling code here:
}//GEN-LAST:event_chkRulesActionPerformed
private void btnExpansionSearchActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnExpansionSearchActionPerformed
FastSearchUtil.showFastSearchForStringComboBox(cbExpansionSet, "Select set or expansion");
}//GEN-LAST:event_btnExpansionSearchActionPerformed
private void tbCommonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbCommonActionPerformed
filterCardsRarity(evt.getModifiers(), evt.getActionCommand());
}//GEN-LAST:event_tbCommonActionPerformed
private void tbUncommonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbUncommonActionPerformed
filterCardsRarity(evt.getModifiers(), evt.getActionCommand());
}//GEN-LAST:event_tbUncommonActionPerformed
private void tbRareActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbRareActionPerformed
filterCardsRarity(evt.getModifiers(), evt.getActionCommand());
}//GEN-LAST:event_tbRareActionPerformed
private void tbMythicActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbMythicActionPerformed
filterCardsRarity(evt.getModifiers(), evt.getActionCommand());
}//GEN-LAST:event_tbMythicActionPerformed
private void tbSpecialActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbSpecialActionPerformed
filterCardsRarity(evt.getModifiers(), evt.getActionCommand());
}//GEN-LAST:event_tbSpecialActionPerformed
private void toggleViewMode() {
if (currentView instanceof CardGrid) {
jToggleListView.setSelected(true);
@ -1249,6 +1407,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
private javax.swing.ButtonGroup bgView;
private javax.swing.JButton btnBooster;
private javax.swing.JButton btnClear;
private javax.swing.JButton btnExpansionSearch;
private javax.swing.JLabel cardCount;
private javax.swing.JLabel cardCountLabel;
private javax.swing.JPanel cardSelectorBottomPanel;
@ -1270,6 +1429,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
private javax.swing.JToolBar.Separator jSeparator2;
private javax.swing.JToolBar.Separator jSeparator3;
private javax.swing.JToolBar.Separator jSeparator4;
private javax.swing.JToolBar.Separator jSeparator5;
private javax.swing.JToolBar.Separator jSeparator6;
private javax.swing.JTextField jTextFieldSearch;
private javax.swing.JToggleButton jToggleCardView;
@ -1279,15 +1439,21 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
private javax.swing.JToggleButton tbBlue;
private javax.swing.JToolBar tbColor;
private javax.swing.JToggleButton tbColorless;
private javax.swing.JToggleButton tbCommon;
private javax.swing.JToggleButton tbCreatures;
private javax.swing.JToggleButton tbEnchantments;
private javax.swing.JToggleButton tbGreen;
private javax.swing.JToggleButton tbInstants;
private javax.swing.JToggleButton tbLand;
private javax.swing.JToggleButton tbMythic;
private javax.swing.JToggleButton tbPlaneswalkers;
private javax.swing.JToggleButton tbRare;
private javax.swing.JToolBar tbRarities;
private javax.swing.JToggleButton tbRed;
private javax.swing.JToggleButton tbSorceries;
private javax.swing.JToggleButton tbSpecial;
private javax.swing.JToolBar tbTypes;
private javax.swing.JToggleButton tbUncommon;
private javax.swing.JToggleButton tbWhite;
// End of variables declaration//GEN-END:variables

View file

@ -691,8 +691,10 @@ public class DeckEditorPanel extends javax.swing.JPanel {
break;
case 1:
btnImportFromClipboardActionPerformed(evt);
break;
case 2:
btnImportFromClipboardActionWAppendPerformed(evt);
break;
}
});
@ -803,6 +805,14 @@ public class DeckEditorPanel extends javax.swing.JPanel {
.addComponent(jSplitPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 615, Short.MAX_VALUE));
}
private void processAndShowImportErrors(StringBuilder errorMessages){
// show up errors list
if (errorMessages.length() > 0){
String mes = "Founded problems with deck: \n\n" + errorMessages.toString();
JOptionPane.showMessageDialog(MageFrame.getDesktop(), mes.substring(0, Math.min(1000, mes.length())), "Errors while loading deck", JOptionPane.WARNING_MESSAGE);
}
}
/**
* @param evt ActionEvent
*/
@ -814,11 +824,23 @@ public class DeckEditorPanel extends javax.swing.JPanel {
dialog.addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent e) {
Deck newDeck = null;
StringBuilder errorMessages = new StringBuilder();
MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR));
try {
deck = Deck.load(DeckImporterUtil.importDeck(dialog.getTmpPath()), true, true);
refreshDeck();
newDeck = Deck.load(DeckImporterUtil.importDeck(dialog.getTmpPath(), errorMessages), true, true);
processAndShowImportErrors(errorMessages);
if (newDeck != null) {
deck = newDeck;
refreshDeck();
}
} catch (GameException e1) {
JOptionPane.showMessageDialog(MageFrame.getDesktop(), e1.getMessage(), "Error loading deck", JOptionPane.ERROR_MESSAGE);
}finally {
MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
}
});
@ -836,16 +858,22 @@ public class DeckEditorPanel extends javax.swing.JPanel {
@Override
public void windowClosed(WindowEvent e) {
Deck deckToAppend = null;
StringBuilder errorMessages = new StringBuilder();
MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR));
try {
deckToAppend = Deck.load(DeckImporterUtil.importDeck(dialog.getTmpPath()), true, true);
deckToAppend = Deck.load(DeckImporterUtil.importDeck(dialog.getTmpPath(), errorMessages), true, true);
processAndShowImportErrors(errorMessages);
if (deckToAppend != null) {
deck = Deck.append(deckToAppend, deck);
refreshDeck();
}
} catch (GameException e1) {
JOptionPane.showMessageDialog(MageFrame.getDesktop(), e1.getMessage(), "Error loading deck", JOptionPane.ERROR_MESSAGE);
}finally {
MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
}
});
}
@ -875,20 +903,31 @@ public class DeckEditorPanel extends javax.swing.JPanel {
}
}
}
MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR));
try {
setCursor(new Cursor(Cursor.WAIT_CURSOR));
deck = Deck.load(DeckImporterUtil.importDeck(file.getPath()), true, true);
Deck newDeck = null;
StringBuilder errorMessages = new StringBuilder();
newDeck = Deck.load(DeckImporterUtil.importDeck(file.getPath(), errorMessages), true, true);
processAndShowImportErrors(errorMessages);
if (newDeck != null) {
deck = newDeck;
refreshDeck(true);
}
// save last deck history
try {
MageFrame.getPreferences().put("lastDeckFolder", file.getCanonicalPath());
} catch (IOException ex) {
logger.error("Error on save last load deck folder: " + ex.getMessage());
}
} catch (GameException ex) {
JOptionPane.showMessageDialog(MageFrame.getDesktop(), ex.getMessage(), "Error loading deck", JOptionPane.ERROR_MESSAGE);
} finally {
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
refreshDeck(true);
try {
if (file != null) {
MageFrame.getPreferences().put("lastDeckFolder", file.getCanonicalPath());
}
} catch (IOException ex) {
MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
}
fcSelectDeck.setSelectedFile(null);
@ -924,7 +963,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
if (!fileName.endsWith(".dck")) {
fileName += ".dck";
}
setCursor(new Cursor(Cursor.WAIT_CURSOR));
MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR));
DeckCardLists cardLists = deck.getDeckCardLists();
cardLists.setCardLayout(deckArea.getCardLayout());
cardLists.setSideboardLayout(deckArea.getSideboardLayout());
@ -932,7 +971,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
} catch (FileNotFoundException ex) {
JOptionPane.showMessageDialog(MageFrame.getDesktop(), ex.getMessage() + "\nTry ensuring that the selected directory is writable.", "Error saving deck", JOptionPane.ERROR_MESSAGE);
} finally {
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
try {
MageFrame.getPreferences().put("lastDeckFolder", file.getCanonicalPath());
@ -967,29 +1006,36 @@ public class DeckEditorPanel extends javax.swing.JPanel {
int ret = fcImportDeck.showOpenDialog(this);
if (ret == JFileChooser.APPROVE_OPTION) {
File file = fcImportDeck.getSelectedFile();
MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR));
try {
setCursor(new Cursor(Cursor.WAIT_CURSOR));
DeckImporter importer = DeckImporterUtil.getDeckImporter(file.getPath());
if (importer != null) {
deck = Deck.load(importer.importDeck(file.getPath()));
String errors = importer.getErrors();
if (!errors.isEmpty()) {
JOptionPane.showMessageDialog(MageFrame.getDesktop(), errors, "Error importing deck", JOptionPane.ERROR_MESSAGE);
StringBuilder errorMessages = new StringBuilder();
Deck newDeck = null;
newDeck = Deck.load(importer.importDeck(file.getPath(), errorMessages));
processAndShowImportErrors(errorMessages);
if (newDeck != null) {
deck = newDeck;
refreshDeck();
}
// save last deck import folder
try {
MageFrame.getPreferences().put("lastImportFolder", file.getCanonicalPath());
} catch (IOException ex) {
logger.error("Error on save last used import folder: " + ex.getMessage());
}
} else {
JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Unknown deck format", "Error importing deck", JOptionPane.ERROR_MESSAGE);
}
} catch (Exception ex) {
logger.fatal(ex);
} finally {
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
refreshDeck();
try {
if (file != null) {
MageFrame.getPreferences().put("lastImportFolder", file.getCanonicalPath());
}
} catch (IOException ex) {
MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
}
fcImportDeck.setSelectedFile(null);
@ -1031,7 +1077,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
private void btnGenDeckActionPerformed(ActionEvent evt) {
try {
setCursor(new Cursor(Cursor.WAIT_CURSOR));
MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR));
String path = DeckGenerator.generateDeck();
deck = Deck.load(DeckImporterUtil.importDeck(path), true, true);
} catch (GameException ex) {
@ -1039,7 +1085,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
} catch (DeckGeneratorException ex) {
JOptionPane.showMessageDialog(MageFrame.getDesktop(), ex.getMessage(), "Generator error", JOptionPane.ERROR_MESSAGE);
} finally {
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
refreshDeck();
}

View file

@ -44,6 +44,7 @@ import mage.client.MageFrame;
import mage.client.cards.BigCard;
import mage.client.dialog.PreferencesDialog;
import mage.client.plugins.impl.Plugins;
import mage.client.util.gui.FastSearchUtil;
import mage.client.util.sets.ConstructedFormats;
import org.apache.log4j.Logger;
@ -76,31 +77,56 @@ public final class CollectionViewerPanel extends JPanel {
}
public void initComponents() {
jPanel1 = new javax.swing.JPanel();
jPanel1.setOpaque(false);
buttonsPanel = new javax.swing.JPanel();
buttonsPanel.setOpaque(false);
bigCard = new BigCard();
BoxLayout boxlayout = new BoxLayout(jPanel1, BoxLayout.PAGE_AXIS);
jPanel1.setLayout(boxlayout);
BoxLayout boxlayout = new BoxLayout(buttonsPanel, BoxLayout.PAGE_AXIS);
buttonsPanel.setLayout(boxlayout);
btnExit = new javax.swing.JButton();
btnExit.setAlignmentX(Component.LEFT_ALIGNMENT);
jPanel1.add(btnExit);
buttonsPanel.add(btnExit);
JLabel label1 = new JLabel("Choose format:");
label1.setAlignmentX(Component.LEFT_ALIGNMENT);
label1.setForeground(Color.white);
jPanel1.add(label1);
buttonsPanel.add(label1);
// SELECT SET
// panel
setPanel = new JPanel();
setPanel.setLayout(new javax.swing.BoxLayout(setPanel, javax.swing.BoxLayout.LINE_AXIS));
setPanel.setOpaque(false);
setPanel.setPreferredSize(new Dimension(200, 25));
setPanel.setMaximumSize(new Dimension(200, 25));
setPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
buttonsPanel.add(setPanel);
// combo set
formats = new JComboBox<>(ConstructedFormats.getTypes());
formats.setSelectedItem(ConstructedFormats.getDefault());
formats.setPreferredSize(new Dimension(250, 25));
formats.setMaximumSize(new Dimension(250, 25));
formats.setAlignmentX(Component.LEFT_ALIGNMENT);
jPanel1.add(formats);
formats.setAlignmentX(0.0F);
formats.setMinimumSize(new Dimension(50, 25));
formats.setPreferredSize(new Dimension(50, 25));
formats.setMaximumSize(new Dimension(Integer.MAX_VALUE, 25));
setPanel.add(formats);
// search button
btnSetFastSearch = new JButton();
btnSetFastSearch.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/search_24.png")));
btnSetFastSearch.setToolTipText(FastSearchUtil.DEFAULT_EXPANSION_TOOLTIP_MESSAGE);
btnSetFastSearch.setAlignmentX(1.0F);
btnSetFastSearch.setMinimumSize(new java.awt.Dimension(24, 24));
btnSetFastSearch.setPreferredSize(new java.awt.Dimension(32, 32));
btnSetFastSearch.setMaximumSize(new java.awt.Dimension(32, 32));
btnSetFastSearch.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
FastSearchUtil.showFastSearchForStringComboBox(formats, FastSearchUtil.DEFAULT_EXPANSION_SEARCH_MESSAGE);
}
});
setPanel.add(btnSetFastSearch);
JLabel label2 = new JLabel("Choose size:");
label2.setAlignmentX(Component.LEFT_ALIGNMENT);
label2.setForeground(Color.white);
jPanel1.add(label2);
buttonsPanel.add(label2);
small3x3 = new JRadioButton("3x3");
small3x3.setForeground(Color.white);
@ -111,7 +137,7 @@ public final class CollectionViewerPanel extends JPanel {
mageBook.updateSize(MageBook.LAYOUT_3x3);
MageFrame.getPreferences().put(LAYOYT_CONFIG_KEY, MageBook.LAYOUT_3x3);
});
jPanel1.add(small3x3);
buttonsPanel.add(small3x3);
big4x4 = new JRadioButton("4x4");
big4x4.setForeground(Color.white);
@ -121,19 +147,19 @@ public final class CollectionViewerPanel extends JPanel {
mageBook.updateSize(MageBook.LAYOUT_4x4);
MageFrame.getPreferences().put(LAYOYT_CONFIG_KEY, MageBook.LAYOUT_4x4);
});
jPanel1.add(big4x4);
buttonsPanel.add(big4x4);
JLabel label3 = new JLabel("Switch tabs:");
label3.setAlignmentX(Component.LEFT_ALIGNMENT);
label3.setForeground(Color.white);
jPanel1.add(label3);
buttonsPanel.add(label3);
JPanel buttonPanel = new JPanel();
buttonPanel.setPreferredSize(new Dimension(200, 100));
buttonPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 100));
buttonPanel.setOpaque(false);
buttonPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
jPanel1.add(buttonPanel);
buttonsPanel.add(buttonPanel);
JButton prev = new JButton("Prev");
prev.addActionListener(e -> mageBook.prev());
@ -146,13 +172,13 @@ public final class CollectionViewerPanel extends JPanel {
JLabel label4 = new JLabel("Show cards or tokens:");
label3.setAlignmentX(Component.LEFT_ALIGNMENT);
label3.setForeground(Color.white);
jPanel1.add(label4);
buttonsPanel.add(label4);
JCheckBox cardsOrTokens = new JCheckBox("Display Cards");
cardsOrTokens.setSelected(true);
cardsOrTokens.setToolTipText("Select to show Cards or Tokens(and emblems) for the chosen set");
cardsOrTokens.addActionListener(e -> mageBook.cardsOrTokens(cardsOrTokens.isSelected()));
jPanel1.add(cardsOrTokens);
buttonsPanel.add(cardsOrTokens);
formats.addActionListener(e -> {
if (mageBook != null) {
@ -162,12 +188,12 @@ public final class CollectionViewerPanel extends JPanel {
}
});
jPanel1.add(Box.createVerticalGlue());
buttonsPanel.add(Box.createVerticalGlue());
bigCard.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
bigCard.setAlignmentX(Component.LEFT_ALIGNMENT);
bigCard.setAlignmentY(Component.BOTTOM_ALIGNMENT);
jPanel1.add(bigCard);
buttonsPanel.add(bigCard);
jPanel2 = new MageBookContainer();
jPanel2.setOpaque(false);
@ -177,13 +203,13 @@ public final class CollectionViewerPanel extends JPanel {
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, 261, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(buttonsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 261, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0)
.addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, 604, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(buttonsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, 615, Short.MAX_VALUE)
);
@ -241,8 +267,10 @@ public final class CollectionViewerPanel extends JPanel {
}
}
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel buttonsPanel;
private javax.swing.JPanel jPanel2;
private javax.swing.JPanel setPanel;
private javax.swing.JButton btnSetFastSearch;
private mage.client.cards.BigCard bigCard;
private javax.swing.JButton btnExit;
private JComboBox formats;

View file

@ -27,9 +27,7 @@
*/
package mage.client.deckeditor.collection.viewer;
import mage.cards.Card;
import mage.cards.CardDimensions;
import mage.cards.MageCard;
import mage.cards.*;
import mage.cards.repository.CardCriteria;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
@ -38,9 +36,7 @@ import mage.client.MageFrame;
import mage.client.cards.BigCard;
import mage.client.components.HoverButton;
import mage.client.plugins.impl.Plugins;
import mage.client.util.Config;
import mage.client.util.ImageHelper;
import mage.client.util.NaturalOrderCardNumberComparator;
import mage.client.util.*;
import mage.client.util.audio.AudioManager;
import mage.client.util.sets.ConstructedFormats;
import mage.components.ImagePanel;
@ -48,7 +44,6 @@ import mage.components.ImagePanelStyle;
import mage.constants.Rarity;
import mage.view.CardView;
import org.apache.log4j.Logger;
import org.mage.card.arcane.GlowText;
import org.mage.card.arcane.ManaSymbols;
import javax.imageio.ImageIO;
@ -59,17 +54,17 @@ import java.io.FileNotFoundException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.*;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
import mage.client.util.CardsViewUtil;
import mage.game.command.Emblem;
import mage.game.permanent.PermanentToken;
import mage.game.permanent.token.Token;
import mage.view.EmblemView;
import mage.view.PermanentView;
import org.mage.plugins.card.images.CardDownloadData;
import static java.lang.Math.min;
import static org.mage.plugins.card.images.DownloadPictures.getTokenCardUrls;
/**
@ -115,6 +110,7 @@ public class MageBook extends JComponent {
Image image = ImageHelper.loadImage(LEFT_PAGE_BUTTON_IMAGE_PATH);
pageLeft = new HoverButton(null, image, image, image, new Rectangle(64, 64));
//pageLeft.setBorder(BorderFactory.createLineBorder(new Color(180, 50, 0), 3, true)); //debug
pageLeft.setBounds(0, 0, 64, 64);
pageLeft.setVisible(false);
pageLeft.setObserver(() -> {
@ -146,12 +142,46 @@ public class MageBook extends JComponent {
add(jPanelCenter, BorderLayout.CENTER);
add(jPanelRight, BorderLayout.LINE_END);
cardDimensions = new CardDimensions(0.45d);
}
int captionHeight = Math.max(30, pageLeft.getHeight()); // caption size = next-prev images
private void addLeftRightPageButtons() {
jLayeredPane.add(pageLeft, JLayeredPane.DEFAULT_LAYER, 0);
jLayeredPane.add(pageRight, JLayeredPane.DEFAULT_LAYER, 1);
// Top Panel (left page + (caption / stats) + right page
jPanelTop = new JPanel();
jPanelTop.setLayout(new BorderLayout());
// jPanelTop.setBorder(BorderFactory.createLineBorder(new Color(180, 50, 150), 3, true)); // debug
jPanelTop.setPreferredSize(new Dimension(captionHeight, captionHeight));
jPanelCenter.add(jPanelTop, BorderLayout.NORTH);
// page left
pageRight.setPreferredSize(new Dimension(pageRight.getWidth(), pageRight.getHeight()));
jPanelTop.add(pageRight, BorderLayout.EAST);
// page right
pageLeft.setPreferredSize(new Dimension(pageLeft.getWidth(), pageLeft.getHeight()));
jPanelTop.add(pageLeft, BorderLayout.WEST);
// Caption Panel
jPanelCaption = new JPanel();
jPanelCaption.setLayout(new BorderLayout());
jPanelCaption.setOpaque(false);
jPanelTop.add(jPanelCaption, BorderLayout.CENTER);
// set's caption
setCaption = new JLabel();
setCaption.setHorizontalAlignment(SwingConstants.CENTER);
//setCaption.setBorder(BorderFactory.createLineBorder(new Color(180, 50, 150), 3, true)); // debug
setCaption.setFont(jLayeredPane.getFont().deriveFont(25f));
setCaption.setText("EMPTY CAPTION");
jPanelCaption.add(setCaption, BorderLayout.NORTH);
// set's info
setInfo = new JLabel();
setInfo.setHorizontalAlignment(SwingConstants.CENTER);
//setCaption.setBorder(BorderFactory.createLineBorder(new Color(180, 50, 150), 3, true)); // debug
setInfo.setFont(jLayeredPane.getFont().deriveFont(17f));
setInfo.setText("EMPTY STATS");
jPanelCaption.add(setInfo, BorderLayout.SOUTH);
cardDimensions = new CardDimensions(0.45d);
}
private void addSetTabs() {
@ -174,7 +204,7 @@ public class MageBook extends JComponent {
if (setImage != null) {
tab.setOverlayImage(setImage);
} else {
System.out.println("Couldn't find: " + "/plugins/images/sets/" + set + "-C.jpg");
System.out.println("Couldn't find symbol image: " + set + "-C.jpg");
}
tab.setSet(set);
tab.setBounds(0, y, 39, 120);
@ -217,8 +247,10 @@ public class MageBook extends JComponent {
private void showCardsOrTokens() {
stateChanged = false;
if (showCardsOrTokens) {
updateCardStats(currentSet, true);
showCards();
} else {
updateCardStats(currentSet, false);
int numTokens = showTokens();
showEmblems(numTokens);
}
@ -226,16 +258,19 @@ public class MageBook extends JComponent {
public void showCards() {
jLayeredPane.removeAll();
addLeftRightPageButtons();
// stats info
updateCardStats(currentSet, true);
List<CardInfo> cards = getCards(currentPage, currentSet);
int size = cards.size();
Rectangle rectangle = new Rectangle();
rectangle.translate(OFFSET_X, OFFSET_Y);
for (int i = 0; i < Math.min(conf.CARDS_PER_PAGE / 2, size); i++) {
for (int i = 0; i < min(conf.CARDS_PER_PAGE / 2, size); i++) {
Card card = cards.get(i).getMockCard();
addCard(new CardView(card), bigCard, null, rectangle);
rectangle = CardPosition.translatePosition(i, rectangle, conf);
}
@ -244,7 +279,7 @@ public class MageBook extends JComponent {
- (cardDimensions.frameWidth + CardPosition.GAP_X) * conf.CARD_COLUMNS + CardPosition.GAP_X - OFFSET_X;
rectangle.setLocation(second_page_x, OFFSET_Y);
for (int i = conf.CARDS_PER_PAGE / 2; i < Math.min(conf.CARDS_PER_PAGE, size); i++) {
for (int i = conf.CARDS_PER_PAGE / 2; i < min(conf.CARDS_PER_PAGE, size); i++) {
Card card = cards.get(i).getMockCard();
addCard(new CardView(card), bigCard, null, rectangle);
rectangle = CardPosition.translatePosition(i - conf.CARDS_PER_PAGE / 2, rectangle, conf);
@ -255,7 +290,6 @@ public class MageBook extends JComponent {
public int showTokens() {
jLayeredPane.removeAll();
addLeftRightPageButtons();
List<Token> tokens = getTokens(currentPage, currentSet);
int size = tokens.size();
@ -263,7 +297,7 @@ public class MageBook extends JComponent {
if (tokens != null && tokens.size() > 0) {
Rectangle rectangle = new Rectangle();
rectangle.translate(OFFSET_X, OFFSET_Y);
for (int i = 0; i < Math.min(conf.CARDS_PER_PAGE / 2, size); i++) {
for (int i = 0; i < min(conf.CARDS_PER_PAGE / 2, size); i++) {
Token token = tokens.get(i);
addToken(token, bigCard, null, rectangle);
rectangle = CardPosition.translatePosition(i, rectangle, conf);
@ -274,7 +308,7 @@ public class MageBook extends JComponent {
- (cardDimensions.frameWidth + CardPosition.GAP_X) * conf.CARD_COLUMNS + CardPosition.GAP_X - OFFSET_X;
rectangle.setLocation(second_page_x, OFFSET_Y);
for (int i = conf.CARDS_PER_PAGE / 2; i < Math.min(conf.CARDS_PER_PAGE, size); i++) {
for (int i = conf.CARDS_PER_PAGE / 2; i < min(conf.CARDS_PER_PAGE, size); i++) {
Token token = tokens.get(i);
addToken(token, bigCard, null, rectangle);
rectangle = CardPosition.translatePosition(i - conf.CARDS_PER_PAGE / 2, rectangle, conf);
@ -341,14 +375,30 @@ public class MageBook extends JComponent {
cardImg.update(card);
cardImg.setCardBounds(rectangle.x, rectangle.y, cardDimensions.frameWidth, cardDimensions.frameHeight);
cardImg.setCardCaptionTopOffset(8); // card caption below real card caption to see full name even with mana icons
boolean implemented = card.getRarity() != Rarity.NA;
// implemented label
// old code, nowadays app load only implemented cards (JayDi85, 23.11.2017)
/*
GlowText label = new GlowText();
label.setGlow(implemented ? Color.green : NOT_IMPLEMENTED, 12, 0.0f);
label.setText(implemented ? "Implemented" : "Not implemented");
int dx = implemented ? 15 : 5;
label.setBounds(rectangle.x + dx, rectangle.y + cardDimensions.frameHeight + 7, 110, 30);
jLayeredPane.add(label);
*/
// card number label
JLabel cardNumber = new JLabel();
int dy = -5; // image panel have empty space in bottom (bug?), need to move label up
cardNumber.setBounds(rectangle.x, rectangle.y + cardImg.getHeight() + dy, cardDimensions.frameWidth, 20);
cardNumber.setHorizontalAlignment(SwingConstants.CENTER);
//cardNumber.setBorder(BorderFactory.createLineBorder(new Color(180, 50, 150), 3, true));
cardNumber.setFont(jLayeredPane.getFont().deriveFont(jLayeredPane.getFont().getStyle() | Font.BOLD));
cardNumber.setText(card.getCardNumber());
jLayeredPane.add(cardNumber);
}
private void addToken(Token token, BigCard bigCard, UUID gameId, Rectangle rectangle) {
@ -386,6 +436,66 @@ public class MageBook extends JComponent {
return cards.subList(start, end);
}
private void updateCardStats(String setCode, boolean isCardsShow){
// sets do not have total cards number, it's a workaround
ExpansionSet set = Sets.findSet(setCode);
if (set != null){
setCaption.setText(set.getCode() + " - " + set.getName());
}else{
setCaption.setText("ERROR");
setInfo.setText("ERROR");
return;
}
if (!isCardsShow){
// tokens or emblems, stats not need
setInfo.setText("");
return;
}
// cards stats
int startNumber = 9999;
int endNumber = 0;
List<ExpansionSet.SetCardInfo> cards = set.getSetCardInfo();
// first run for numbers list
LinkedList<Integer> haveNumbers = new LinkedList<>();
for (ExpansionSet.SetCardInfo card: cards){
int cardNumber = card.getCardNumberAsInt();
// skip xmage special numbers for cards (TODO: replace full art cards numbers from 180+20 to 180b, 180c and vice versa like scryfall)
if(cardNumber > 500){
continue;
}
startNumber = min(startNumber, cardNumber);
endNumber = Math.max(endNumber, cardNumber);
haveNumbers.add(cardNumber);
}
// second run for empty numbers
int countHave = haveNumbers.size();
int countNotHave = 0;
if (cards.size() > 0){
for(int i = startNumber; i <= endNumber; i++){
if(!haveNumbers.contains(i)){
countNotHave++;
}
}
}
// result
setInfo.setText(String.format("Have %d cards of %d", countHave, countHave + countNotHave));
if (countNotHave > 0) {
setInfo.setForeground(new Color(150, 0, 0));
}else{
setInfo.setForeground(jLayeredPane.getForeground());
}
}
private List<Token> getTokens(int page, String set) {
ArrayList<CardDownloadData> allTokens = getTokenCardUrls();
ArrayList<Token> tokens = new ArrayList<>();
@ -573,7 +683,6 @@ public class MageBook extends JComponent {
setSize(conf.WIDTH, conf.HEIGHT);
setPreferredSize(new Dimension(conf.WIDTH, conf.HEIGHT));
setMinimumSize(new Dimension(conf.WIDTH, conf.HEIGHT));
pageRight.setBounds(conf.WIDTH - 2 * LEFT_RIGHT_PAGES_WIDTH - 64, 0, 64, 64);
addSetTabs();
showCards();
}
@ -613,7 +722,7 @@ public class MageBook extends JComponent {
_3x3Configuration() {
this.WIDTH = 950;
this.HEIGHT = 650;
this.HEIGHT = 650 + 50; // + for caption
CARD_ROWS = 3;
CARD_COLUMNS = 3;
this.CARDS_PER_PAGE = 18;
@ -626,7 +735,7 @@ public class MageBook extends JComponent {
_4x4Configuration() {
this.WIDTH = 1250;
this.HEIGHT = 850;
this.HEIGHT = 850 + 50; // + for caption
CARD_ROWS = 4;
CARD_COLUMNS = 4;
this.CARDS_PER_PAGE = 32;
@ -635,6 +744,10 @@ public class MageBook extends JComponent {
}
}
private JPanel jPanelTop;
private JPanel jPanelCaption;
private JLabel setCaption;
private JLabel setInfo;
private JPanel jPanelLeft;
private ImagePanel jPanelCenter;
private JPanel jPanelRight;
@ -645,6 +758,8 @@ public class MageBook extends JComponent {
private int currentPage = 0;
private String currentSet = "RTR";
private int currentCardsInSet = 0;
private int currentCardsNotInSet = 0;
private static CardDimensions cardDimensions = new CardDimensions(1.2d);
private static final Logger log = Logger.getLogger(MageBook.class);

View file

@ -79,6 +79,7 @@ public class TableModel extends AbstractTableModel implements ICardGrid {
private UpdateCountsCallback updateCountsCallback;
private final String column[] = {"Qty", "Name", "Cost", "Color", "Type", "Stats", "Rarity", "Set", "#"};
public final int COLUMN_INDEX_COST = 2;
private SortSetting sortSetting;
private int recentSortedColumn;
@ -239,6 +240,10 @@ public class TableModel extends AbstractTableModel implements ICardGrid {
case 1:
return c.getName();
case 2:
// new svg images version
return ManaSymbols.getStringManaCost(c.getManaCost());
/*
// old html images version
String manaCost = "";
for (String m : c.getManaCost()) {
manaCost += m;
@ -246,6 +251,8 @@ public class TableModel extends AbstractTableModel implements ICardGrid {
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:

View file

@ -85,9 +85,8 @@ public class AboutDialog extends MageDialog {
jLabel2.setText("Courtesy: BetaSteward@googlemail.com. Site: http://XMage.de/");
jLabel3.setText("Devs: BetaSteward, Noxx, Eugen.Rivniy, North, LevelX2, Jeff, Plopman, dustinconrad, emerald000.,");
jLabel4.setText("fireshoes, lunaskyrise, mnapoleon, jgod, LoneFox, drmDev, spjspj.");
jLabel3.setText("Devs: BetaSteward, Noxx, Eugen.Rivniy, North, LevelX2, Jeff, Plopman, dustinconrad, emerald000,");
jLabel4.setText("fireshoes, lunaskyrise, mnapoleon, jgod, LoneFox, drmDev, spjspj, L_J, JayDi85.");
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);

View file

@ -32,52 +32,39 @@
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="lblIsland" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblMountain" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblForest" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblLandSet" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="spnMountain" pref="85" max="32767" attributes="0"/>
<Component id="spnIsland" max="32767" attributes="0"/>
<Component id="spnForest" max="32767" attributes="0"/>
</Group>
<Component id="cbLandSet" min="-2" pref="207" max="-2" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="lblSwamp" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="14" max="-2" attributes="0"/>
<Component id="spnSwamp" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="lblPains" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="21" max="-2" attributes="0"/>
<Component id="spnPlains" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" pref="122" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="lblMountain" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblForest" alignment="1" min="-2" max="-2" attributes="0"/>
<Component id="lblLandSet" alignment="1" min="-2" max="-2" attributes="0"/>
<Component id="lblIsland" alignment="1" min="-2" max="-2" attributes="0"/>
<Component id="lblPains" alignment="1" min="-2" max="-2" attributes="0"/>
<Component id="lblSwamp" alignment="1" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="btnAutoAdd" pref="122" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnAdd" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnCancel" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="btnCancel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="btnAutoAdd" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="btnAdd" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Group type="103" alignment="0" groupAlignment="1" max="-2" attributes="0">
<Component id="spnMountain" alignment="0" pref="85" max="32767" attributes="0"/>
<Component id="spnIsland" alignment="0" pref="85" max="32767" attributes="0"/>
<Component id="spnForest" alignment="0" max="32767" attributes="0"/>
</Group>
<Group type="103" alignment="0" groupAlignment="1" max="-2" attributes="0">
<Component id="spnSwamp" alignment="0" pref="85" max="32767" attributes="0"/>
<Component id="spnPlains" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Component id="panelSet" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -85,9 +72,9 @@
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="cbLandSet" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="lblLandSet" alignment="3" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="lblLandSet" min="-2" max="-2" attributes="0"/>
<Component id="panelSet" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
@ -128,19 +115,7 @@
<SubComponents>
<Component class="javax.swing.JLabel" name="lblLandSet">
<Properties>
<Property name="text" type="java.lang.String" value="Set"/>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="cbLandSet">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="4">
<StringItem index="0" value="Item 1"/>
<StringItem index="1" value="Item 2"/>
<StringItem index="2" value="Item 3"/>
<StringItem index="3" value="Item 4"/>
</StringArray>
</Property>
<Property name="text" type="java.lang.String" value="Set:"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lblForest">
@ -227,5 +202,41 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnAutoAddActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JPanel" name="panelSet">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
<SubComponents>
<Component class="javax.swing.JComboBox" name="cbLandSet">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="4">
<StringItem index="0" value="Item 1"/>
<StringItem index="1" value="Item 2"/>
<StringItem index="2" value="Item 3"/>
<StringItem index="3" value="Item 4"/>
</StringArray>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[20, 20]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="btnSetFastSearch">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/buttons/search_24.png"/>
</Property>
<Property name="toolTipText" type="java.lang.String" value="Search for set"/>
<Property name="alignmentX" type="float" value="1.0"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[23, 23]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnSetFastSearchActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View file

@ -44,6 +44,7 @@ import mage.cards.repository.ExpansionInfo;
import mage.cards.repository.ExpansionRepository;
import mage.client.MageFrame;
import mage.client.constants.Constants.DeckEditorMode;
import mage.client.util.gui.FastSearchUtil;
import mage.constants.Rarity;
import mage.util.RandomUtil;
import org.apache.log4j.Logger;
@ -113,7 +114,14 @@ public class AddLandDialog extends MageDialog {
}
cbLandSet.setModel(new DefaultComboBoxModel(landSetNames.toArray()));
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
// windows settings
if (this.isModal()){
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
}else{
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
this.setVisible(true);
}
@ -157,7 +165,6 @@ public class AddLandDialog extends MageDialog {
jButton2 = new javax.swing.JButton();
lblLandSet = new javax.swing.JLabel();
cbLandSet = new javax.swing.JComboBox();
lblForest = new javax.swing.JLabel();
spnForest = new javax.swing.JSpinner();
lblIsland = new javax.swing.JLabel();
@ -171,14 +178,15 @@ public class AddLandDialog extends MageDialog {
btnAdd = new javax.swing.JButton();
btnCancel = new javax.swing.JButton();
btnAutoAdd = new javax.swing.JButton();
panelSet = new javax.swing.JPanel();
cbLandSet = new javax.swing.JComboBox();
btnSetFastSearch = new javax.swing.JButton();
jButton2.setText("jButton2");
setTitle("Add Land");
lblLandSet.setText("Set");
cbLandSet.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
lblLandSet.setText("Set:");
lblForest.setText("Forest");
@ -201,13 +209,42 @@ public class AddLandDialog extends MageDialog {
spnSwamp.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1));
btnAdd.setText("Add");
btnAdd.addActionListener(evt -> btnAddActionPerformed(evt));
btnAdd.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnAddActionPerformed(evt);
}
});
btnCancel.setText("Cancel");
btnCancel.addActionListener(evt -> btnCancelActionPerformed(evt));
btnCancel.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnCancelActionPerformed(evt);
}
});
btnAutoAdd.setText("Suggest");
btnAutoAdd.addActionListener(evt -> btnAutoAddActionPerformed(evt));
btnAutoAdd.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnAutoAddActionPerformed(evt);
}
});
panelSet.setLayout(new javax.swing.BoxLayout(panelSet, javax.swing.BoxLayout.LINE_AXIS));
cbLandSet.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
cbLandSet.setMinimumSize(new java.awt.Dimension(20, 20));
panelSet.add(cbLandSet);
btnSetFastSearch.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/search_24.png"))); // NOI18N
btnSetFastSearch.setToolTipText("Search for set");
btnSetFastSearch.setAlignmentX(1.0F);
btnSetFastSearch.setPreferredSize(new java.awt.Dimension(23, 23));
btnSetFastSearch.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnSetFastSearchActionPerformed(evt);
}
});
panelSet.add(btnSetFastSearch);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
@ -216,48 +253,40 @@ public class AddLandDialog extends MageDialog {
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblIsland)
.addComponent(lblMountain)
.addComponent(lblForest)
.addComponent(lblLandSet))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(spnMountain, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE)
.addComponent(spnIsland)
.addComponent(spnForest))
.addComponent(cbLandSet, javax.swing.GroupLayout.PREFERRED_SIZE, 207, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addComponent(lblSwamp)
.addGap(14, 14, 14)
.addComponent(spnSwamp))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addComponent(lblPains)
.addGap(21, 21, 21)
.addComponent(spnPlains)))
.addGap(122, 122, 122)))
.addContainerGap())
.addComponent(lblMountain)
.addComponent(lblForest, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(lblLandSet, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(lblIsland, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(lblPains, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(lblSwamp, javax.swing.GroupLayout.Alignment.TRAILING))
.addGap(18, 18, 18)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(btnCancel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(btnAutoAdd)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(btnAutoAdd, javax.swing.GroupLayout.DEFAULT_SIZE, 122, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnAdd)
.addGap(0, 0, Short.MAX_VALUE))))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnCancel))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(spnMountain, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE)
.addComponent(spnIsland, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE)
.addComponent(spnForest, javax.swing.GroupLayout.Alignment.LEADING))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(spnSwamp, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE)
.addComponent(spnPlains, javax.swing.GroupLayout.Alignment.LEADING)))
.addGap(0, 0, Short.MAX_VALUE))
.addComponent(panelSet, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(cbLandSet, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblLandSet))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblLandSet)
.addComponent(panelSet, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblForest)
@ -312,6 +341,10 @@ public class AddLandDialog extends MageDialog {
autoAddLands();
}//GEN-LAST:event_btnAutoAddActionPerformed
private void btnSetFastSearchActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSetFastSearchActionPerformed
FastSearchUtil.showFastSearchForStringComboBox(cbLandSet, FastSearchUtil.DEFAULT_EXPANSION_SEARCH_MESSAGE);
}//GEN-LAST:event_btnSetFastSearchActionPerformed
private void autoAddLands() {
int red = 0;
int green = 0;
@ -356,6 +389,7 @@ public class AddLandDialog extends MageDialog {
private javax.swing.JButton btnAdd;
private javax.swing.JButton btnAutoAdd;
private javax.swing.JButton btnCancel;
private javax.swing.JButton btnSetFastSearch;
private javax.swing.JComboBox cbLandSet;
private javax.swing.JButton jButton2;
private javax.swing.JLabel lblForest;
@ -364,6 +398,7 @@ public class AddLandDialog extends MageDialog {
private javax.swing.JLabel lblMountain;
private javax.swing.JLabel lblPains;
private javax.swing.JLabel lblSwamp;
private javax.swing.JPanel panelSet;
private javax.swing.JSpinner spnForest;
private javax.swing.JSpinner spnIsland;
private javax.swing.JSpinner spnMountain;

View file

@ -26,68 +26,76 @@
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="29" max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="lblPort" alignment="1" min="-2" max="-2" attributes="0"/>
<Component id="lblServer" min="-2" max="-2" attributes="0"/>
<Component id="lblUserName" min="-2" max="-2" attributes="0"/>
<Component id="lblPassword" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="lblFlag" alignment="1" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="lblStatus" alignment="1" max="32767" attributes="0"/>
<Component id="chkForceUpdateDB" alignment="0" max="32767" attributes="0"/>
<Component id="chkAutoConnect" alignment="0" pref="386" max="32767" attributes="0"/>
<Component id="jProxySettingsButton" min="-2" max="-2" attributes="0"/>
<Component id="cbFlag" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="txtServer" alignment="1" pref="286" max="32767" attributes="0"/>
<Component id="txtUserName" alignment="1" max="32767" attributes="0"/>
<Component id="txtPassword" alignment="1" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="txtPort" min="-2" pref="71" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnFind1" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnFind3" min="-2" pref="42" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="btnFind2" min="-2" pref="42" max="-2" attributes="0"/>
<EmptySpace min="69" pref="69" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
<Component id="btnFind" pref="92" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="lblFlag" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="btnRegister" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<Component id="btnConnect" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnForgotPassword" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnCancel" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="lblUserName" min="-2" max="-2" attributes="0"/>
<Component id="lblPassword" alignment="1" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="26" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="btnConnect" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="btnRegister" max="32767" attributes="0"/>
<Component id="btnForgotPassword" max="32767" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="btnCancel" min="-2" pref="77" max="-2" attributes="0"/>
</Group>
<Component id="lblStatus" alignment="1" max="32767" attributes="0"/>
<Component id="chkForceUpdateDB" alignment="0" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="jProxySettingsButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Component id="chkAutoConnect" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Component id="panelFlag" alignment="0" max="32767" attributes="0"/>
<Component id="txtServer" alignment="0" max="32767" attributes="0"/>
<Component id="txtUserName" alignment="0" max="32767" attributes="0"/>
<Component id="txtPassword" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<Component id="txtPort" min="-2" pref="71" max="-2" attributes="0"/>
<EmptySpace pref="11" max="32767" attributes="0"/>
<Component id="lblFastConnect" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnFind1" min="-2" pref="70" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnFind3" min="-2" pref="70" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnFind2" min="-2" pref="40" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="btnFind" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="lblServer" alignment="3" min="-2" max="-2" attributes="0"/>
@ -101,39 +109,42 @@
<Component id="btnFind1" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnFind2" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnFind3" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="lblFastConnect" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="txtUserName" min="-2" max="-2" attributes="0"/>
<Component id="lblUserName" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="txtPassword" min="-2" max="-2" attributes="0"/>
<Component id="lblPassword" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="lblFlag" max="32767" attributes="0"/>
<Component id="cbFlag" max="32767" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
<Component id="chkAutoConnect" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="chkForceUpdateDB" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jProxySettingsButton" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="47" max="32767" attributes="0"/>
<Component id="lblStatus" min="-2" pref="24" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="btnConnect" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnCancel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnForgotPassword" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="txtUserName" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="lblUserName" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="txtPassword" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="lblPassword" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
<Component id="btnRegister" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="panelFlag" min="-2" pref="20" max="-2" attributes="0"/>
<Component id="lblFlag" min="-2" pref="18" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="chkAutoConnect" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="chkForceUpdateDB" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Component id="jProxySettingsButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="lblStatus" min="-2" pref="24" max="-2" attributes="0"/>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" max="-2" attributes="0">
<Group type="102" attributes="0">
<Component id="btnRegister" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnForgotPassword" max="32767" attributes="0"/>
</Group>
<Component id="btnConnect" max="32767" attributes="0"/>
<Component id="btnCancel" alignment="0" max="32767" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="23" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -200,11 +211,6 @@
<Property name="text" type="java.lang.String" value="User flag:"/>
</Properties>
</Component>
<Component class="mage.client.util.gui.countryBox.CountryComboBox" name="cbFlag">
<Properties>
<Property name="editable" type="boolean" value="true"/>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="chkAutoConnect">
<Properties>
<Property name="text" type="java.lang.String" value="Automatically connect to this server next time"/>
@ -233,7 +239,13 @@
</Component>
<Component class="javax.swing.JButton" name="btnConnect">
<Properties>
<Property name="text" type="java.lang.String" value="Connect"/>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="11" style="1"/>
</Property>
<Property name="text" type="java.lang.String" value="Connect to server"/>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
<Insets value="[2, 2, 2, 2]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnConnectActionPerformed"/>
@ -242,6 +254,10 @@
<Component class="javax.swing.JButton" name="btnCancel">
<Properties>
<Property name="text" type="java.lang.String" value="Cancel"/>
<Property name="horizontalTextPosition" type="int" value="0"/>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
<Insets value="[2, 2, 2, 2]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnCancelActionPerformed"/>
@ -251,8 +267,11 @@
</Component>
<Component class="javax.swing.JButton" name="btnRegister">
<Properties>
<Property name="text" type="java.lang.String" value="Register new user"/>
<Property name="text" type="java.lang.String" value="Register new user..."/>
<Property name="toolTipText" type="java.lang.String" value="&lt;html&gt;XMage now supports user authentication.&lt;br&gt;Register your account before you log in.&lt;html&gt;"/>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
<Insets value="[2, 2, 2, 2]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnRegisterActionPerformed"/>
@ -260,8 +279,11 @@
</Component>
<Component class="javax.swing.JButton" name="btnForgotPassword">
<Properties>
<Property name="text" type="java.lang.String" value="Forgot password"/>
<Property name="text" type="java.lang.String" value="Forgot password..."/>
<Property name="toolTipText" type="java.lang.String" value="&lt;html&gt;You can reset your password if you have registered&lt;br&gt;your account with an email address.&lt;/html&gt;"/>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
<Insets value="[2, 2, 2, 2]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnForgotPasswordActionPerformed"/>
@ -269,12 +291,16 @@
</Component>
<Component class="javax.swing.JButton" name="btnFind1">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/flags/de.png"/>
</Property>
<Property name="text" type="java.lang.String" value="X"/>
<Property name="toolTipText" type="java.lang.String" value="Connect to xmage.de"/>
<Property name="toolTipText" type="java.lang.String" value="Connect to xmage.de (Europe, most popular)"/>
<Property name="actionCommand" type="java.lang.String" value="connectXmageDe"/>
<Property name="alignmentY" type="float" value="0.0"/>
<Property name="horizontalAlignment" type="int" value="2"/>
<Property name="horizontalTextPosition" type="int" value="2"/>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
<Insets value="[2, 2, 2, 2]"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[42, 23]"/>
</Property>
@ -293,11 +319,13 @@
<Component class="javax.swing.JButton" name="btnFind2">
<Properties>
<Property name="text" type="java.lang.String" value="L"/>
<Property name="toolTipText" type="java.lang.String" value="Connect to localhost"/>
<Property name="toolTipText" type="java.lang.String" value="Connect to localhost (local server)"/>
<Property name="actionCommand" type="java.lang.String" value="connectLocalhost"/>
<Property name="alignmentY" type="float" value="0.0"/>
<Property name="horizontalAlignment" type="int" value="2"/>
<Property name="horizontalTextPosition" type="int" value="2"/>
<Property name="horizontalTextPosition" type="int" value="0"/>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
<Insets value="[2, 2, 2, 2]"/>
</Property>
<Property name="name" type="java.lang.String" value="connectLocalhostBtn" noResource="true"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[23, 23]"/>
@ -309,12 +337,16 @@
</Component>
<Component class="javax.swing.JButton" name="btnFind3">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/flags/us.png"/>
</Property>
<Property name="text" type="java.lang.String" value="W"/>
<Property name="toolTipText" type="java.lang.String" value="Connect to woogerworks"/>
<Property name="toolTipText" type="java.lang.String" value="Connect to Woogerworks (USA)"/>
<Property name="actionCommand" type="java.lang.String" value="connectWoogerworks"/>
<Property name="alignmentY" type="float" value="0.0"/>
<Property name="horizontalAlignment" type="int" value="2"/>
<Property name="horizontalTextPosition" type="int" value="2"/>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
<Insets value="[2, 2, 2, 2]"/>
</Property>
<Property name="name" type="java.lang.String" value="connectWoogerworksBtn" noResource="true"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[23, 23]"/>
@ -324,5 +356,69 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="connectWoogerworks"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lblFastConnect">
<Properties>
<Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="btnFind1"/>
</Property>
<Property name="text" type="java.lang.String" value="Fast connect to:"/>
<Property name="name" type="java.lang.String" value="" noResource="true"/>
</Properties>
</Component>
<Container class="javax.swing.JPanel" name="panelFlag">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[189, 30]"/>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
<SubComponents>
<Component class="mage.client.util.gui.countryBox.CountryComboBox" name="cbFlag">
<Properties>
<Property name="editable" type="boolean" value="true"/>
<Property name="maximumRowCount" type="int" value="16"/>
<Property name="alignmentX" type="float" value="0.0"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[50, 18]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[278, 15]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.Box$Filler" name="filler1">
<Properties>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[5, 32767]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[5, 0]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[4, 0]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.HorizontalStrut"/>
</AuxValues>
</Component>
<Component class="javax.swing.JButton" name="btnFlagSearch">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/buttons/search_24.png"/>
</Property>
<Property name="toolTipText" type="java.lang.String" value="Fast search your flag"/>
<Property name="alignmentX" type="float" value="1.0"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[23, 23]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnFlagSearchActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View file

@ -51,14 +51,21 @@ import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;
import mage.choices.Choice;
import mage.choices.ChoiceImpl;
import mage.client.MageFrame;
import static mage.client.dialog.PreferencesDialog.KEY_CONNECTION_URL_SERVER_LIST;
import static mage.client.dialog.PreferencesDialog.KEY_CONNECT_AUTO_CONNECT;
@ -95,10 +102,10 @@ public class ConnectDialog extends MageDialog {
this.txtPassword.addActionListener(connectAction);
registerUserDialog = new RegisterUserDialog(this);
MageFrame.getDesktop().add(registerUserDialog, JLayeredPane.POPUP_LAYER);
MageFrame.getDesktop().add(registerUserDialog, JLayeredPane.MODAL_LAYER);
resetPasswordDialog = new ResetPasswordDialog(this);
MageFrame.getDesktop().add(resetPasswordDialog, JLayeredPane.POPUP_LAYER);
MageFrame.getDesktop().add(resetPasswordDialog, JLayeredPane.MODAL_LAYER);
}
public void showDialog() {
@ -152,7 +159,6 @@ public class ConnectDialog extends MageDialog {
lblPassword = new javax.swing.JLabel();
txtPassword = new javax.swing.JPasswordField();
lblFlag = new javax.swing.JLabel();
cbFlag = new mage.client.util.gui.countryBox.CountryComboBox();
chkAutoConnect = new javax.swing.JCheckBox();
chkForceUpdateDB = new javax.swing.JCheckBox();
jProxySettingsButton = new javax.swing.JButton();
@ -164,6 +170,11 @@ public class ConnectDialog extends MageDialog {
btnFind1 = new javax.swing.JButton();
btnFind2 = new javax.swing.JButton();
btnFind3 = new javax.swing.JButton();
lblFastConnect = new javax.swing.JLabel();
panelFlag = new javax.swing.JPanel();
cbFlag = new mage.client.util.gui.countryBox.CountryComboBox();
filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(5, 0), new java.awt.Dimension(4, 0), new java.awt.Dimension(5, 32767));
btnFlagSearch = new javax.swing.JButton();
setTitle("Connect to server");
setNormalBounds(new java.awt.Rectangle(100, 100, 410, 307));
@ -174,7 +185,11 @@ public class ConnectDialog extends MageDialog {
btnFind.setText("Find...");
btnFind.setToolTipText("Shows the list of public servers");
btnFind.setName("findServerBtn"); // NOI18N
btnFind.addActionListener(evt -> findPublicServerActionPerformed(evt));
btnFind.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
findPublicServerActionPerformed(evt);
}
});
lblPort.setLabelFor(txtPort);
lblPort.setText("Port:");
@ -194,119 +209,194 @@ public class ConnectDialog extends MageDialog {
lblFlag.setLabelFor(txtUserName);
lblFlag.setText("User flag:");
cbFlag.setEditable(true);
chkAutoConnect.setText("Automatically connect to this server next time");
chkAutoConnect.setToolTipText("<HTML>If active this connect dialog will not be shown if you choose to connect.<br>\nInstead XMage tries to connect to the last server you were connected to.");
chkAutoConnect.addActionListener(evt -> chkAutoConnectActionPerformed(evt));
chkAutoConnect.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
chkAutoConnectActionPerformed(evt);
}
});
chkForceUpdateDB.setText("Force update of card database");
chkForceUpdateDB.setToolTipText("<HTML>If active the comparison of the server cards database to the client database will be enforced.<br>If not, the comparison will only done if the database version of the client is lower than the version of the server.");
chkForceUpdateDB.addActionListener(evt -> chkForceUpdateDBActionPerformed(evt));
chkForceUpdateDB.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
chkForceUpdateDBActionPerformed(evt);
}
});
jProxySettingsButton.setText("Proxy Settings...");
jProxySettingsButton.addActionListener(evt -> jProxySettingsButtonActionPerformed(evt));
jProxySettingsButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jProxySettingsButtonActionPerformed(evt);
}
});
btnConnect.setText("Connect");
btnConnect.addActionListener(evt -> btnConnectActionPerformed(evt));
btnConnect.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
btnConnect.setText("Connect to server");
btnConnect.setMargin(new java.awt.Insets(2, 2, 2, 2));
btnConnect.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnConnectActionPerformed(evt);
}
});
btnCancel.setText("Cancel");
btnCancel.addActionListener(evt -> btnCancelActionPerformed(evt));
btnCancel.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
btnCancel.setMargin(new java.awt.Insets(2, 2, 2, 2));
btnCancel.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnCancelActionPerformed(evt);
}
});
btnRegister.setText("Register new user");
btnRegister.setText("Register new user...");
btnRegister.setToolTipText("<html>XMage now supports user authentication.<br>Register your account before you log in.<html>");
btnRegister.addActionListener(evt -> btnRegisterActionPerformed(evt));
btnRegister.setMargin(new java.awt.Insets(2, 2, 2, 2));
btnRegister.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnRegisterActionPerformed(evt);
}
});
btnForgotPassword.setText("Forgot password");
btnForgotPassword.setText("Forgot password...");
btnForgotPassword.setToolTipText("<html>You can reset your password if you have registered<br>your account with an email address.</html>");
btnForgotPassword.addActionListener(evt -> btnForgotPasswordActionPerformed(evt));
btnForgotPassword.setMargin(new java.awt.Insets(2, 2, 2, 2));
btnForgotPassword.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnForgotPasswordActionPerformed(evt);
}
});
btnFind1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/flags/de.png"))); // NOI18N
btnFind1.setText("X");
btnFind1.setToolTipText("Connect to xmage.de");
btnFind1.setToolTipText("Connect to xmage.de (Europe, most popular)");
btnFind1.setActionCommand("connectXmageDe");
btnFind1.setAlignmentY(0.0F);
btnFind1.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
btnFind1.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT);
btnFind1.setMargin(new java.awt.Insets(2, 2, 2, 2));
btnFind1.setMaximumSize(new java.awt.Dimension(42, 23));
btnFind1.setMinimumSize(new java.awt.Dimension(42, 23));
btnFind1.setName("connectXmageDeBtn"); // NOI18N
btnFind1.setPreferredSize(new java.awt.Dimension(23, 23));
btnFind1.addActionListener(evt -> connectXmageDe(evt));
btnFind1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
connectXmageDe(evt);
}
});
btnFind2.setText("L");
btnFind2.setToolTipText("Connect to localhost");
btnFind2.setToolTipText("Connect to localhost (local server)");
btnFind2.setActionCommand("connectLocalhost");
btnFind2.setAlignmentY(0.0F);
btnFind2.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
btnFind2.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT);
btnFind2.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
btnFind2.setMargin(new java.awt.Insets(2, 2, 2, 2));
btnFind2.setName("connectLocalhostBtn"); // NOI18N
btnFind2.setPreferredSize(new java.awt.Dimension(23, 23));
btnFind2.addActionListener(evt -> connectLocalhost(evt));
btnFind2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
connectLocalhost(evt);
}
});
btnFind3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/flags/us.png"))); // NOI18N
btnFind3.setText("W");
btnFind3.setToolTipText("Connect to woogerworks");
btnFind3.setToolTipText("Connect to Woogerworks (USA)");
btnFind3.setActionCommand("connectWoogerworks");
btnFind3.setAlignmentY(0.0F);
btnFind3.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
btnFind3.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT);
btnFind3.setMargin(new java.awt.Insets(2, 2, 2, 2));
btnFind3.setName("connectWoogerworksBtn"); // NOI18N
btnFind3.setPreferredSize(new java.awt.Dimension(23, 23));
btnFind3.addActionListener(evt -> connectWoogerworks(evt));
btnFind3.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
connectWoogerworks(evt);
}
});
lblFastConnect.setLabelFor(btnFind1);
lblFastConnect.setText("Fast connect to:");
lblFastConnect.setName(""); // NOI18N
panelFlag.setPreferredSize(new java.awt.Dimension(189, 30));
panelFlag.setLayout(new javax.swing.BoxLayout(panelFlag, javax.swing.BoxLayout.LINE_AXIS));
cbFlag.setEditable(true);
cbFlag.setMaximumRowCount(16);
cbFlag.setAlignmentX(0.0F);
cbFlag.setMinimumSize(new java.awt.Dimension(50, 18));
cbFlag.setPreferredSize(new java.awt.Dimension(278, 15));
panelFlag.add(cbFlag);
panelFlag.add(filler1);
btnFlagSearch.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/search_24.png"))); // NOI18N
btnFlagSearch.setToolTipText("Fast search your flag");
btnFlagSearch.setAlignmentX(1.0F);
btnFlagSearch.setPreferredSize(new java.awt.Dimension(23, 23));
btnFlagSearch.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnFlagSearchActionPerformed(evt);
}
});
panelFlag.add(btnFlagSearch);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(29, 29, 29)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(lblPort)
.addComponent(lblServer)
.addComponent(lblUserName)
.addComponent(lblPassword))
.addComponent(lblFlag, javax.swing.GroupLayout.Alignment.TRAILING))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblServer)))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addComponent(lblFlag)))
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblStatus, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(chkForceUpdateDB, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(chkAutoConnect, javax.swing.GroupLayout.DEFAULT_SIZE, 386, Short.MAX_VALUE)
.addComponent(jProxySettingsButton)
.addComponent(cbFlag, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(txtServer, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 286, Short.MAX_VALUE)
.addComponent(txtUserName, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(txtPassword, javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(layout.createSequentialGroup()
.addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnFind1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnFind3, javax.swing.GroupLayout.PREFERRED_SIZE, 42, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnFind2, javax.swing.GroupLayout.PREFERRED_SIZE, 42, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(69, 69, 69)))
.addGap(8, 8, 8)
.addComponent(btnFind, javax.swing.GroupLayout.DEFAULT_SIZE, 92, Short.MAX_VALUE))))
.addComponent(lblUserName)
.addComponent(lblPassword, javax.swing.GroupLayout.Alignment.TRAILING))))
.addGap(0, 0, 0)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(btnConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(btnRegister, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(btnForgotPassword, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 77, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(lblStatus, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(chkForceUpdateDB, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(jProxySettingsButton)
.addGap(0, 0, Short.MAX_VALUE))
.addComponent(chkAutoConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(btnRegister)
.addComponent(panelFlag, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(txtServer, javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(txtUserName, javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(txtPassword, javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(btnConnect)
.addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 11, Short.MAX_VALUE)
.addComponent(lblFastConnect)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnForgotPassword)
.addComponent(btnFind1, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnCancel)))
.addGap(26, 26, 26)))
.addComponent(btnFind3, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnFind2, javax.swing.GroupLayout.PREFERRED_SIZE, 40, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGap(0, 0, 0)
.addComponent(btnFind)))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblServer)
@ -318,35 +408,37 @@ public class ConnectDialog extends MageDialog {
.addComponent(lblPort)
.addComponent(btnFind1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(btnFind2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(btnFind3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(btnFind3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblFastConnect))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(txtUserName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblUserName))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblPassword))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(lblFlag, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(cbFlag, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGap(5, 5, 5)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(panelFlag, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblFlag, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(chkAutoConnect)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(chkForceUpdateDB)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jProxySettingsButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 47, Short.MAX_VALUE)
.addComponent(lblStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(btnConnect)
.addComponent(btnCancel)
.addComponent(btnForgotPassword))
.addGap(3, 3, 3)
.addComponent(btnRegister)
.addContainerGap())
.addComponent(lblStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addGroup(layout.createSequentialGroup()
.addComponent(btnRegister, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnForgotPassword, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(btnConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(btnCancel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGap(23, 23, 23))
);
pack();
@ -640,6 +732,45 @@ public class ConnectDialog extends MageDialog {
this.txtPassword.setText(MagePreferences.getPassword(serverAddress));
}//GEN-LAST:event_connectWoogerworks
private void btnFlagSearchActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnFlagSearchActionPerformed
doFastFlagSearch();
}//GEN-LAST:event_btnFlagSearchActionPerformed
private void doFastFlagSearch(){
Choice choice = new ChoiceImpl(false);
// collect data from country combobox String[name][code]
Map<String, String> choiceItems = new LinkedHashMap<>();
DefaultComboBoxModel flagModel = (DefaultComboBoxModel)cbFlag.getModel();
String[] flagItem;
for(int i = 0; i < flagModel.getSize(); i++){
flagItem = (String[])flagModel.getElementAt(i);
choiceItems.put(flagItem[1], flagItem[0]);
}
choice.setKeyChoices(choiceItems);
choice.setMessage("Select your country");
// current selection value restore
String needSelectValue = null;
flagItem = (String[])flagModel.getSelectedItem();
if (flagItem != null){
needSelectValue = flagItem[1];
}
// ask for new value
PickChoiceDialog dlg = new PickChoiceDialog();
dlg.setWindowSize(300, 500);
dlg.showDialog(choice, needSelectValue);
if(choice.isChosen()){
flagItem = new String[2];
flagItem[0] = choice.getChoiceValue();
flagItem[1] = choice.getChoiceKey();
flagModel.setSelectedItem(flagItem);
}
}
public String getServer() {
return this.txtServer.getText();
}
@ -655,18 +786,22 @@ public class ConnectDialog extends MageDialog {
private javax.swing.JButton btnFind1;
private javax.swing.JButton btnFind2;
private javax.swing.JButton btnFind3;
private javax.swing.JButton btnFlagSearch;
private javax.swing.JButton btnForgotPassword;
private javax.swing.JButton btnRegister;
private mage.client.util.gui.countryBox.CountryComboBox cbFlag;
private javax.swing.JCheckBox chkAutoConnect;
private javax.swing.JCheckBox chkForceUpdateDB;
private javax.swing.Box.Filler filler1;
private javax.swing.JButton jProxySettingsButton;
private javax.swing.JLabel lblFastConnect;
private javax.swing.JLabel lblFlag;
private javax.swing.JLabel lblPassword;
private javax.swing.JLabel lblPort;
private javax.swing.JLabel lblServer;
private javax.swing.JLabel lblStatus;
private javax.swing.JLabel lblUserName;
private javax.swing.JPanel panelFlag;
private javax.swing.JPasswordField txtPassword;
private javax.swing.JTextField txtPort;
private javax.swing.JTextField txtServer;

View file

@ -45,8 +45,8 @@ import java.awt.event.MouseEvent;
import java.beans.PropertyVetoException;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import javax.swing.*;
import mage.client.MageFrame;
import org.apache.log4j.Logger;
@ -74,11 +74,34 @@ public class MageDialog extends javax.swing.JInternalFrame {
@Override
public void show() {
super.show();
this.toFront();
// frames desktop ordering
// more info https://docs.oracle.com/javase/7/docs/api/javax/swing/JLayeredPane.html
// WARNING, use
// - JLayeredPane.DEFAULT_LAYER: tables and games (tabs)
// - JLayeredPane.PALETTE_LAYER: toolbars and info windows like cards list, not modal dialogs (not required user actions)
// - JLayeredPane.MODAL_LAYER: all modal dialogs (user required actions - select cards in game, new game window, error windows)
// - JLayeredPane.POPUP_LAYER: hints and other top level graphics
// - JLayeredPane.DRAG_LAYER: top most layer for critical actions and user controls
/*
JInternalFrame[] frames = MageFrame.getDesktop().getAllFrames();
System.out.println("---");
for(JInternalFrame frame: frames){
int zorder = -1;
if (frame.getParent() != null){
frame.getParent().getComponentZOrder(frame);
}
System.out.println(frame.getClass() + " (" + frame.getTitle() + ") : layer = " + frame.getLayer() + ", zorder = " + zorder);
}
*/
if (modal) {
this.setClosable(false);
}
if (this.modal) {
this.toFront();
if (modal){
startModal();
}
}
@ -108,7 +131,6 @@ public class MageDialog extends javax.swing.JInternalFrame {
}
private synchronized void startModal() {
try {
if (SwingUtilities.isEventDispatchThread()) {
EventQueue theQueue = getToolkit().getSystemEventQueue();

View file

@ -47,6 +47,7 @@ import mage.cards.repository.ExpansionRepository;
import mage.client.MageFrame;
import mage.client.SessionHandler;
import mage.client.table.TournamentPlayerPanel;
import mage.client.util.gui.FastSearchUtil;
import mage.constants.MatchTimeLimit;
import mage.constants.MultiplayerAttackOption;
import mage.constants.RangeOfInfluence;
@ -76,7 +77,7 @@ public class NewTournamentDialog extends MageDialog {
private RandomPacksSelectorDialog randomPackSelector;
private JTextArea txtRandomPacks;
private final List<TournamentPlayerPanel> players = new ArrayList<>();
private final List<JComboBox> packs = new ArrayList<>();
private final List<JPanel> packPanels = new ArrayList<>();
private static final int CONSTRUCTION_TIME_MIN = 6;
private static final int CONSTRUCTION_TIME_MAX = 30;
private boolean isRandom = false;
@ -586,8 +587,13 @@ public class NewTournamentDialog extends MageDialog {
tOptions.getLimitedOptions().getSetCodes().addAll(selected);
}
} else {
for (JComboBox pack : packs) {
tOptions.getLimitedOptions().getSetCodes().add(((ExpansionInfo) pack.getSelectedItem()).getCode());
for (JPanel panel : packPanels) {
JComboBox combo = findComboInComponent(panel);
if(combo != null) {
tOptions.getLimitedOptions().getSetCodes().add(((ExpansionInfo) combo.getSelectedItem()).getCode());
}else{
logger.error("Can't find combo component in " + panel.toString());
}
}
}
tOptions.getMatchOptions().setDeckType("Limited");
@ -884,35 +890,89 @@ public class NewTournamentDialog extends MageDialog {
}
private void createPacks(int numPacks) {
while (packs.size() > numPacks) {
pnlPacks.remove(packs.get(packs.size() - 1));
packs.remove(packs.size() - 1);
while (packPanels.size() > numPacks) {
pnlPacks.remove(packPanels.get(packPanels.size() - 1));
packPanels.remove(packPanels.size() - 1);
}
while (packs.size() < numPacks) {
while (packPanels.size() < numPacks) {
// SELECT PACK
// panel
JPanel setPanel = new JPanel();
setPanel.setLayout(new javax.swing.BoxLayout(setPanel, javax.swing.BoxLayout.LINE_AXIS));
setPanel.setOpaque(false);
//setPanel.setPreferredSize(new Dimension(200, 25));
//setPanel.setMaximumSize(new Dimension(200, 25));
pnlPacks.add(setPanel);
packPanels.add(setPanel); // for later access
// combo set
JComboBox pack = new JComboBox();
pack = new JComboBox();
pack.setModel(new DefaultComboBoxModel(ExpansionRepository.instance.getWithBoostersSortedByReleaseDate()));
pnlPacks.add(pack);
packs.add(pack);
pack.addActionListener(evt -> packActionPerformed(evt));
pack.setAlignmentX(0.0F);
pack.setMinimumSize(new Dimension(50, 25));
pack.setPreferredSize(new Dimension(50, 25));
pack.setMaximumSize(new Dimension(Integer.MAX_VALUE, 25));
setPanel.add(pack);
// search button
JButton searchButton = new JButton();
searchButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/search_24.png")));
searchButton.setToolTipText("Search and select from list");
searchButton.setAlignmentX(1.0F);
searchButton.setMinimumSize(new java.awt.Dimension(24, 24));
searchButton.setPreferredSize(new java.awt.Dimension(32, 32));
searchButton.setMaximumSize(new java.awt.Dimension(32, 32));
searchButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
// search combo box near button (must be only one combo in panel)
JButton button = (JButton)evt.getSource();
JComboBox combo = findComboInComponent(button.getParent());
if (combo != null) {
FastSearchUtil.showFastSearchForStringComboBox(combo, "Select value");
}
}
});
setPanel.add(searchButton);
}
this.pack();
this.revalidate();
this.repaint();
}
private void packActionPerformed(java.awt.event.ActionEvent evt) {
boolean start = false;
int selectedIndex = 0;
for (JComboBox pack : packs) {
if (!start) {
if (evt.getSource().equals(pack)) {
start = true;
selectedIndex = pack.getSelectedIndex();
}
} else {
pack.setSelectedIndex(selectedIndex);
private JComboBox findComboInComponent(Container panel){
// search combo box near button (must be only one combo in panel)
JComboBox combo = null;
for(Component comp: panel.getComponents()){
if (comp instanceof JComboBox){
combo = (JComboBox)comp;
break;
}
}
return combo;
}
private void packActionPerformed(java.awt.event.ActionEvent evt) {
// fill all bottom combobox with same value
JComboBox curentCombo = (JComboBox)evt.getSource();
int newValue = curentCombo.getSelectedIndex();
// search start index
int startIndex = 0;
for(int i = 0; i < packPanels.size(); i++){
JComboBox pack = findComboInComponent(packPanels.get(i));
if (pack.equals(curentCombo)){
startIndex = i + 1;
break;
}
}
// change all from start index
for(int i = startIndex; i < packPanels.size(); i++){
JComboBox pack = findComboInComponent(packPanels.get(i));
pack.setSelectedIndex(newValue);
}
}
private void createPlayers(int numPlayers) {
@ -1054,16 +1114,22 @@ public class NewTournamentDialog extends MageDialog {
int packNumber = 0;
for (String pack : packsArray) {
packNumber++;
if (this.packs.size() >= packNumber - 1) {
JComboBox comboBox = this.packs.get(packNumber - 1);
ComboBoxModel model = comboBox.getModel();
int size = model.getSize();
for (int i = 0; i < size; i++) {
ExpansionInfo element = (ExpansionInfo) model.getElementAt(i);
if (element.getCode().equals(pack.trim())) {
comboBox.setSelectedIndex(i);
break;
if (this.packPanels.size() >= packNumber - 1) {
JPanel panel = packPanels.get(packNumber - 1);
JComboBox comboBox = findComboInComponent(panel);
if (comboBox != null) {
ComboBoxModel model = comboBox.getModel();
int size = model.getSize();
for (int i = 0; i < size; i++) {
ExpansionInfo element = (ExpansionInfo) model.getElementAt(i);
if (element.getCode().equals(pack.trim())) {
comboBox.setSelectedIndex(i);
break;
}
}
}else{
logger.error("Can't find combo component in " + panel.toString());
}
}

View file

@ -1,13 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JInternalFrameFormInfo">
<Properties>
<Property name="resizable" type="boolean" value="true"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[280, 200]"/>
</Property>
<Property name="name" type="java.lang.String" value="" noResource="true"/>
</Properties>
<Form version="1.9" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JInternalFrameFormInfo">
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
</SyntheticProperties>
@ -26,19 +19,13 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="jScrollPane1" alignment="0" pref="335" max="32767" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="btnAutoSelect" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnOk" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnCancel" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="lblMessage" alignment="0" pref="335" max="32767" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="scrollList" alignment="1" max="32767" attributes="0"/>
<Component id="panelCommands" alignment="0" max="32767" attributes="0"/>
<Component id="panelHeader" alignment="0" max="32767" attributes="0"/>
<Component id="panelSearch" alignment="1" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
@ -47,74 +34,173 @@
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Component id="lblMessage" min="-2" pref="37" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="panelHeader" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane1" pref="158" max="32767" attributes="0"/>
<Component id="panelSearch" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="btnCancel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnOk" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnAutoSelect" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Component id="scrollList" pref="246" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="panelCommands" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="btnAutoSelect">
<Properties>
<Property name="text" type="java.lang.String" value="Auto select"/>
<Property name="toolTipText" type="java.lang.String" value="If you select an effect with &quot;Auto select&quot;, this effect will be selected the next time automatically first."/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnAutoSelectActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnCancel">
<Properties>
<Property name="text" type="java.lang.String" value="Cancel"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnCancelActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnOk">
<Properties>
<Property name="text" type="java.lang.String" value="OK"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnOkActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Container class="javax.swing.JPanel" name="panelHeader">
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="labelMessage" alignment="1" pref="210" max="32767" attributes="0"/>
<Component id="labelSubMessage" alignment="1" pref="210" max="32767" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="labelMessage" max="32767" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="labelSubMessage" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JList" name="lstChoices">
<Component class="javax.swing.JLabel" name="labelMessage">
<Properties>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor">
<StringArray count="5">
<StringItem index="0" value="Item 1"/>
<StringItem index="1" value="Item 2"/>
<StringItem index="2" value="Item 3"/>
<StringItem index="3" value="Item 4"/>
<StringItem index="4" value="Item 5"/>
</StringArray>
<Property name="horizontalAlignment" type="int" value="0"/>
<Property name="text" type="java.lang.String" value="&lt;html&gt;&lt;div style=&apos;text-align: center;&apos;&gt;example long message example long message example long message example long message example long message&lt;/div&gt;&lt;/html&gt;"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="labelSubMessage">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true">
<Font bold="true" component="labelSubMessage" italic="true" property="font" relativeSize="true" size="0"/>
</FontInfo>
</Property>
<Property name="horizontalAlignment" type="int" value="0"/>
<Property name="text" type="java.lang.String" value="&lt;html&gt;&lt;div style=&apos;text-align: center;&apos;&gt;example long message example long&lt;/div&gt;&lt;/html&gt;"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="lblMessage">
<Properties>
<Property name="horizontalAlignment" type="int" value="0"/>
<Property name="text" type="java.lang.String" value="message"/>
</Properties>
</Component>
<Container class="javax.swing.JPanel" name="panelSearch">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="labelSearch" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="editSearch" max="32767" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="labelSearch" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="editSearch" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="labelSearch">
<Properties>
<Property name="text" type="java.lang.String" value="Search:"/>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="editSearch">
<Properties>
<Property name="text" type="java.lang.String" value="sample search text"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JScrollPane" name="scrollList">
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="listChoices">
<Properties>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor">
<StringArray count="3">
<StringItem index="0" value="item1"/>
<StringItem index="1" value="item2"/>
<StringItem index="2" value="item3"/>
</StringArray>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value=""/>
</AuxValues>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="panelCommands">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="32767" attributes="0"/>
<Component id="btOK" linkSize="3" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btCancel" linkSize="3" min="-2" pref="70" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="32767" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="btCancel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btOK" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="btOK">
<Properties>
<Property name="text" type="java.lang.String" value="Choose"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btOKActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_AddingCodePost" type="java.lang.String" value="getRootPane().setDefaultButton(btOK);"/>
</AuxValues>
</Component>
<Component class="javax.swing.JButton" name="btCancel">
<Properties>
<Property name="text" type="java.lang.String" value="Cancel"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btCancelActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View file

@ -1,43 +1,28 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
/*
* PickNumberDialog.java
*
* Created on Feb 25, 2010, 12:03:39 PM
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mage.client.dialog;
import java.awt.Dimension;
import java.awt.Point;
import java.util.Map;
import java.util.UUID;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.*;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.DefaultListModel;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.KeyStroke;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import mage.choices.Choice;
import mage.client.MageFrame;
import mage.client.util.SettingsManager;
@ -46,38 +31,145 @@ import mage.client.util.gui.MageDialogState;
/**
*
* @author BetaSteward_at_googlemail.com
* @author JayDi85
*/
public class PickChoiceDialog extends MageDialog {
/** Creates new form PickNumberDialog */
public PickChoiceDialog() {
initComponents();
this.setModal(true);
}
Choice choice;
boolean autoSelect;
ArrayList<KeyValueItem> allItems = new ArrayList<>();
DefaultListModel<KeyValueItem> dataModel = new DefaultListModel();
final private static String HTML_TEMPLATE = "<html><div style='text-align: center;'>%s</div></html>";
public void showDialog(Choice choice) {
showDialog(choice, null, null, null);
}
public void showDialog(Choice choice, String startSelectionValue) {
showDialog(choice, null, null, startSelectionValue);
}
public void showDialog(Choice choice, UUID objectId, MageDialogState mageDialogState) {
this.lblMessage.setText("<html>" + choice.getMessage());
showDialog(choice, objectId, mageDialogState, null);
}
public void showDialog(Choice choice, UUID objectId, MageDialogState mageDialogState, String startSelectionValue) {
this.choice = choice;
this.autoSelect = false;
btnAutoSelect.setVisible(choice.isKeyChoice());
if (choice.isKeyChoice()){
ComboItem[] comboItems = new ComboItem[choice.getKeyChoices().size()];
int count = 0;
for (Map.Entry<String, String> entry : choice.getKeyChoices().entrySet()) {
comboItems[count] = new ComboItem(entry.getKey(), entry.getValue());
count++;
setLabelText(this.labelMessage, choice.getMessage());
setLabelText(this.labelSubMessage, choice.getSubMessage());
btCancel.setEnabled(!choice.isRequired());
// 2 modes: string or key-values
// sore data in allItems for inremental filtering
// http://logicbig.com/tutorials/core-java-tutorial/swing/list-filter/
this.allItems.clear();
if (choice.isKeyChoice()){
for (Map.Entry<String, String> entry: choice.getKeyChoices().entrySet()) {
this.allItems.add(new KeyValueItem(entry.getKey(), entry.getValue()));
}
this.lstChoices.setListData(comboItems);
} else {
this.lstChoices.setListData(choice.getChoices().toArray());
for (String value: choice.getChoices()){
this.allItems.add(new KeyValueItem(value, value));
}
}
// sorting
if(choice.isSortEnabled()){
Collections.sort(this.allItems, new Comparator<KeyValueItem>() {
@Override
public int compare(KeyValueItem o1, KeyValueItem o2) {
Integer n1 = choice.getSortData().get(o1.Key);
Integer n2 = choice.getSortData().get(o2.Key);
return n1.compareTo(n2);
}
});
}
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
// search
if(choice.isSearchEnabled())
{
panelSearch.setVisible(true);
this.editSearch.setText(choice.getSearchText());
}else{
panelSearch.setVisible(false);
this.editSearch.setText("");
}
// listeners for inremental filtering
editSearch.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
choice.setSearchText(editSearch.getText());
loadData();
}
@Override
public void removeUpdate(DocumentEvent e) {
choice.setSearchText(editSearch.getText());
loadData();
}
@Override
public void changedUpdate(DocumentEvent e) {
choice.setSearchText(editSearch.getText());
loadData();
}
});
// listeners for select up and down without edit focus lost
editSearch.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {
//System.out.println("types");
}
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_UP){
doPrevSelect();
}else if(e.getKeyCode() == KeyEvent.VK_DOWN){
doNextSelect();
}
}
@Override
public void keyReleased(KeyEvent e) {
//System.out.println("released");
}
});
// listeners double click choose
listChoices.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if(e.getClickCount() == 2){
doChoose();
}
}
});
// listeners for ESC close
if(!choice.isRequired()){
String cancelName = "cancel";
InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName);
ActionMap actionMap = getRootPane().getActionMap();
actionMap.put(cancelName, new AbstractAction() {
public void actionPerformed(ActionEvent e) {
doCancel();
}
});
}
// window settings
if (this.isModal()){
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
}else{
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
if (mageDialogState != null) {
mageDialogState.setStateToDialog(this);
@ -86,155 +178,317 @@ public class PickChoiceDialog extends MageDialog {
this.setLocation(centered.x, centered.y);
GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, this);
}
// final load
loadData();
// start selection
if((startSelectionValue != null)){
int selectIndex = -1;
for(int i = 0; i < this.listChoices.getModel().getSize(); i++){
KeyValueItem listItem = (KeyValueItem)this.listChoices.getModel().getElementAt(i);
if (listItem.Key.equals(startSelectionValue)){
selectIndex = i;
break;
}
}
if(selectIndex >= 0){
this.listChoices.setSelectedIndex(selectIndex);
this.listChoices.ensureIndexIsVisible(selectIndex);
}
}
this.setVisible(true);
}
public boolean isAutoSelect() {
return autoSelect;
public void setWindowSize(int width, int heigth){
this.setSize(new Dimension(width, heigth));
}
private void loadData(){
// load data to datamodel after filter or on startup
String filter = choice.getSearchText();
if (filter == null){ filter = ""; }
filter = filter.toLowerCase();
this.dataModel.clear();
for(KeyValueItem item: this.allItems){
if(!choice.isSearchEnabled() || item.Value.toLowerCase().contains(filter)){
this.dataModel.addElement(item);
}
}
}
private void setLabelText(JLabel label, String text){
if ((text != null) && !text.equals("")){
label.setText(String.format(HTML_TEMPLATE, text));
label.setVisible(true);
}else{
label.setText("");
label.setVisible(false);
}
}
private void doNextSelect(){
int newSel = this.listChoices.getSelectedIndex() + 1;
int maxSel = this.listChoices.getModel().getSize() - 1;
if(newSel <= maxSel){
this.listChoices.setSelectedIndex(newSel);
this.listChoices.ensureIndexIsVisible(newSel);
}
}
private void doPrevSelect(){
int newSel = this.listChoices.getSelectedIndex() - 1;
if(newSel >= 0){
this.listChoices.setSelectedIndex(newSel);
this.listChoices.ensureIndexIsVisible(newSel);
}
}
public void setChoice() {
if (this.lstChoices.getSelectedValue() == null) {
choice.clearChoice();
private void doChoose(){
if(setChoice()){
this.hideDialog();
}
}
private void doCancel(){
this.listChoices.clearSelection();
this.choice.clearChoice();
hideDialog();
}
/**
* Creates new form PickChoiceDialog
*/
public PickChoiceDialog() {
initComponents();
this.listChoices.setModel(dataModel);
this.setModal(true);
}
public boolean setChoice() {
KeyValueItem item = (KeyValueItem)this.listChoices.getSelectedValue();
// auto select one item (after incemental filtering)
if((item == null) && (this.listChoices.getModel().getSize() == 1)){
this.listChoices.setSelectedIndex(0);
item = (KeyValueItem)this.listChoices.getSelectedValue();
}
if (choice.isKeyChoice()) {
ComboItem item = (ComboItem)this.lstChoices.getSelectedValue();
if (item != null) {
choice.setChoiceByKey(item.getValue());
} else {
choice.clearChoice();
if(item != null){
if(choice.isKeyChoice()){
choice.setChoiceByKey(item.getKey());
}else{
choice.setChoice(item.getKey());
}
} else {
choice.setChoice((String)this.lstChoices.getSelectedValue());
return true;
}else{
choice.clearChoice();
return false;
}
}
class KeyValueItem
{
private final String Key;
private final String Value;
public KeyValueItem(String value, String label) {
this.Key = value;
this.Value = label;
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
public String getKey() {
return this.Key;
}
public String getValue() {
return this.Value;
}
@Override
public String toString() {
return this.Value;
}
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
btnAutoSelect = new javax.swing.JButton();
btnCancel = new javax.swing.JButton();
btnOk = new javax.swing.JButton();
jScrollPane1 = new javax.swing.JScrollPane();
lstChoices = new javax.swing.JList();
lblMessage = new javax.swing.JLabel();
panelHeader = new javax.swing.JPanel();
labelMessage = new javax.swing.JLabel();
labelSubMessage = new javax.swing.JLabel();
panelSearch = new javax.swing.JPanel();
labelSearch = new javax.swing.JLabel();
editSearch = new javax.swing.JTextField();
scrollList = new javax.swing.JScrollPane();
listChoices = new javax.swing.JList();
panelCommands = new javax.swing.JPanel();
btOK = new javax.swing.JButton();
btCancel = new javax.swing.JButton();
setResizable(true);
setMinimumSize(new java.awt.Dimension(280, 200));
setName(""); // NOI18N
labelMessage.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
labelMessage.setText("<html><div style='text-align: center;'>example long message example long message example long message example long message example long message</div></html>");
btnAutoSelect.setText("Auto select");
btnAutoSelect.setToolTipText("If you select an effect with \"Auto select\", this effect will be selected the next time automatically first.");
btnAutoSelect.addActionListener(evt -> btnAutoSelectActionPerformed(evt));
labelSubMessage.setFont(labelSubMessage.getFont().deriveFont((labelSubMessage.getFont().getStyle() | java.awt.Font.ITALIC) | java.awt.Font.BOLD));
labelSubMessage.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
labelSubMessage.setText("<html><div style='text-align: center;'>example long message example long</div></html>");
btnCancel.setText("Cancel");
btnCancel.addActionListener(evt -> btnCancelActionPerformed(evt));
javax.swing.GroupLayout panelHeaderLayout = new javax.swing.GroupLayout(panelHeader);
panelHeader.setLayout(panelHeaderLayout);
panelHeaderLayout.setHorizontalGroup(
panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(panelHeaderLayout.createSequentialGroup()
.addGroup(panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(labelMessage, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 210, Short.MAX_VALUE)
.addComponent(labelSubMessage, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 210, Short.MAX_VALUE))
.addGap(0, 0, 0))
);
panelHeaderLayout.setVerticalGroup(
panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(panelHeaderLayout.createSequentialGroup()
.addGap(0, 0, 0)
.addComponent(labelMessage)
.addGap(0, 0, 0)
.addComponent(labelSubMessage))
);
btnOk.setText("OK");
btnOk.addActionListener(evt -> btnOkActionPerformed(evt));
labelSearch.setText("Search:");
lstChoices.setModel(new javax.swing.AbstractListModel() {
final String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
editSearch.setText("sample search text");
javax.swing.GroupLayout panelSearchLayout = new javax.swing.GroupLayout(panelSearch);
panelSearch.setLayout(panelSearchLayout);
panelSearchLayout.setHorizontalGroup(
panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(panelSearchLayout.createSequentialGroup()
.addGap(0, 0, 0)
.addComponent(labelSearch)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(editSearch)
.addGap(0, 0, 0))
);
panelSearchLayout.setVerticalGroup(
panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(panelSearchLayout.createSequentialGroup()
.addGap(3, 3, 3)
.addGroup(panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(labelSearch)
.addComponent(editSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(3, 3, 3))
);
listChoices.setModel(new javax.swing.AbstractListModel() {
String[] strings = { "item1", "item2", "item3" };
public int getSize() { return strings.length; }
public Object getElementAt(int i) { return strings[i]; }
});
jScrollPane1.setViewportView(lstChoices);
scrollList.setViewportView(listChoices);
lblMessage.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
lblMessage.setText("message");
btOK.setText("Choose");
btOK.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btOKActionPerformed(evt);
}
});
btCancel.setText("Cancel");
btCancel.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btCancelActionPerformed(evt);
}
});
javax.swing.GroupLayout panelCommandsLayout = new javax.swing.GroupLayout(panelCommands);
panelCommands.setLayout(panelCommandsLayout);
panelCommandsLayout.setHorizontalGroup(
panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(panelCommandsLayout.createSequentialGroup()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(btOK)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
panelCommandsLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {btCancel, btOK});
panelCommandsLayout.setVerticalGroup(
panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(panelCommandsLayout.createSequentialGroup()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(btCancel)
.addComponent(btOK))
.addContainerGap())
);
getRootPane().setDefaultButton(btOK);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 335, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(btnAutoSelect)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnOk)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnCancel))
.addComponent(lblMessage, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 335, Short.MAX_VALUE))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(scrollList, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(panelCommands, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(panelHeader, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(panelSearch, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(6, 6, 6)
.addComponent(lblMessage, javax.swing.GroupLayout.PREFERRED_SIZE, 37, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap()
.addComponent(panelHeader, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 158, Short.MAX_VALUE)
.addComponent(panelSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(btnCancel)
.addComponent(btnOk)
.addComponent(btnAutoSelect))
.addGap(10, 10, 10))
.addComponent(scrollList, javax.swing.GroupLayout.DEFAULT_SIZE, 246, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void btnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOkActionPerformed
setChoice();
this.hideDialog();
}//GEN-LAST:event_btnOkActionPerformed
private void btOKActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btOKActionPerformed
doChoose();
}//GEN-LAST:event_btOKActionPerformed
private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed
this.lstChoices.clearSelection();
this.choice.clearChoice();
this.hideDialog();
}//GEN-LAST:event_btnCancelActionPerformed
private void btCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btCancelActionPerformed
doCancel();
}//GEN-LAST:event_btCancelActionPerformed
private void btnAutoSelectActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAutoSelectActionPerformed
this.autoSelect = true;
setChoice();
this.hideDialog();
}//GEN-LAST:event_btnAutoSelectActionPerformed
/**
* Closes the dialog
*/
private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog
doCancel();
}//GEN-LAST:event_closeDialog
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton btnAutoSelect;
private javax.swing.JButton btnCancel;
private javax.swing.JButton btnOk;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JLabel lblMessage;
private javax.swing.JList lstChoices;
private javax.swing.JButton btCancel;
private javax.swing.JButton btOK;
private javax.swing.JTextField editSearch;
private javax.swing.JLabel labelMessage;
private javax.swing.JLabel labelSearch;
private javax.swing.JLabel labelSubMessage;
private javax.swing.JList listChoices;
private javax.swing.JPanel panelCommands;
private javax.swing.JPanel panelHeader;
private javax.swing.JPanel panelSearch;
private javax.swing.JScrollPane scrollList;
// End of variables declaration//GEN-END:variables
}
class ComboItem {
private final String value;
private final String label;
public ComboItem(String value, String label) {
this.value = value;
this.label = label;
}
public String getValue() {
return this.value;
}
public String getLabel() {
return this.label;
}
@Override
public String toString() {
return label;
}
}

View file

@ -35,7 +35,9 @@
package mage.client.dialog;
import java.awt.Point;
import javax.swing.SpinnerNumberModel;
import javax.swing.*;
import mage.client.MageFrame;
import mage.client.util.SettingsManager;
import mage.client.util.gui.GuiDisplayUtil;
@ -60,6 +62,13 @@ public class PickNumberDialog extends MageDialog {
this.btnCancel.setVisible(false);
this.pack();
// window settings
if (this.isModal()){
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
}else{
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
Point centered = SettingsManager.instance.getComponentPosition(getWidth(), getHeight());
this.setLocation(centered.x, centered.y);
GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, this);

View file

@ -114,6 +114,14 @@ public class PickPileDialog extends MageDialog {
this.revalidate();
this.repaint();
this.setModal(true);
// window settings
if (this.isModal()){
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
}else{
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
this.setVisible(true);
}

View file

@ -120,15 +120,19 @@ public class ShowCardsDialog extends MageDialog {
this.cardArea.addCardEventListener(eventListener);
}
if (getParent() != MageFrame.getDesktop() /*|| this.isClosed*/) {
MageFrame.getDesktop().add(this, JLayeredPane.DEFAULT_LAYER);
}
pack();
this.revalidate();
this.repaint();
this.setModal(modal);
// window settings
if (this.isModal()){
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
}else{
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
SwingUtilities.invokeLater(() -> {
if (!positioned) {
int width = ShowCardsDialog.this.getWidth();

View file

@ -791,7 +791,7 @@ public final class GamePanel extends javax.swing.JPanel {
if (!exiles.containsKey(exile.getId())) {
CardInfoWindowDialog newExile = new CardInfoWindowDialog(ShowType.EXILE, exile.getName());
exiles.put(exile.getId(), newExile);
MageFrame.getDesktop().add(newExile, JLayeredPane.MODAL_LAYER);
MageFrame.getDesktop().add(newExile, JLayeredPane.PALETTE_LAYER);
newExile.show();
}
exiles.get(exile.getId()).loadCards(exile, bigCard, gameId);
@ -1004,7 +1004,7 @@ public final class GamePanel extends javax.swing.JPanel {
}
CardInfoWindowDialog newGraveyard = new CardInfoWindowDialog(ShowType.GRAVEYARD, playerName);
graveyardWindows.put(playerName, newGraveyard);
MageFrame.getDesktop().add(newGraveyard, JLayeredPane.MODAL_LAYER);
MageFrame.getDesktop().add(newGraveyard, JLayeredPane.PALETTE_LAYER);
newGraveyard.loadCards(graveyards.get(playerName), bigCard, gameId, false);
}
@ -1039,7 +1039,7 @@ public final class GamePanel extends javax.swing.JPanel {
if (!windowMap.containsKey(name)) {
cardInfoWindowDialog = new CardInfoWindowDialog(showType, name);
windowMap.put(name, cardInfoWindowDialog);
MageFrame.getDesktop().add(cardInfoWindowDialog, JLayeredPane.MODAL_LAYER);
MageFrame.getDesktop().add(cardInfoWindowDialog, JLayeredPane.PALETTE_LAYER);
} else {
cardInfoWindowDialog = windowMap.get(name);
}
@ -1115,7 +1115,7 @@ public final class GamePanel extends javax.swing.JPanel {
}
this.feedbackPanel.getFeedback(required ? FeedbackMode.INFORM : FeedbackMode.CANCEL, message, gameView.getSpecial(), options0, messageId);
if (dialog != null) {
this.pickTarget.add(dialog);
this.pickTarget.add(dialog); // TODO: 01.01.2018, JayDi85: why feedbackPanel saved to pickTarget list? Need to research
}
}
@ -1220,14 +1220,17 @@ public final class GamePanel extends javax.swing.JPanel {
public void getChoice(Choice choice, UUID objectId) {
hideAll();
// TODO: remember last choices and search incremental for same events?
PickChoiceDialog pickChoice = new PickChoiceDialog();
pickChoice.showDialog(choice, objectId, choiceWindowState);
if (choice.isKeyChoice()) {
SessionHandler.sendPlayerString(gameId, choice.getChoiceKey());
/* // old code, auto complete was for auto scripting?
if (pickChoice.isAutoSelect()) {
SessionHandler.sendPlayerString(gameId, '#' + choice.getChoiceKey());
} else {
SessionHandler.sendPlayerString(gameId, choice.getChoiceKey());
}
}*/
} else {
SessionHandler.sendPlayerString(gameId, choice.getChoice());
}

View file

@ -51,7 +51,9 @@ import javax.swing.UIManager;
import mage.client.SessionHandler;
import mage.client.components.MageTextArea;
import mage.client.constants.Constants;
import mage.client.game.FeedbackPanel.FeedbackMode;
import static mage.client.game.FeedbackPanel.FeedbackMode.QUESTION;
import mage.client.util.GUISizeHelper;
import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_ID_NO;
@ -82,7 +84,6 @@ public class HelperPanel extends JPanel {
private javax.swing.JButton linkSpecial;
private javax.swing.JButton linkUndo;
private final int defaultDismissTimeout = ToolTipManager.sharedInstance().getDismissDelay();
private final Object tooltipBackground = UIManager.get("info");
private static final String CMD_AUTO_ANSWER_ID_YES = "cmdAutoAnswerIdYes";
@ -232,13 +233,13 @@ public class HelperPanel extends JPanel {
@Override
public void mouseEntered(MouseEvent me) {
ToolTipManager.sharedInstance().setDismissDelay(100000);
ToolTipManager.sharedInstance().setDismissDelay(100 * 1000);
UIManager.put("info", Color.DARK_GRAY);
}
@Override
public void mouseExited(MouseEvent me) {
ToolTipManager.sharedInstance().setDismissDelay(defaultDismissTimeout);
ToolTipManager.sharedInstance().setDismissDelay(Constants.TOOLTIPS_DELAY_MS);
UIManager.put("info", tooltipBackground);
}
});

View file

@ -32,9 +32,11 @@ import org.apache.log4j.Logger;
import org.mage.plugins.card.CardPluginImpl;
import org.mage.plugins.theme.ThemePluginImpl;
import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
public enum Plugins implements MagePlugins {
instance;
public static final String PLUGINS_DIRECTORY = "plugins/";
public static final String PLUGINS_DIRECTORY = "plugins";
private static final Logger LOGGER = Logger.getLogger(Plugins.class);
private static PluginManager pm;
@ -48,9 +50,10 @@ public enum Plugins implements MagePlugins {
@Override
public void loadPlugins() {
LOGGER.info("Loading plugins...");
pm = PluginManagerFactory.createPluginManager();
pm.addPluginsFrom(new File(PLUGINS_DIRECTORY).toURI());
pm.addPluginsFrom(new File(PLUGINS_DIRECTORY + File.separator).toURI());
this.cardPlugin = new CardPluginImpl();
this.counterPlugin = pm.getPlugin(CounterPlugin.class);
this.themePlugin = new ThemePluginImpl();
@ -131,10 +134,8 @@ public enum Plugins implements MagePlugins {
@Override
public void downloadSymbols() {
String useDefault = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_USE_DEFAULT, "true");
String path = useDefault.equals("true") ? null : PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PATH, null);
if (this.cardPlugin != null) {
this.cardPlugin.downloadSymbols(path);
this.cardPlugin.downloadSymbols(getImagesDir());
}
}

View file

@ -46,6 +46,9 @@ import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import mage.cards.decks.importer.DeckImporterUtil;
import mage.client.MageFrame;
import mage.client.SessionHandler;
@ -54,7 +57,6 @@ import mage.client.components.MageComponents;
import mage.client.dialog.*;
import static mage.client.dialog.PreferencesDialog.KEY_TABLES_COLUMNS_ORDER;
import static mage.client.dialog.PreferencesDialog.KEY_TABLES_COLUMNS_WIDTH;
import static mage.client.table.TablesPanel.PASSWORDED;
import mage.client.util.ButtonColumn;
import mage.client.util.GUISizeHelper;
import mage.client.util.IgnoreList;
@ -70,6 +72,9 @@ import mage.view.RoomUsersView;
import mage.view.TableView;
import mage.view.UserRequestMessage;
import org.apache.log4j.Logger;
import org.ocpsoft.prettytime.PrettyTime;
import org.ocpsoft.prettytime.units.JustNow;
import org.ocpsoft.prettytime.Duration;
/**
*
@ -80,7 +85,6 @@ public class TablesPanel extends javax.swing.JPanel {
private static final Logger LOGGER = Logger.getLogger(TablesPanel.class);
private static final int[] DEFAULT_COLUMNS_WIDTH = {35, 150, 120, 180, 80, 120, 80, 60, 40, 40, 60};
public static final String PASSWORDED = "***";
private final TableTableModel tableModel;
private final MatchesTableModel matchesModel;
private UUID roomId;
@ -94,12 +98,62 @@ public class TablesPanel extends javax.swing.JPanel {
private java.util.List<String> messages;
private int currentMessage;
private final MageTableRowSorter activeTablesSorter;
private final MageTableRowSorter completedTablesSorter;
private final ButtonColumn actionButton1;
private final ButtonColumn actionButton2;
final JToggleButton[] filterButtons;
// time formater
private PrettyTime timeFormater = new PrettyTime();
// time ago renderer
TableCellRenderer timeAgoCellRenderer = new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
Date d = (Date)value;
label.setText(timeFormater.format(d));
return label;
}
};
// duration renderer
TableCellRenderer durationCellRenderer = new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
Long ms = (Long)value;
if(ms != 0){
Duration dur = timeFormater.approximateDuration(new Date(ms));
label.setText((timeFormater.formatDuration(dur)));
}else{
label.setText("");
}
return label;
}
};
// datetime render
TableCellRenderer datetimeCellRenderer = new DefaultTableCellRenderer() {
DateFormat datetimeFormater = new SimpleDateFormat("HH:mm:ss");
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
Date d = (Date)value;
if(d != null){
label.setText(datetimeFormater.format(d));
}else{
label.setText("");
}
return label;
}
};
/**
* Creates new form TablesPanel
*/
@ -112,20 +166,56 @@ public class TablesPanel extends javax.swing.JPanel {
initComponents();
// tableModel.setSession(session);
tableTables.createDefaultColumnsFromModel();
// formater
timeFormater.setLocale(Locale.ENGLISH);
JustNow jn = timeFormater.getUnit(JustNow.class);
jn.setMaxQuantity(1000L * 30L); // 30 seconds gap (show "just now" from 0 to 30 secs)
// 1. TABLE CURRENT
tableTables.createDefaultColumnsFromModel();
activeTablesSorter = new MageTableRowSorter(tableModel);
tableTables.setRowSorter(activeTablesSorter);
// time ago
tableTables.getColumnModel().getColumn(TableTableModel.COLUMN_CREATED).setCellRenderer(timeAgoCellRenderer);
/* date sorter (not need, default is good - see getColumnClass)
activeTablesSorter.setComparator(TableTableModel.COLUMN_CREATED, new Comparator<Date>() {
@Override
public int compare(Date v1, Date v2) {
return v1.compareTo(v2);
}
});*/
// default sort by created date (last games from above)
ArrayList list = new ArrayList();
list.add(new RowSorter.SortKey(TableTableModel.COLUMN_CREATED, SortOrder.DESCENDING));
activeTablesSorter.setSortKeys(list);
TableUtil.setColumnWidthAndOrder(tableTables, DEFAULT_COLUMNS_WIDTH,
PreferencesDialog.KEY_TABLES_COLUMNS_WIDTH, PreferencesDialog.KEY_TABLES_COLUMNS_ORDER);
PreferencesDialog.KEY_TABLES_COLUMNS_WIDTH, PreferencesDialog.KEY_TABLES_COLUMNS_ORDER); // TODO: is sort order save and restore after app restart/window open?
tableCompleted.setRowSorter(new MageTableRowSorter(matchesModel));
// 2. TABLE COMPLETED
completedTablesSorter = new MageTableRowSorter(matchesModel);
tableCompleted.setRowSorter(completedTablesSorter);
// duration
tableCompleted.getColumnModel().getColumn(MatchesTableModel.COLUMN_DURATION).setCellRenderer(durationCellRenderer);
// start-end
tableCompleted.getColumnModel().getColumn(MatchesTableModel.COLUMN_START).setCellRenderer(datetimeCellRenderer);
tableCompleted.getColumnModel().getColumn(MatchesTableModel.COLUMN_END).setCellRenderer(datetimeCellRenderer);
// default sort by ended date (last games from above)
ArrayList list2 = new ArrayList();
list2.add(new RowSorter.SortKey(MatchesTableModel.COLUMN_END, SortOrder.DESCENDING));
completedTablesSorter.setSortKeys(list2);
// 3. CHAT
chatPanelMain.getUserChatPanel().useExtendedView(ChatPanelBasic.VIEW_MODE.NONE);
chatPanelMain.getUserChatPanel().setBorder(null);
chatPanelMain.getUserChatPanel().setChatType(ChatPanelBasic.ChatType.TABLES);
// 4. BUTTONS
filterButtons = new JToggleButton[]{btnStateWaiting, btnStateActive, btnStateFinished,
btnTypeMatch, btnTypeTourneyConstructed, btnTypeTourneyLimited,
btnFormatBlock, btnFormatStandard, btnFormatModern, btnFormatLegacy, btnFormatVintage, btnFormatCommander, btnFormatTinyLeader, btnFormatLimited, btnFormatOther,
@ -181,7 +271,7 @@ public class TablesPanel extends javax.swing.JPanel {
if (isTournament) {
LOGGER.info("Joining tournament " + tableId);
if (deckType.startsWith("Limited")) {
if (PASSWORDED.equals(pwdColumn)) {
if (TableTableModel.PASSWORD_VALUE_YES.equals(pwdColumn)) {
joinTableDialog.showDialog(roomId, tableId, true, deckType.startsWith("Limited"));
} else {
SessionHandler.joinTournamentTable(roomId, tableId, SessionHandler.getUserName(), PlayerType.HUMAN, 1, null, "");
@ -225,7 +315,7 @@ public class TablesPanel extends javax.swing.JPanel {
@Override
public void actionPerformed(ActionEvent e) {
int modelRow = Integer.valueOf(e.getActionCommand());
String action = (String) matchesModel.getValueAt(modelRow, MatchesTableModel.ACTION_COLUMN);
String action = (String) matchesModel.getValueAt(modelRow, MatchesTableModel.COLUMN_ACTION);
switch (action) {
case "Replay":
java.util.List<UUID> gameList = matchesModel.getListofGames(modelRow);
@ -250,7 +340,7 @@ public class TablesPanel extends javax.swing.JPanel {
// !!!! adds action buttons to the table panel (don't delete this)
actionButton1 = new ButtonColumn(tableTables, openTableAction, tableTables.convertColumnIndexToView(TableTableModel.ACTION_COLUMN));
actionButton2 = new ButtonColumn(tableCompleted, closedTableAction, tableCompleted.convertColumnIndexToView(MatchesTableModel.ACTION_COLUMN));
actionButton2 = new ButtonColumn(tableCompleted, closedTableAction, tableCompleted.convertColumnIndexToView(MatchesTableModel.COLUMN_ACTION));
// !!!!
}
@ -560,7 +650,7 @@ public class TablesPanel extends javax.swing.JPanel {
formatFilterList.add(RowFilter.regexFilter("^Constructed - Vintage", TableTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatCommander.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Commander|^Duel Commander|^Penny Dreadful Commander", TableTableModel.COLUMN_DECK_TYPE));
formatFilterList.add(RowFilter.regexFilter("^Commander|^Duel Commander|^Penny Dreadful Commander|^Freeform Commander", TableTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatTinyLeader.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Tiny", TableTableModel.COLUMN_DECK_TYPE));
@ -583,21 +673,27 @@ public class TablesPanel extends javax.swing.JPanel {
skillFilterList.add(RowFilter.regexFilter(SkillLevel.SERIOUS.toString(), TableTableModel.COLUMN_SKILL));
}
String ratedMark = TableTableModel.RATED_VALUE_YES;
java.util.List<RowFilter<Object, Object>> ratingFilterList = new ArrayList<>();
if (btnRated.isSelected()) {
ratingFilterList.add(RowFilter.regexFilter("^Rated", TableTableModel.COLUMN_RATING));
// yes word
ratingFilterList.add(RowFilter.regexFilter("^" + ratedMark, TableTableModel.COLUMN_RATING));
}
if (btnUnrated.isSelected()) {
ratingFilterList.add(RowFilter.regexFilter("^Unrated", TableTableModel.COLUMN_RATING));
// not yes word, see https://stackoverflow.com/a/406408/1276632
ratingFilterList.add(RowFilter.regexFilter("^((?!" + ratedMark + ").)*$", TableTableModel.COLUMN_RATING));
}
// Password
String passwordMark = TableTableModel.PASSWORD_VALUE_YES;
java.util.List<RowFilter<Object, Object>> passwordFilterList = new ArrayList<>();
if (btnOpen.isSelected()) {
passwordFilterList.add(RowFilter.regexFilter("^$", TableTableModel.COLUMN_PASSWORD));
}
if (btnPassword.isSelected()) {
passwordFilterList.add(RowFilter.regexFilter("^\\*\\*\\*$", TableTableModel.COLUMN_PASSWORD));
// yes
passwordFilterList.add(RowFilter.regexFilter("^" + passwordMark, TableTableModel.COLUMN_PASSWORD));
}
if (btnOpen.isSelected()) {
// no
passwordFilterList.add(RowFilter.regexFilter("^((?!" + passwordMark + ").)*$", TableTableModel.COLUMN_PASSWORD));
}
// Hide games of ignored players
@ -1281,16 +1377,24 @@ class TableTableModel extends AbstractTableModel {
public static final int COLUMN_QUIT_RATIO = 10;
public static final int ACTION_COLUMN = 11; // column the action is located (starting with 0)
public static final String RATED_VALUE_YES = "YES";
public static final String RATED_VALUE_NO = "";
public static final String PASSWORD_VALUE_YES = "YES";
private final String[] columnNames = new String[]{"M/T", "Deck Type", "Owner / Players", "Game Type", "Info", "Status", "Password", "Created / Started", "Skill Level", "Rating", "Quit %", "Action"};
private TableView[] tables = new TableView[0];
private static final DateFormat timeFormatter = new SimpleDateFormat("HH:mm:ss");
TableTableModel() {
}
public void loadData(Collection<TableView> tables) throws MageRemoteException {
this.tables = tables.toArray(new TableView[0]);
this.fireTableDataChanged();
}
@Override
public int getRowCount() {
return tables.length;
@ -1317,13 +1421,13 @@ class TableTableModel extends AbstractTableModel {
case 5:
return tables[arg0].getTableStateText();
case 6:
return tables[arg0].isPassworded() ? PASSWORDED : "";
return tables[arg0].isPassworded() ? PASSWORD_VALUE_YES : "";
case 7:
return timeFormatter.format(tables[arg0].getCreateTime());
return tables[arg0].getCreateTime(); // use cell render, not format here
case 8:
return tables[arg0].getSkillLevel();
case 9:
return tables[arg0].isRated() ? "Rated" : "Unrated";
return tables[arg0].isRated() ? RATED_VALUE_YES : RATED_VALUE_NO;
case 10:
return tables[arg0].getQuitRatio();
case 11:
@ -1384,6 +1488,8 @@ class TableTableModel extends AbstractTableModel {
return Icon.class;
case COLUMN_SKILL:
return SkillLevel.class;
case COLUMN_CREATED:
return Date.class;
default:
return String.class;
}
@ -1486,17 +1592,22 @@ class UpdatePlayersTask extends SwingWorker<Void, Collection<RoomUsersView>> {
class MatchesTableModel extends AbstractTableModel {
public static final int ACTION_COLUMN = 7; // column the action is located (starting with 0)
public static final int GAMES_LIST_COLUMN = 8;
private final String[] columnNames = new String[]{"Deck Type", "Players", "Game Type", "Rating", "Result", "Start Time", "End Time", "Action"};
private final String[] columnNames = new String[]{"Deck Type", "Players", "Game Type", "Rating", "Result", "Duration", "Start Time", "End Time", "Action"};
public static final int COLUMN_DURATION = 5;
public static final int COLUMN_START = 6;
public static final int COLUMN_END = 7;
public static final int COLUMN_ACTION = 8; // column the action is located (starting with 0)
private MatchView[] matches = new MatchView[0];
private static final DateFormat timeFormatter = SimpleDateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
public void loadData(Collection<MatchView> matches) throws MageRemoteException {
this.matches = matches.toArray(new MatchView[0]);
this.fireTableDataChanged();
}
MatchesTableModel(){
}
@Override
public int getRowCount() {
return matches.length;
@ -1517,22 +1628,20 @@ class MatchesTableModel extends AbstractTableModel {
case 2:
return matches[arg0].getGameType();
case 3:
return matches[arg0].isRated() ? "Rated" : "Unrated";
return matches[arg0].isRated() ? TableTableModel.RATED_VALUE_YES : TableTableModel.RATED_VALUE_NO;
case 4:
return matches[arg0].getResult();
case 5:
if (matches[arg0].getStartTime() != null) {
return timeFormatter.format(matches[arg0].getStartTime());
if (matches[arg0].getEndTime() != null) {
return matches[arg0].getEndTime().getTime() - matches[arg0].getStartTime().getTime() + new Date().getTime();
} else {
return "";
return 0L;
}
case 6:
if (matches[arg0].getEndTime() != null) {
return timeFormatter.format(matches[arg0].getEndTime());
} else {
return "";
}
return matches[arg0].getStartTime();
case 7:
return matches[arg0].getEndTime();
case 8:
if (matches[arg0].isTournament()) {
return "Show";
} else if (matches[arg0].isReplayAvailable()) {
@ -1540,7 +1649,7 @@ class MatchesTableModel extends AbstractTableModel {
} else {
return "None";
}
case 8:
case 9:
return matches[arg0].getGames();
}
return "";
@ -1575,12 +1684,21 @@ class MatchesTableModel extends AbstractTableModel {
@Override
public Class getColumnClass(int columnIndex) {
return String.class;
switch (columnIndex) {
case COLUMN_DURATION:
return Long.class;
case COLUMN_START:
return Date.class;
case COLUMN_END:
return Date.class;
default:
return String.class;
}
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex == ACTION_COLUMN;
return columnIndex == COLUMN_ACTION;
}
}

View file

@ -0,0 +1,64 @@
package mage.client.util.gui;
import mage.choices.ChoiceImpl;
import mage.client.dialog.PickChoiceDialog;
import javax.swing.*;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author JayDi85
*/
public class FastSearchUtil {
public static String DEFAULT_EXPANSION_SEARCH_MESSAGE = "Select set or expansion";
public static String DEFAULT_EXPANSION_TOOLTIP_MESSAGE = "Fast search set or expansion";
/**
* Show fast choice modal dialog with incremental searching for any string combobox components
* @param combo combobox control with default data model
* @param chooseMessage caption message for dialog
*/
public static void showFastSearchForStringComboBox(JComboBox combo, String chooseMessage){
// fast search/choice dialog for string combobox
mage.choices.Choice choice = new ChoiceImpl(false);
// collect data from expansion combobox (String)
DefaultComboBoxModel comboModel = (DefaultComboBoxModel)combo.getModel();
Map<String, String> choiceItems = new HashMap<>(comboModel.getSize());
Map<String, Integer> choiceSorting = new HashMap<>(comboModel.getSize());
String item;
for(int i = 0; i < comboModel.getSize(); i++){
item = comboModel.getElementAt(i).toString();
choiceItems.put(item, item);
choiceSorting.put(item, i); // need so sorting
}
choice.setKeyChoices(choiceItems);
choice.setSortData(choiceSorting);
choice.setMessage(chooseMessage);
// current selection value restore
String needSelectValue;
needSelectValue = comboModel.getSelectedItem().toString();
// ask for new value
PickChoiceDialog dlg = new PickChoiceDialog();
dlg.setWindowSize(300, 500);
dlg.showDialog(choice, needSelectValue);
if(choice.isChosen()){
item = choice.getChoiceKey();
// compatible select for object's models (use setSelectedIndex instead setSelectedObject)
for(int i = 0; i < comboModel.getSize(); i++){
if(comboModel.getElementAt(i).toString().equals(item)){
combo.setSelectedIndex(i);
}
}
}
}
}

View file

@ -27,44 +27,34 @@
*/
package mage.client.util.gui.countryBox;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.basic.BasicComboBoxEditor;
/**
* Editor for JComboBox
* @author wwww.codejava.net
* @author wwww.codejava.net, JayDi85
*
*/
public class CountryItemEditor extends BasicComboBoxEditor {
private final JPanel panel = new JPanel();
private final JLabel labelItem = new JLabel();
private String selectedValue;
private String selectedImage;
private String[] editValue = new String[2];
public CountryItemEditor() {
panel.setLayout(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.weightx = 1.0;
// constraints.insets = new Insets(2, 5, 2, 2);
constraints.insets = new Insets(0, 5, 0, 0);
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
panel.setBackground(new Color(0, 100,190, 255));
panel.add(labelItem);
labelItem.setAlignmentX(Component.LEFT_ALIGNMENT);
labelItem.setMaximumSize(new Dimension(Short.MAX_VALUE, Short.MAX_VALUE));
labelItem.setBorder(new EmptyBorder(0, 5, 0, 0));
labelItem.setOpaque(false);
labelItem.setHorizontalAlignment(JLabel.LEFT);
labelItem.setForeground(Color.WHITE);
panel.add(labelItem, constraints);
// panel.setBackground(Color.WHITE);
panel.setBackground(new Color(0, 100,190, 255));
selectedValue = null;
editValue = null;
}
@Override
@ -74,21 +64,26 @@ public class CountryItemEditor extends BasicComboBoxEditor {
@Override
public Object getItem() {
return this.selectedValue;
return this.editValue;
}
public String getImageItem() {
return this.selectedImage;
}
return this.editValue[1];
}
@Override
public void setItem(Object item) {
if (item == null || !(item instanceof String[])) {
return;
}
String[] countryItem = (String[]) item;
selectedValue = countryItem[0];
selectedImage = countryItem[1];
labelItem.setText(selectedValue);
labelItem.setIcon(new ImageIcon(getClass().getResource("/flags/"+ countryItem[1] + ".png")));
String[] newItem = (String[])item;
editValue = new String[2];
editValue[0] = newItem[0];
editValue[1] = newItem[1];
labelItem.setText(editValue[0]);
labelItem.setIcon(new ImageIcon(getClass().getResource("/flags/"+ editValue[1] + ".png")));
}
}

View file

@ -50,8 +50,10 @@ public class MyComboBoxRenderer extends JLabel implements ListCellRenderer {
@Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
setText(value.toString());
String[] val = (String[]) value;
setText(val[0]);
return this;
}
}

View file

@ -0,0 +1,52 @@
package mage.client.util.stats;
/**
*
* @author JayDi85
*/
public class MemoryStats {
private float Available = 0;
private float MaxAvailable = 0;
private float Used = 0;
private float Free = 0;
public MemoryStats(float MaxAvailable, float Available, float Used, float Free){
this.setMaxAvailable(MaxAvailable);
this.setAvailable(Available);
this.setUsed(Used);
this.setFree(Free);
}
public float getAvailable() {
return Available;
}
public void setAvailable(float available) {
Available = available;
}
public float getUsed() {
return Used;
}
public void setUsed(float used) {
Used = used;
}
public float getFree() {
return Free;
}
public void setFree(float free) {
Free = free;
}
public float getMaxAvailable() {
return MaxAvailable;
}
public void setMaxAvailable(float maxAvailable) {
MaxAvailable = maxAvailable;
}
}

View file

@ -1,25 +0,0 @@
package mage.client.util.stats;
/**
* @author noxx
*/
public final class MemoryUsageStatUtil {
private MemoryUsageStatUtil() {}
/**
* Returns percentage of available memory used at runtime.
* If not possible to determine, returns -1.
*
* @return
*/
public static float getMemoryFreeStatPercentage() {
Runtime runtime = Runtime.getRuntime();
if (runtime.maxMemory() != 0) {
long usedMem = runtime.totalMemory() - runtime.freeMemory();
return (1 - (1.0f*usedMem)/runtime.maxMemory())*100;
} else {
return -1;
}
}
}

View file

@ -1,5 +1,6 @@
package mage.client.util.stats;
import java.awt.*;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
@ -11,11 +12,13 @@ import org.apache.log4j.Logger;
* This updates the mem usage info in the Mage client every
* MEM_USAGE_UPDATE_TIME ms.
*
* @author noxx
* @author noxx, JayDi85
*/
public class UpdateMemUsageTask extends SwingWorker<Void, Float> {
public class UpdateMemUsageTask extends SwingWorker<Void, MemoryStats> {
private static final int MEM_USAGE_UPDATE_TIME = 2000;
private static final int MEM_USAGE_WARNING_PERCENT = 80; // red color for mem used more than xx%
private final JLabel jLabelToDisplayInfo;
@ -23,24 +26,60 @@ public class UpdateMemUsageTask extends SwingWorker<Void, Float> {
public UpdateMemUsageTask(JLabel jLabelToDisplayInfo) {
this.jLabelToDisplayInfo = jLabelToDisplayInfo;
this.jLabelToDisplayInfo.setToolTipText("<html>Memory usage statistics");
}
@Override
protected Void doInBackground() throws Exception {
while (!isCancelled()) {
float memUsage = MemoryUsageStatUtil.getMemoryFreeStatPercentage();
this.publish(memUsage >= 0 ? memUsage : null);
MemoryStats memoryStats = new MemoryStats(0, 0, 0, 0);
Runtime runtime = Runtime.getRuntime();
if (runtime.maxMemory() != 0) {
memoryStats.setMaxAvailable(runtime.maxMemory());
memoryStats.setAvailable(runtime.totalMemory());
memoryStats.setFree(runtime.freeMemory());
memoryStats.setUsed(runtime.totalMemory() - runtime.freeMemory());
}
this.publish(memoryStats);
TimeUnit.MILLISECONDS.sleep(MEM_USAGE_UPDATE_TIME);
}
return null;
}
@Override
protected void process(List<Float> chunks) {
protected void process(List<MemoryStats> chunks) {
if (chunks != null && !chunks.isEmpty()) {
Float memUsage = chunks.get(chunks.size() - 1);
if (memUsage != null) {
jLabelToDisplayInfo.setText(Math.round(memUsage) + "% Mem free");
MemoryStats memoryStats = chunks.get(chunks.size() - 1);
if (memoryStats != null) {
int max = Math.round(memoryStats.getMaxAvailable() / (1000 * 1000));
int used = Math.round(memoryStats.getUsed() / (1000 * 1000));
int total = Math.round(memoryStats.getAvailable() / (1000 * 1000));
int percent = 0;
if(max != 0){
percent = Math.round((used * 100) / max);
}
jLabelToDisplayInfo.setText("Memory used: " + percent + "% (" + used + " of " + max + " MB)");
String warning = "";
String optimizeHint = "<br><br>If you see low memory warning and have free system memory then try to increase max limit in launcher settings:<br>"
+ " - Go to <i>launcher -> settings -> java tab</i>;<br>"
+ " - Find <i>client java options</i> (it's may contain many commands);<br>"
+ " - Find max available memory setting: <i>-Xmx256m</i> (it's must start with <b>-Xmx</b>);<br>"
+ " - Increase number in that value from 256 to 512, or 512 to 1024;<br>"
+ " - Save new settings and restart application.";
if(percent >= MEM_USAGE_WARNING_PERCENT){
jLabelToDisplayInfo.setForeground(Color.red);
warning = "<br><br><b>WARNING</b><br>"
+ "Application memory limit almost reached. Errors and freezes are very possible.";
}else{
jLabelToDisplayInfo.setForeground(Color.black);
}
this.jLabelToDisplayInfo.setToolTipText("<html>Memory usage statistics" + warning + optimizeHint);
return;
}
}

View file

@ -91,7 +91,8 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
private JPanel cardArea;
private int yTextOffset = 10;
// default offset, e.g. for battlefield
private int yCardCaptionOffsetPercent = 8; // card caption offset (use for moving card caption view center, below mana icons -- for more good UI)
// if this is set, it's opened if the user right clicks on the card panel
private JPopupMenu popupMenu;
@ -819,12 +820,12 @@ public abstract class CardPanel extends MagePermanent implements MouseListener,
}
@Override
public void setTextOffset(int yOffset) {
yTextOffset = yOffset;
public void setCardCaptionTopOffset(int yOffsetPercent) {
yCardCaptionOffsetPercent = yOffsetPercent;
}
public int getTextOffset() {
return yTextOffset;
public int getCardCaptionTopOffset() {
return yCardCaptionOffsetPercent;
}
@Override

View file

@ -13,28 +13,26 @@ import mage.view.CardView;
import mage.view.CounterView;
import mage.view.PermanentView;
import mage.view.StackAbilityView;
import net.java.truevfs.access.TFile;
import org.apache.log4j.Logger;
import org.jdesktop.swingx.graphics.GraphicsUtilities;
import org.mage.plugins.card.dl.sources.DirectLinksForDownload;
import org.mage.plugins.card.images.ImageCache;
import org.mage.plugins.card.utils.impl.ImageManagerImpl;
import mage.client.constants.Constants;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.UUID;
import static org.mage.plugins.card.constants.Constants.THUMBNAIL_SIZE_FULL;
/**
* Class for drawing the mage card object by using a form based JComponent
* approach
*
* @author arcane, nantuko, noxx, stravant
* @author arcane, nantuko, noxx, stravant, JayDi85
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public class CardPanelComponentImpl extends CardPanel {
@ -47,9 +45,14 @@ public class CardPanelComponentImpl extends CardPanel {
private static final float ROUNDED_CORNER_SIZE = 0.1f;
private static final float BLACK_BORDER_SIZE = 0.03f;
private static final float SELECTION_BORDER_SIZE = 0.03f;
private static final int TEXT_GLOW_SIZE = 6;
private static final float TEXT_GLOW_INTENSITY = 3f;
// size to show icons and text (help to see full size card without text)
private static final int CARD_MIN_SIZE_FOR_ICONS = 60;
private static final int CARD_MAX_SIZE_FOR_ICONS = 200;
public final ScaledImagePanel imagePanel;
public ImagePanel overlayPanel;
@ -177,6 +180,34 @@ public class CardPanelComponentImpl extends CardPanel {
IMAGE_CACHE = ImageCaches.register(new MapMaker().softValues().makeComputingMap((Function<Key, BufferedImage>) key -> createImage(key)));
}
static private boolean canShowCardIcons(int cardFullWidth, boolean cardHasImage){
// cards without images show icons and text always
// TODO: apply "card names on card" setting to icon too?
// TODO: fix card min-max size to hide (compare to settings size, not direct 60 and 200)
return ((cardFullWidth > 60) && (cardFullWidth < 200)) || (!cardHasImage);
}
private static class CardSizes{
Rectangle rectFull;
Rectangle rectSelection;
Rectangle rectBorder;
Rectangle rectCard;
CardSizes(int offsetX, int offsetY, int fullWidth, int fullHeight){
int realBorderSizeX = Math.round(fullWidth * BLACK_BORDER_SIZE);
int realBorderSizeY = Math.round(fullWidth * BLACK_BORDER_SIZE);
int realSelectionSizeX = Math.round(fullWidth * SELECTION_BORDER_SIZE);
int realSelectionSizeY = Math.round(fullWidth * SELECTION_BORDER_SIZE);
// card full size = select border + black border + real card
rectFull = new Rectangle(offsetX, offsetY, fullWidth, fullHeight);
rectSelection = new Rectangle(rectFull.x, rectFull.y, rectFull.width, rectFull.height);
rectBorder = new Rectangle(rectSelection.x + realSelectionSizeX, rectSelection.y + realSelectionSizeY, rectSelection.width - 2 * realSelectionSizeX, rectSelection.height - 2 * realSelectionSizeY);
rectCard = new Rectangle(rectBorder.x + realBorderSizeX, rectBorder.y + realBorderSizeY, rectBorder.width - 2 * realBorderSizeX, rectBorder.height - 2 * realBorderSizeY);
}
}
public CardPanelComponentImpl(CardView newGameCard, UUID gameId, final boolean loadImage, ActionCallback callback, final boolean foil, Dimension dimension) {
// Call to super
super(newGameCard, gameId, loadImage, callback, foil, dimension);
@ -368,32 +399,45 @@ public class CardPanelComponentImpl extends CardPanel {
Graphics2D g2d = image.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (!key.hasImage) {
g2d.setColor(new Color(30, 200, 200, 120));
} else {
g2d.setColor(new Color(0, 0, 0, 0));
}
// card full size = select border + black border + real card
CardSizes sizes = new CardSizes(cardXOffset, cardYOffset, cardWidth, cardHeight);
int cornerSize = Math.max(4, Math.round(cardWidth * ROUNDED_CORNER_SIZE));
g2d.fillRoundRect(cardXOffset, cardYOffset, cardWidth, cardHeight, cornerSize, cornerSize);
// corners for selection and for border
int cornerSizeSelection = Math.max(4, Math.round(sizes.rectSelection.width * ROUNDED_CORNER_SIZE));
int cornerSizeBorder = Math.max(4, Math.round(sizes.rectBorder.width * ROUNDED_CORNER_SIZE));
// DRAW ORDER from big to small: select -> select info -> border -> card
// draw selection
if (key.isSelected) {
g2d.setColor(Color.green);
g2d.fillRoundRect(cardXOffset + 1, cardYOffset + 1, cardWidth - 2, cardHeight - 2, cornerSize, cornerSize);
g2d.fillRoundRect(sizes.rectSelection.x + 1, sizes.rectSelection.y + 1, sizes.rectSelection.width - 2, sizes.rectSelection.height - 2, cornerSizeSelection, cornerSizeSelection);
} else if (key.isChoosable) {
g2d.setColor(new Color(250, 250, 0, 230));
g2d.fillRoundRect(cardXOffset + 1, cardYOffset + 1, cardWidth - 2, cardHeight - 2, cornerSize, cornerSize);
g2d.fillRoundRect(sizes.rectSelection.x + 1, sizes.rectSelection.y + 1, sizes.rectSelection.width - 2, sizes.rectSelection.height - 2, cornerSizeSelection, cornerSizeSelection);
} else if (key.isPlayable) {
g2d.setColor(new Color(153, 102, 204, 200));
//g2d.fillRoundRect(cardXOffset + 1, cardYOffset + 1, cardWidth - 2, cardHeight - 2, cornerSize, cornerSize);
g2d.fillRoundRect(cardXOffset, cardYOffset, cardWidth, cardHeight, cornerSize, cornerSize);
g2d.fillRoundRect(sizes.rectSelection.x, sizes.rectSelection.y, sizes.rectSelection.width, sizes.rectSelection.height, cornerSizeSelection, cornerSizeSelection);
}
// draw empty card with border
if (!key.hasImage) {
// gray 1 px border
g2d.setColor(new Color(125, 125, 125, 255));
g2d.fillRoundRect(sizes.rectBorder.x, sizes.rectBorder.y, sizes.rectBorder.width, sizes.rectBorder.height, cornerSizeBorder, cornerSizeBorder);
// color plate
g2d.setColor(new Color(30, 200, 200, 200));
g2d.fillRoundRect(sizes.rectBorder.x + 1, sizes.rectBorder.y + 1, sizes.rectBorder.width - 2, sizes.rectBorder.height - 2, cornerSizeBorder, cornerSizeBorder);
}
// draw attack border (inner part of selection)
if (key.canAttack) {
g2d.setColor(new Color(0, 0, 255, 230));
g2d.fillRoundRect(cardXOffset + 1, cardYOffset + 1, cardWidth - 2, cardHeight - 2, cornerSize, cornerSize);
g2d.fillRoundRect(sizes.rectBorder.x + 1, sizes.rectBorder.y + 1, sizes.rectBorder.width - 2, sizes.rectBorder.height - 2, cornerSizeBorder, cornerSizeBorder);
}
// draw real card by component (see imagePanel and other layout's items)
//TODO:uncomment
/*
if (gameCard.isAttacking()) {
@ -409,23 +453,55 @@ public class CardPanelComponentImpl extends CardPanel {
protected void paintChildren(Graphics g) {
super.paintChildren(g);
if (getShowCastingCost() && !isAnimationPanel() && getCardWidth() < 200 && getCardWidth() > 60) {
CardSizes realCard = new CardSizes(getCardXOffset(), getCardYOffset(), getCardWidth(), getCardHeight());
/*
// draw recs for debug
// full card
g.setColor(new Color(255, 0, 0));
g.drawRect(realCard.rectFull.x, realCard.rectFull.y, realCard.rectFull.width, realCard.rectFull.height);
// real card - image
g.setColor(new Color(0, 0, 255));
g.drawRect(imagePanel.getX(), imagePanel.getY(), imagePanel.getBounds().width, imagePanel.getBounds().height);
// caption
g.setColor(new Color(0, 255, 255));
g.drawRect(titleText.getX(), titleText.getY(), titleText.getBounds().width, titleText.getBounds().height);
// life points
g.setColor(new Color(120, 0, 120));
g.drawRect(ptText.getX(), ptText.getY(), ptText.getBounds().width, ptText.getBounds().height);
//*/
if (getShowCastingCost() && !isAnimationPanel() && canShowCardIcons(getCardWidth(), hasImage)) {
int symbolMarginX = 2; // 2 px between icons
String manaCost = ManaSymbols.getStringManaCost(gameCard.getManaCost());
int width = getWidth(manaCost);
if (hasImage) {
ManaSymbols.draw(g, manaCost, getCardXOffset() + getCardWidth() - width - 5, getCardYOffset() + 5, getSymbolWidth());
} else {
ManaSymbols.draw(g, manaCost, getCardXOffset() + 8, getCardHeight() - 9, getSymbolWidth());
}
int manaWidth = getManaWidth(manaCost, symbolMarginX);
// right top corner with margin (sizes from any sample card, length from black border to mana icon)
int manaMarginRight = Math.round(22f / 672f * getCardWidth());
int manaMarginTop = Math.round(24f / 936f * getCardHeight());
int manaX = getCardXOffset() + getCardWidth() - manaMarginRight - manaWidth;
int manaY = getCardYOffset() + manaMarginTop;
ManaSymbols.draw(g, manaCost, manaX, manaY, getSymbolWidth(), Color.black, symbolMarginX);
}
}
private int getWidth(String manaCost) {
private int getManaWidth(String manaCost, int symbolMarginX) {
int width = 0;
manaCost = manaCost.replace("\\", "");
StringTokenizer tok = new StringTokenizer(manaCost, " ");
while (tok.hasMoreTokens()) {
tok.nextToken();
if(width != 0) {
width += symbolMarginX;
}
width += getSymbolWidth();
}
return width;
@ -439,24 +515,28 @@ public class CardPanelComponentImpl extends CardPanel {
int cardHeight = getCardHeight();
int cardXOffset = getCardXOffset();
int cardYOffset = getCardYOffset();
int borderSize = Math.round(cardWidth * BLACK_BORDER_SIZE);
imagePanel.setLocation(cardXOffset + borderSize, cardYOffset + borderSize);
imagePanel.setSize(cardWidth - borderSize * 2, cardHeight - borderSize * 2);
CardSizes sizes = new CardSizes(cardXOffset, cardYOffset, cardWidth, cardHeight);
// origin card without selection
Rectangle realCardSize = sizes.rectBorder;
imagePanel.setLocation(realCardSize.x, realCardSize.y);
imagePanel.setSize(realCardSize.width, realCardSize.height);
if (hasSickness() && gameCard.isCreature() && isPermanent()) {
overlayPanel.setLocation(cardXOffset + borderSize, cardYOffset + borderSize);
overlayPanel.setSize(cardWidth - borderSize * 2, cardHeight - borderSize * 2);
overlayPanel.setLocation(realCardSize.x, realCardSize.y);
overlayPanel.setSize(realCardSize.width, realCardSize.height);
} else {
overlayPanel.setVisible(false);
}
if (iconPanel != null) {
iconPanel.setLocation(cardXOffset + borderSize, cardYOffset + borderSize);
iconPanel.setSize(cardWidth - borderSize * 2, cardHeight - borderSize * 2);
iconPanel.setLocation(realCardSize.x, realCardSize.y);
iconPanel.setSize(realCardSize.width, realCardSize.height);
}
if (counterPanel != null) {
counterPanel.setLocation(cardXOffset + borderSize, cardYOffset + borderSize);
counterPanel.setSize(cardWidth - borderSize * 2, cardHeight - borderSize * 2);
counterPanel.setLocation(realCardSize.x, realCardSize.y);
counterPanel.setSize(realCardSize.width, realCardSize.height);
int size = cardWidth > WIDTH_LIMIT ? 40 : 20;
minusCounterLabel.setLocation(counterPanel.getWidth() - size, counterPanel.getHeight() - size * 2);
@ -472,32 +552,52 @@ public class CardPanelComponentImpl extends CardPanel {
otherCounterLabel.setSize(size, size);
}
int fontHeight = Math.round(cardHeight * (27f / 680));
boolean showText = (!isAnimationPanel() && fontHeight < 12);
// TITLE
//old version - text hide on small fonts, why?
//int fontHeight = Math.round(cardHeight * (26f / 672));
//boolean showText = (!isAnimationPanel() && fontHeight < 12);
boolean showText = !isAnimationPanel() && canShowCardIcons(cardWidth, hasImage);
titleText.setVisible(showText);
ptText.setVisible(showText);
fullImageText.setVisible(fullImagePath != null);
if (showText) {
int fontSize = cardHeight / 11;
int fontSize = cardHeight / 13; // startup font size (it same size on all zoom levels)
titleText.setFont(getFont().deriveFont(Font.BOLD, fontSize));
int titleX = Math.round(cardWidth * (20f / 480));
int titleY = Math.round(cardHeight * (9f / 680)) + getTextOffset();
titleText.setBounds(cardXOffset + titleX, cardYOffset + titleY, cardWidth - titleX, cardHeight - titleY);
// margins from card black border to text, not need? text show up good without margins
int titleMarginLeft = 0; //Math.round(28f / 672f * cardWidth);
int titleMarginRight = 0;
int titleMarginTop = 0 + Math.round(getCardCaptionTopOffset() / 100f * cardHeight);//Math.round(28f / 936f * cardHeight);
int titleMarginBottom = 0;
titleText.setBounds(
imagePanel.getX() + titleMarginLeft,
imagePanel.getY() + titleMarginTop,
imagePanel.getBounds().width - titleMarginLeft - titleMarginRight,
imagePanel.getBounds().height - titleMarginTop - titleMarginBottom
);
fullImageText.setFont(getFont().deriveFont(Font.PLAIN, 10));
fullImageText.setBounds(cardXOffset, cardYOffset + titleY, cardWidth, cardHeight - titleY);
fullImageText.setBounds(titleText.getX(), titleText.getY(), titleText.getBounds().width, titleText.getBounds().height);
// life points location (font as title)
ptText.setFont(getFont().deriveFont(Font.BOLD, fontSize));
Dimension ptSize = ptText.getPreferredSize();
ptText.setSize(ptSize.width, ptSize.height);
int ptX = Math.round(cardWidth * (420f / 480)) - ptSize.width / 2;
int ptY = Math.round(cardHeight * (675f / 680)) - ptSize.height;
int offsetX = Math.round((CARD_SIZE_FULL.width - cardWidth) / 10.0f);
// right bottom corner with margin (sizes from any sample card)
int ptMarginRight = Math.round(64f / 672f * cardWidth);
int ptMarginBottom = Math.round(62f / 936f * cardHeight);
ptText.setLocation(cardXOffset + ptX - TEXT_GLOW_SIZE / 2 - offsetX, cardYOffset + ptY - TEXT_GLOW_SIZE / 2);
int ptX = cardXOffset + cardWidth - ptMarginRight - ptSize.width;
int ptY = cardYOffset + cardHeight - ptMarginBottom - ptSize.height;
ptText.setLocation(ptX, ptY);
// old version was with TEXT_GLOW_SIZE
//ptText.setLocation(cardXOffset + ptX - TEXT_GLOW_SIZE / 2 - offsetX, cardYOffset + ptY - TEXT_GLOW_SIZE / 2);
}
}
@ -548,7 +648,7 @@ public class CardPanelComponentImpl extends CardPanel {
final BufferedImage srcImage;
if (gameCard.isFaceDown()) {
srcImage = getFaceDownImage();
} else if (getCardWidth() > THUMBNAIL_SIZE_FULL.width) {
} else if (getCardWidth() > Constants.THUMBNAIL_SIZE_FULL.width) {
srcImage = ImageCache.getImage(gameCard, getCardWidth(), getCardHeight());
} else {
srcImage = ImageCache.getThumbnail(gameCard);
@ -581,7 +681,7 @@ public class CardPanelComponentImpl extends CardPanel {
} else if (this.gameCard instanceof StackAbilityView) {
return ImageCache.getMorphImage();
} else {
return ImageCache.loadImage(new TFile(DirectLinksForDownload.outDir + File.separator + DirectLinksForDownload.cardbackFilename));
return ImageCache.getCardbackImage();
}
}

View file

@ -14,6 +14,7 @@ import org.apache.log4j.Logger;
import org.jdesktop.swingx.graphics.GraphicsUtilities;
import org.mage.plugins.card.dl.sources.DirectLinksForDownload;
import org.mage.plugins.card.images.ImageCache;
import mage.client.constants.Constants;
import java.awt.*;
import java.awt.image.BufferedImage;
@ -21,8 +22,6 @@ import java.io.File;
import java.util.Map;
import java.util.UUID;
import static org.mage.plugins.card.constants.Constants.THUMBNAIL_SIZE_FULL;
public class CardPanelRenderImpl extends CardPanel {
private static final Logger LOGGER = Logger.getLogger(CardPanelRenderImpl.class);
@ -218,13 +217,15 @@ public class CardPanelRenderImpl extends CardPanel {
}
}
// Map of generated images
private final static Map<ImageKey, BufferedImage> IMAGE_CACHE = new MapMaker().softValues().makeMap();
// The art image for the card, loaded in from the disk
private BufferedImage artImage;
// The faceart image for the card, loaded in from the disk (based on artid from mtgo)
private BufferedImage faceArtImage;
// Factory to generate card appropriate views
private CardRendererFactory cardRendererFactory = new CardRendererFactory();
@ -252,6 +253,8 @@ public class CardPanelRenderImpl extends CardPanel {
// Use the art image and current rendered image from the card
artImage = impl.artImage;
cardRenderer.setArtImage(artImage);
faceArtImage = impl.faceArtImage;
cardRenderer.setFaceArtImage(faceArtImage);
cardImage = impl.cardImage;
}
}
@ -263,8 +266,8 @@ public class CardPanelRenderImpl extends CardPanel {
// Try to get card image from cache based on our card characteristics
ImageKey key
= new ImageKey(gameCard, artImage,
getCardWidth(), getCardHeight(),
isChoosable(), isSelected());
getCardWidth(), getCardHeight(),
isChoosable(), isSelected());
cardImage = IMAGE_CACHE.computeIfAbsent(key, k -> renderCard());
// No cached copy exists? Render one and cache it
@ -277,7 +280,6 @@ public class CardPanelRenderImpl extends CardPanel {
/**
* Create an appropriate card renderer for the
*/
/**
* Render the card to a new BufferedImage at it's current dimensions
*
@ -315,6 +317,7 @@ public class CardPanelRenderImpl extends CardPanel {
artImage = null;
cardImage = null;
cardRenderer.setArtImage(null);
cardRenderer.setFaceArtImage(null);
// Stop animation
tappedAngle = isTapped() ? CardPanel.TAPPED_ANGLE : 0;
@ -332,19 +335,26 @@ public class CardPanelRenderImpl extends CardPanel {
Util.threadPool.submit(() -> {
try {
final BufferedImage srcImage;
final BufferedImage faceArtSrcImage;
if (gameCard.isFaceDown()) {
// Nothing to do
srcImage = null;
} else if (getCardWidth() > THUMBNAIL_SIZE_FULL.width) {
faceArtSrcImage = null;
} else if (getCardWidth() > Constants.THUMBNAIL_SIZE_FULL.width) {
srcImage = ImageCache.getImage(gameCard, getCardWidth(), getCardHeight());
faceArtSrcImage = ImageCache.getFaceImage(gameCard, getCardWidth(), getCardHeight());
} else {
srcImage = ImageCache.getThumbnail(gameCard);
faceArtSrcImage = ImageCache.getFaceImage(gameCard, getCardWidth(), getCardHeight());
}
UI.invokeLater(() -> {
if (stamp == updateArtImageStamp) {
artImage = srcImage;
cardRenderer.setArtImage(srcImage);
faceArtImage = faceArtSrcImage;
cardRenderer.setFaceArtImage(faceArtSrcImage);
if (srcImage != null) {
// Invalidate and repaint
cardImage = null;
@ -370,6 +380,7 @@ public class CardPanelRenderImpl extends CardPanel {
cardImage = null;
cardRenderer = cardRendererFactory.create(gameCard, isTransformed());
cardRenderer.setArtImage(artImage);
cardRenderer.setFaceArtImage(faceArtImage);
// Repaint
repaint();
@ -398,7 +409,7 @@ public class CardPanelRenderImpl extends CardPanel {
} else if (this.gameCard instanceof StackAbilityView) {
return ImageCache.getMorphImage();
} else {
return ImageCache.loadImage(new TFile(DirectLinksForDownload.outDir + File.separator + DirectLinksForDownload.cardbackFilename));
return ImageCache.getCardbackImage();
}
}

View file

@ -66,6 +66,9 @@ public abstract class CardRenderer {
// The card image
protected BufferedImage artImage;
// The face card image
protected BufferedImage faceArtImage;
///////////////////////////////////////////////////////////////////////////
// Common layout metrics between all cards
// Polygons for counters
@ -289,8 +292,8 @@ public abstract class CardRenderer {
try {
BufferedImage subImg
= artImage.getSubimage(
(int) (artRect.getX() * fullCardImgWidth), (int) (artRect.getY() * fullCardImgHeight),
(int) artWidth, (int) artHeight);
(int) (artRect.getX() * fullCardImgWidth), (int) (artRect.getY() * fullCardImgHeight),
(int) artWidth, (int) artHeight);
g.drawImage(subImg,
x, y,
(int) targetWidth, (int) targetHeight,
@ -300,6 +303,44 @@ public abstract class CardRenderer {
}
}
protected void drawFaceArtIntoRect(Graphics2D g, int x, int y, int w, int h, Rectangle2D artRect, boolean shouldPreserveAspect) {
// Perform a process to make sure that the art is scaled uniformly to fill the frame, cutting
// off the minimum amount necessary to make it completely fill the frame without "squashing" it.
double fullCardImgWidth = faceArtImage.getWidth();
double fullCardImgHeight = faceArtImage.getHeight();
double artWidth = fullCardImgWidth;
double artHeight = fullCardImgHeight;
double targetWidth = w;
double targetHeight = h;
double targetAspect = targetWidth / targetHeight;
if (!shouldPreserveAspect) {
// No adjustment to art
} else if (targetAspect * artHeight < artWidth) {
// Trim off some width
artWidth = targetAspect * artHeight;
} else {
// Trim off some height
artHeight = artWidth / targetAspect;
}
try {
/*BufferedImage subImg
= faceArtImage.getSubimage(
(int) (artRect.getX() * fullCardImgWidth), (int) (artRect.getY() * fullCardImgHeight),
(int) artWidth, (int) artHeight);*/
RenderingHints rh = new RenderingHints(
RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g.setRenderingHints(rh);
g.drawImage(faceArtImage,
x, y,
(int) targetWidth, (int) targetHeight,
null);
} catch (RasterFormatException e) {
// At very small card sizes we may encounter a problem with rounding error making the rect not fit
System.out.println(e);
}
}
// Draw +1/+1 and other counters
protected void drawCounters(Graphics2D g) {
int xPos = (int) (0.65 * cardWidth);
@ -442,4 +483,10 @@ public abstract class CardRenderer {
public void setArtImage(Image image) {
artImage = CardRendererUtils.toBufferedImage(image);
}
// Set the card art image (CardPanel will give it to us when it
// is loaded and ready)
public void setFaceArtImage(Image image) {
faceArtImage = CardRendererUtils.toBufferedImage(image);
}
}

View file

@ -16,8 +16,8 @@ import java.util.regex.Pattern;
/**
* @author stravant@gmail.com
* <p>
* Various static utilities for use in the card renderer
* <p>
* Various static utilities for use in the card renderer
*/
public final class CardRendererUtils {
@ -51,6 +51,38 @@ public final class CardRendererUtils {
// Return the buffered image
return bimage;
}
private static Color abitbrighter(Color c) {
int r = c.getRed();
int g = c.getGreen();
int b = c.getBlue();
int alpha = c.getAlpha();
int plus_r = (int) ((255 - r) / 2);
int plus_g = (int) ((255 - g) / 2);
int plus_b = (int) ((255 - b) / 2);
return new Color(r + plus_r,
g + plus_g,
b + plus_b,
alpha);
}
private static Color abitdarker(Color c) {
int r = c.getRed();
int g = c.getGreen();
int b = c.getBlue();
int alpha = c.getAlpha();
int plus_r = (int) (Math.min (255 - r, r) / 2);
int plus_g = (int) (Math.min (255 - g, g) / 2);
int plus_b = (int) (Math.min (255 - b, b) / 2);
return new Color(r - plus_r,
g - plus_g,
b - plus_b,
alpha);
}
// Draw a rounded box with a 2-pixel border
// Used on various card parts.
@ -68,6 +100,12 @@ public final class CardRendererUtils {
g.fillOval(x + 2, y + 2, bevel * 2 - 4, h - 4);
g.fillOval(x + 2 + w - bevel * 2, y + 2, bevel * 2 - 4, h - 4);
g.fillRect(x + bevel, y + 2, w - 2 * bevel, h - 4);
g.setPaint(fill);
g.setColor(abitbrighter(g.getColor()));
g.drawLine(x + 1 + bevel, y + 1, x + 1 + bevel + w - 2 * bevel - 2, y + 1);
g.setPaint(fill);
g.setColor(abitdarker(g.getColor()));
g.drawLine(x + 1 + bevel, y + h - 2, x + 1 + bevel + w - 2 * bevel - 2, y + h - 2);
}
// Get the width of a mana cost rendered with ManaSymbols.draw

View file

@ -1,11 +1,13 @@
package org.mage.card.arcane;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageProducer;
import java.awt.image.RGBImageFilter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
@ -16,27 +18,37 @@ import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.HashSet;
import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
import javax.swing.*;
import mage.cards.repository.ExpansionRepository;
import mage.client.dialog.PreferencesDialog;
import mage.client.util.GUISizeHelper;
import mage.client.util.ImageHelper;
import mage.client.util.gui.BufferedImageBuilder;
import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.TranscodingHints;
import org.apache.batik.transcoder.image.ImageTranscoder;
import org.apache.batik.util.SVGConstants;
import org.apache.log4j.Logger;
import org.mage.plugins.card.constants.Constants;
import mage.client.constants.Constants;
import mage.client.constants.Constants.ResourceSymbolSize;
import mage.client.constants.Constants.ResourceSetSize;
import org.jdesktop.swingx.graphics.ShadowRenderer;
import org.jdesktop.swingx.graphics.GraphicsUtilities;
import org.mage.plugins.card.utils.CardImageUtils;
public final class ManaSymbols {
private static final Logger LOGGER = Logger.getLogger(ManaSymbols.class);
private static final Map<Integer, Map<String, BufferedImage>> manaImages = new HashMap<>();
private static boolean smallSymbolsFound = false;
private static boolean mediumSymbolsFound = false;
private static final Map<String, Map<String, Image>> setImages = new HashMap<>();
@ -63,11 +75,46 @@ public final class ManaSymbols {
"BR", "G", "GU", "GW", "R", "RG", "RW", "S", "T", "U", "UB", "UR", "W", "WB", "WU",
"WP", "UP", "BP", "RP", "GP", "X", "C", "E"};
public static void loadImages() {
renameSymbols(getSymbolsPath() + File.separator + "symbols");
smallSymbolsFound = loadSymbolsImages(15);
mediumSymbolsFound = loadSymbolsImages(25);
private static final JLabel labelRender = new JLabel(); // render mana text
public static void loadImages() {
// TODO: delete files rename jpg->gif (it was for backward compatibility for one of the old version?)
renameSymbols(getResourceSymbolsPath(ResourceSymbolSize.SMALL));
renameSymbols(getResourceSymbolsPath(ResourceSymbolSize.MEDIUM));
renameSymbols(getResourceSymbolsPath(ResourceSymbolSize.LARGE));
//renameSymbols(getSymbolsPath(ResourceSymbolSize.SVG)); // not need
// TODO: remove medium sets files to "medium" folder like symbols above?
// preload symbol images
loadSymbolImages(15);
loadSymbolImages(25);
loadSymbolImages(50);
// save symbol images in png for html replacement in texts
// you can add bigger size for better quality
Map<String, BufferedImage> pngImages = manaImages.get(50);
if (pngImages != null){
File pngPath = new File(getResourceSymbolsPath(ResourceSymbolSize.PNG));
if (!pngPath.exists()) {
pngPath.mkdirs();
}
for(String symbol: symbols){
try
{
BufferedImage image = pngImages.get(symbol);
if (image != null){
File newFile = new File(pngPath.getPath() + File.separator + symbol + ".png");
ImageIO.write(image, "png", newFile);
}
}catch (Exception e) {
LOGGER.warn("Can't generate png image for symbol:" + symbol);
}
}
}
// preload set images
List<String> setCodes = ExpansionRepository.instance.getSetCodes();
if (setCodes == null) {
// the cards db file is probaly not included in the client. It will be created after the first connect to a server.
@ -75,9 +122,11 @@ public final class ManaSymbols {
return;
}
for (String set : setCodes) {
if (withoutSymbols.contains(set)) {
continue;
}
String[] codes;
if (onlyMythics.contains(set)) {
codes = new String[]{"M"};
@ -88,8 +137,9 @@ public final class ManaSymbols {
Map<String, Image> rarityImages = new HashMap<>();
setImages.put(set, rarityImages);
// load medium size
for (String rarityCode : codes) {
File file = new File(getSymbolsPath() + Constants.RESOURCE_PATH_SET + set + '-' + rarityCode + ".jpg");
File file = new File(getResourceSetsPath(ResourceSetSize.MEDIUM) + set + '-' + rarityCode + ".jpg");
try {
Image image = UI.getImageIcon(file.getAbsolutePath()).getImage();
int width = image.getWidth(null);
@ -107,18 +157,19 @@ public final class ManaSymbols {
}
}
// generate small size
try {
File file = new File(getSymbolsPath() + Constants.RESOURCE_PATH_SET_SMALL);
File file = new File(getResourceSetsPath(ResourceSetSize.MEDIUM));
if (!file.exists()) {
file.mkdirs();
}
for (String code : codes) {
file = new File(getSymbolsPath() + Constants.RESOURCE_PATH_SET_SMALL + set + '-' + code + ".png");
file = new File(getResourceSetsPath(ResourceSetSize.MEDIUM) + set + '-' + code + ".png");
if (file.exists()) {
continue;
}
file = new File(getSymbolsPath() + Constants.RESOURCE_PATH_SET + set + '-' + code + ".jpg");
file = new File(getResourceSetsPath(ResourceSetSize.MEDIUM) + set + '-' + code + ".jpg");
Image image = UI.getImageIcon(file.getAbsolutePath()).getImage();
try {
int width = image.getWidth(null);
@ -130,7 +181,7 @@ public final class ManaSymbols {
}
Rectangle r = new Rectangle(15 + dx, (int) (height * (15.0f + dx) / width));
BufferedImage resized = ImageHelper.getResizedImage(BufferedImageBuilder.bufferImage(image, BufferedImage.TYPE_INT_ARGB), r);
File newFile = new File(getSymbolsPath() + Constants.RESOURCE_PATH_SET_SMALL + File.separator + set + '-' + code + ".png");
File newFile = new File(getResourceSetsPath(ResourceSetSize.SMALL) + set + '-' + code + ".png");
ImageIO.write(resized, "png", newFile);
}
} catch (Exception e) {
@ -144,13 +195,15 @@ public final class ManaSymbols {
}
}
// mark loaded images
// TODO: delete that code, images draw-show must dynamicly
File file;
for (String set : ExpansionRepository.instance.getSetCodes()) {
file = new File(getSymbolsPath() + Constants.RESOURCE_PATH_SET_SMALL);
file = new File(getResourceSetsPath(ResourceSetSize.SMALL));
if (!file.exists()) {
break;
}
file = new File(getSymbolsPath() + Constants.RESOURCE_PATH_SET_SMALL + set + "-C.png");
file = new File(getResourceSetsPath(ResourceSetSize.SMALL) + set + "-C.png");
try {
Image image = UI.getImageIcon(file.getAbsolutePath()).getImage();
int width = image.getWidth(null);
@ -161,42 +214,250 @@ public final class ManaSymbols {
}
}
private static boolean loadSymbolsImages(int size) {
boolean fileErrors = false;
HashMap<String, BufferedImage> sizedSymbols = new HashMap<>();
String resourcePath = Constants.RESOURCE_PATH_MANA_SMALL;
if (size > 25) {
resourcePath = Constants.RESOURCE_PATH_MANA_LARGE;
} else if (size > 15) {
resourcePath = Constants.RESOURCE_PATH_MANA_MEDIUM;
}
for (String symbol : symbols) {
File file = new File(getSymbolsPath() + resourcePath + '/' + symbol + ".gif");
try {
public static BufferedImage loadSVG(File svgFile, int resizeToWidth, int resizeToHeight, boolean useShadow) throws IOException {
if (size == 15 || size == 25) {
BufferedImage notResized = ImageIO.read(file);
sizedSymbols.put(symbol, notResized);
} else {
Rectangle r = new Rectangle(size, size);
//Image image = UI.getImageIcon(file.getAbsolutePath()).getImage();
BufferedImage image = ImageIO.read(file);
//BufferedImage resized = ImageHelper.getResizedImage(BufferedImageBuilder.bufferImage(image, BufferedImage.TYPE_INT_ARGB), r);
if (image != null) {
BufferedImage resized = ImageHelper.getResizedImage(image, r);
sizedSymbols.put(symbol, resized);
}
// debug: disable shadow gen, need to test it
useShadow = false;
// load SVG image
// base loader code: https://stackoverflow.com/questions/11435671/how-to-get-a-buffererimage-from-a-svg
// resize code: https://vibranttechie.wordpress.com/2015/05/15/svg-loading-to-javafx-stage-and-auto-scaling-when-stage-resize/
if (useShadow && ((resizeToWidth <= 0) || (resizeToHeight <= 0))){
throw new IllegalArgumentException("Must use non zero sizes for shadow.");
}
final BufferedImage[] imagePointer = new BufferedImage[1];
// Rendering hints can't be set programatically, so
// we override defaults with a temporary stylesheet.
// These defaults emphasize quality and precision, and
// are more similar to the defaults of other SVG viewers.
// SVG documents can still override these defaults.
String css = "svg {" +
"shape-rendering: geometricPrecision;" +
"text-rendering: geometricPrecision;" +
"color-rendering: optimizeQuality;" +
"image-rendering: optimizeQuality;" +
"}";
File cssFile = File.createTempFile("batik-default-override-", ".css");
FileWriter w = new FileWriter(cssFile);
w.write(css);
w.close();
TranscodingHints transcoderHints = new TranscodingHints();
// resize
int shadowX = 0;
int shadowY = 0;
if(useShadow) {
// shadow size (16px image: 1px left, 2px bottom)
shadowX = 1 * Math.round(1f / 16f * resizeToWidth);
shadowY = 2 * Math.round(1f / 16f * resizeToHeight);
resizeToWidth = resizeToWidth - shadowX;
resizeToHeight = resizeToHeight - shadowY;
};
if(resizeToWidth > 0){
transcoderHints.put(ImageTranscoder.KEY_WIDTH, (float)resizeToWidth); //your image width
}
if(resizeToHeight > 0){
transcoderHints.put(ImageTranscoder.KEY_HEIGHT, (float)resizeToHeight); //your image height
}
transcoderHints.put(ImageTranscoder.KEY_XML_PARSER_VALIDATING, Boolean.FALSE);
transcoderHints.put(ImageTranscoder.KEY_DOM_IMPLEMENTATION,
SVGDOMImplementation.getDOMImplementation());
transcoderHints.put(ImageTranscoder.KEY_DOCUMENT_ELEMENT_NAMESPACE_URI,
SVGConstants.SVG_NAMESPACE_URI);
transcoderHints.put(ImageTranscoder.KEY_DOCUMENT_ELEMENT, "svg");
transcoderHints.put(ImageTranscoder.KEY_USER_STYLESHEET_URI, cssFile.toURI().toString());
try {
TranscoderInput input = new TranscoderInput(new FileInputStream(svgFile));
ImageTranscoder t = new ImageTranscoder() {
@Override
public BufferedImage createImage(int w, int h) {
return new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
}
} catch (IOException e) {
LOGGER.error("Error for symbol:" + symbol);
@Override
public void writeImage(BufferedImage image, TranscoderOutput out)
throws TranscoderException {
imagePointer[0] = image;
}
};
t.setTranscodingHints(transcoderHints);
t.transcode(input, null);
} catch (Exception e) {
throw new IOException("Couldn't convert svg file: " + svgFile + " , reason: " + e.getMessage());
}
finally {
cssFile.delete();
}
BufferedImage originImage = imagePointer[0];
if(useShadow && (originImage.getWidth() > 0)){
// draw shadow
// origin image was reduces in sizes to fit shadow
// see https://stackoverflow.com/a/40833715/1276632
// a filter which converts all colors except 0 to black
ImageProducer prod = new FilteredImageSource(originImage.getSource(), new RGBImageFilter() {
@Override
public int filterRGB(int x, int y, int rgb) {
if (rgb == 0)
return 0;
else
return 0xff000000;
}
});
// create whe black image
Image shadow = Toolkit.getDefaultToolkit().createImage(prod);
// result
BufferedImage result = new BufferedImage(originImage.getWidth() + shadowX, originImage.getHeight() + shadowY, originImage.getType());
Graphics2D g = (Graphics2D) result.getGraphics();
// draw shadow with offset (left bottom)
g.drawImage(shadow, -1 * shadowX, shadowY, null);
// draw original image
g.drawImage(originImage, 0, 0, null);
return result;
}else{
// return origin image without shadow
return originImage;
}
/*
BufferedImage base = GraphicsUtilities.createCompatibleTranslucentImage(w, h);
Graphics2D g2 = base.createGraphics();
g2.setColor(Color.WHITE);
g2.fillRoundRect(0, 0, image.getWidth(), image.getHeight(), 10, 10);
g2.dispose();
ShadowRenderer renderer = new ShadowRenderer(shadowSize, 0.5f,
Color.GRAY);
return renderer.createShadow(base);
*/
//imagePointer[0];
}
public static File getSymbolFileNameAsSVG(String symbol){
return new File(getResourceSymbolsPath(ResourceSymbolSize.SVG) + symbol + ".svg");
}
private static BufferedImage loadSymbolAsSVG(String symbol, int resizeToWidth, int resizeToHeight){
File sourceFile = getSymbolFileNameAsSVG(symbol);
return loadSymbolAsSVG(sourceFile, resizeToWidth, resizeToHeight);
}
private static BufferedImage loadSymbolAsSVG(File sourceFile, int resizeToWidth, int resizeToHeight){
try{
// no need to resize svg (lib already do it on load)
return loadSVG(sourceFile, resizeToWidth, resizeToHeight, true);
} catch (Exception e) {
LOGGER.error("Can't load svg symbol: " + sourceFile.getPath() + " , reason: " + e.getMessage());
return null;
}
}
private static File getSymbolFileNameAsGIF(String symbol, int size){
ResourceSymbolSize needSize = null;
if (size <= 15){
needSize = ResourceSymbolSize.SMALL;
}else if (size <= 25){
needSize = ResourceSymbolSize.MEDIUM;
} else {
needSize = ResourceSymbolSize.LARGE;
}
return new File(getResourceSymbolsPath(needSize) + symbol + ".gif");
}
private static BufferedImage loadSymbolAsGIF(String symbol, int resizeToWidth, int resizeToHeight){
File file = getSymbolFileNameAsGIF(symbol, resizeToWidth);
return loadSymbolAsGIF(file, resizeToWidth, resizeToHeight);
}
private static BufferedImage loadSymbolAsGIF(File sourceFile, int resizeToWidth, int resizeToHeight){
BufferedImage image = null;
try {
if ((resizeToWidth == 15) || (resizeToWidth == 25)){
// normal size
image = ImageIO.read(sourceFile);
}else{
// resize size
image = ImageIO.read(sourceFile);
if (image != null) {
Rectangle r = new Rectangle(resizeToWidth, resizeToHeight);
image = ImageHelper.getResizedImage(image, r);
}
}
} catch (IOException e) {
LOGGER.error("Can't load gif symbol: " + sourceFile.getPath());
return null;
}
return image;
}
private static boolean loadSymbolImages(int size) {
// load all symbols to cash
// priority: SVG -> GIF
// gif remain for backward compatibility
boolean fileErrors = false;
HashMap<String, BufferedImage> sizedSymbols = new HashMap<>();
for (String symbol : symbols) {
BufferedImage image = null;
File file = null;
// svg
file = getSymbolFileNameAsSVG(symbol);
if (file.exists()) {
image = loadSymbolAsSVG(file, size, size);
}
// gif
if (image == null) {
//LOGGER.info("SVG symbol can't be load: " + file.getPath());
file = getSymbolFileNameAsGIF(symbol, size);
if (file.exists()) {
image = loadSymbolAsGIF(file, size, size);
}
}
// save
if (image != null) {
sizedSymbols.put(symbol, image);
} else {
fileErrors = true;
LOGGER.warn("SVG or GIF symbol can't be load: " + symbol);
}
}
manaImages.put(size, sizedSymbols);
return !fileErrors;
}
private static void renameSymbols(String path) {
File file = new File(path);
if (!file.exists()){
return;
}
final PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:**/*.jpg");
try {
Files.walkFileTree(Paths.get(path), new SimpleFileVisitor<Path>() {
@ -210,60 +471,184 @@ public final class ManaSymbols {
}
});
} catch (IOException e) {
LOGGER.error("Couldn't rename mana symbols!");
LOGGER.error("Couldn't rename mana symbols on " + path, e);
}
}
private static String getSymbolsPath() {
return getSymbolsPath(false);
private static String getResourceSymbolsPath(ResourceSymbolSize needSize){
// return real path to symbols (default or user defined)
String path = CardImageUtils.getImagesDir() + Constants.RESOURCE_PATH_SYMBOLS + File.separator;
// folder by sizes
switch (needSize) {
case SMALL:
path = path + Constants.RESOURCE_SYMBOL_FOLDER_SMALL;
break;
case MEDIUM:
path = path + Constants.RESOURCE_SYMBOL_FOLDER_MEDIUM;
break;
case LARGE:
path = path + Constants.RESOURCE_SYMBOL_FOLDER_LARGE;
break;
case SVG:
path = path + Constants.RESOURCE_SYMBOL_FOLDER_SVG;
break;
case PNG:
path = path + Constants.RESOURCE_SYMBOL_FOLDER_PNG;
break;
default:
throw new java.lang.IllegalArgumentException(
"ResourceSymbolSize value is unknown");
}
// fix double separator if size folder is not set
while(path.endsWith(File.separator))
{
path = path.substring(0, path.length() - 1);
}
return path + File.separator;
}
private static String getSymbolsPath(boolean forHtmlCode) {
String useDefault = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_USE_DEFAULT, "true");
String path = useDefault.equals("true") ? null : PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PATH, null);
if (path == null) {
if (forHtmlCode) {
// for html code we need to use double '//' symbols
// and seems it should be hard coded - as it is not the same as using File.separator
return "plugins/images/";
} else {
return mage.client.constants.Constants.IO.imageBaseDir;
}
private static String getResourceSetsPath(ResourceSetSize needSize){
// return real path to sets icons (default or user defined)
String path = CardImageUtils.getImagesDir() + Constants.RESOURCE_PATH_SYMBOLS + File.separator;
// folder by sizes
switch (needSize) {
case SMALL:
path = path + Constants.RESOURCE_SET_FOLDER_SMALL;
break;
case MEDIUM:
path = path + Constants.RESOURCE_SET_FOLDER_MEDIUM;
break;
case SVG:
path = path + Constants.RESOURCE_SET_FOLDER_SVG;
break;
default:
throw new java.lang.IllegalArgumentException(
"ResourceSetSize value is unknown");
}
if (forHtmlCode) {
if (cachedPath != null) {
return cachedPath;
}
if (path.contains("\\")) {
cachedPath = path.replaceAll("[\\\\]", "/");
return cachedPath;
}
// fix double separator if size folder is not set
while(path.endsWith(File.separator))
{
path = path.substring(0, path.length() - 1);
}
return path;
return path + File.separator;
}
public static void draw(Graphics g, String manaCost, int x, int y, int symbolWidth) {
draw(g, manaCost, x, y, symbolWidth, Color.white, 0);
}
public static void draw(Graphics g, String manaCost, int x, int y, int symbolWidth, Color symbolsTextColor, int symbolMarginX) {
if (!manaImages.containsKey(symbolWidth)) {
loadSymbolsImages(symbolWidth);
loadSymbolImages(symbolWidth);
}
// TODO: replace with jlabel render (look at table rendere)?
/*
// NEW version with component draw
JPanel manaPanel = new JPanel();
// icons size with margin
int symbolHorizontalMargin = 2;
// create each mana symbol as child label
manaPanel.removeAll();
manaPanel.setLayout(new BoxLayout(manaPanel, BoxLayout.X_AXIS));
StringTokenizer tok = new StringTokenizer(manaCost, " ");
while (tok.hasMoreTokens()) {
String symbol = tok.nextToken();
JLabel symbolLabel = new JLabel();
//symbolLabel.setBorder(new LineBorder(new Color(150, 150, 150))); // debug
symbolLabel.setBorder(new EmptyBorder(0, symbolHorizontalMargin,0, 0));
BufferedImage image = ManaSymbols.getSizedManaSymbol(symbol, symbolWidth);
if (image != null){
// icon
symbolLabel.setIcon(new ImageIcon(image));
}else
{
// text
symbolLabel.setText("{" + symbol + "}");
//symbolLabel.setOpaque(baseLabel.isOpaque());
//symbolLabel.setForeground(baseLabel.getForeground());
//symbolLabel.setBackground(baseLabel.getBackground());
}
manaPanel.add(symbolLabel);
}
// draw result
Dimension d = manaPanel.getPreferredSize();
BufferedImage image = new BufferedImage(d.width, d.height, BufferedImage.TYPE_INT_ARGB);
Graphics2D gg = image.createGraphics();
manaPanel.paint(gg);
g.drawImage(image, x, y, null);
*/
// OLD version with custom draw
Map<String, BufferedImage> sizedSymbols = manaImages.get(symbolWidth);
if (manaCost.isEmpty()) {
return;
}
manaCost = manaCost.replace("\\", "");
manaCost = UI.getDisplayManaCost(manaCost);
StringTokenizer tok = new StringTokenizer(manaCost, " ");
while (tok.hasMoreTokens()) {
String symbol = tok.nextToken();
// Check and load symbol in the width
Image image = sizedSymbols.get(symbol);
if (image == null) {
//log.error("Symbol not recognized \"" + symbol + "\" in mana cost: " + manaCost);
continue;
// TEXT draw
labelRender.setText("{" + symbol + "}");
labelRender.setForeground(symbolsTextColor);
labelRender.setSize(symbolWidth, symbolWidth);
labelRender.setVerticalAlignment(SwingConstants.CENTER);
labelRender.setHorizontalAlignment(SwingConstants.CENTER);
//labelRender.setBorder(new LineBorder(new Color(125, 250, 250), 1));
// fix font size for mana text
// work for labels WITHOUT borders
// https://stackoverflow.com/questions/2715118/how-to-change-the-size-of-the-font-of-a-jlabel-to-take-the-maximum-size
Font labelFont = labelRender.getFont();
String labelText = "{W}"; //labelRender.getText(); // need same font size for all -- use max symbol ever, not current text
int stringWidth = labelRender.getFontMetrics(labelFont).stringWidth(labelText);
int componentWidth = labelRender.getWidth();
// Find out how much the font can grow in width.
double widthRatio = (double)componentWidth / (double)stringWidth;
int newFontSize = (int)(labelFont.getSize() * widthRatio);
int componentHeight = labelRender.getHeight();
// Pick a new font size so it will not be larger than the height of label.
int fontSizeToUse = Math.min(newFontSize, componentHeight);
// Set the label's font size to the newly determined size.
labelRender.setFont(new Font(labelFont.getName(), Font.PLAIN + Font.BOLD, fontSizeToUse - 1)); // - for "..." fix in text
// render component to new position
// need to copy graphics, overvise it draw at top left corner
// https://stackoverflow.com/questions/4974268/java-paint-problem
Graphics2D labelG = (Graphics2D)g.create(x, y, symbolWidth, symbolWidth);
labelG.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
labelG.fillOval(x + 1, y + 1, symbolWidth - 2, symbolWidth - 2);
labelRender.paint(labelG);
}else {
// ICON draw
g.drawImage(image, x, y, null);
}
g.drawImage(image, x, y, null);
x += symbolWidth;
x += symbolWidth + symbolMarginX;
}
}
public static String getStringManaCost(List<String> manaCost) {
@ -281,11 +666,21 @@ public final class ManaSymbols {
TOOLTIP,
}
private static String filePathToUrl(String path){
// convert file path to uri path (for html docs)
if((path != null) && (!path.equals(""))){
File file = new File(path);
return file.toURI().toString();
}else{
return null;
}
}
public static synchronized String replaceSymbolsWithHTML(String value, Type type) {
value = value.replace("{source}", "|source|");
value = value.replace("{this}", "|this|");
String replaced = value;
boolean symbolFilesFound;
// mana cost to HTML images (urls to files)
// do not use it for new code - try to suppotr svg render
int symbolSize;
switch (type) {
case TABLE:
@ -304,21 +699,41 @@ public final class ManaSymbols {
symbolSize = 11;
break;
}
String resourcePath = "small";
symbolFilesFound = smallSymbolsFound;
if (symbolSize > 25) {
resourcePath = "large";
} else if (symbolSize > 15) {
resourcePath = "medium";
symbolFilesFound = mediumSymbolsFound;
// auto size
ResourceSymbolSize needSize = null;
if (symbolSize <= 15){
needSize = ResourceSymbolSize.SMALL;
}else if (symbolSize <= 25){
needSize = ResourceSymbolSize.MEDIUM;
} else {
needSize = ResourceSymbolSize.LARGE;
}
if (symbolFilesFound) {
replaced = REPLACE_SYMBOLS_PATTERN.matcher(value).replaceAll(
"<img src='file:" + getSymbolsPath(true) + "/symbols/" + resourcePath + "/$1$2.gif' alt='$1$2' width=" + symbolSize
+ " height=" + symbolSize + '>');
}
replaced = replaced.replace("|source|", "{source}");
replaced = replaced.replace("|this|", "{this}");
// replace every {symbol} to <img> link
// ignore data backup
String replaced = value
.replace("{source}", "|source|")
.replace("{this}", "|this|");
// not need to add different images (width and height do the work)
// use best png size (generated on startup) TODO: add reload images after update
String htmlImagesPath = getResourceSymbolsPath(ResourceSymbolSize.PNG);
htmlImagesPath = htmlImagesPath
.replace("$", "@S@"); // paths with $ will rise error, need escape that
replaced = REPLACE_SYMBOLS_PATTERN.matcher(replaced).replaceAll(
"<img src='" + filePathToUrl(htmlImagesPath) + "$1$2" + ".png' alt='$1$2' width="
+ symbolSize + " height=" + symbolSize + '>');
// ignore data restore
replaced = replaced
.replace("|source|", "{source}")
.replace("|this|", "{this}")
.replace("@S@", "$");
return replaced;
}
@ -328,7 +743,7 @@ public final class ManaSymbols {
int factor = size / 15 + 1;
Integer width = setImagesExist.get(_set).width * factor;
Integer height = setImagesExist.get(_set).height * factor;
return "<img src='file:" + getSymbolsPath() + "/sets/small/" + _set + '-' + rarity + ".png' alt='" + rarity + "' height='" + height + "' width='" + width + "' >";
return "<img src='" + filePathToUrl(getResourceSetsPath(ResourceSetSize.SMALL)) + _set + '-' + rarity + ".png' alt='" + rarity + "' height='" + height + "' width='" + width + "' >";
} else {
return set;
}
@ -353,9 +768,10 @@ public final class ManaSymbols {
public static BufferedImage getSizedManaSymbol(String symbol, int size) {
if (!manaImages.containsKey(size)) {
loadSymbolsImages(size);
loadSymbolImages(size);
}
Map<String, BufferedImage> sizedSymbols = manaImages.get(size);
return sizedSymbols.get(symbol);
}
}

View file

@ -0,0 +1,66 @@
package org.mage.card.arcane;
import mage.client.util.GUISizeHelper;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableCellRenderer;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.StringTokenizer;
public final class ManaSymbolsCellRenderer extends DefaultTableCellRenderer {
// base panel to render
private JPanel manaPanel = new JPanel();
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
// get table text cell settings
DefaultTableCellRenderer baseRenderer = (DefaultTableCellRenderer) table.getDefaultRenderer(String.class);
JLabel baseLabel = (JLabel)baseRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
// apply settings to mana panel from parent
manaPanel.setOpaque(baseLabel.isOpaque());
manaPanel.setForeground(baseLabel.getForeground());
manaPanel.setBackground(baseLabel.getBackground());
// icons size with margin
int symbolWidth = GUISizeHelper.symbolTableSize;
int symbolHorizontalMargin = 2;
// create each mana symbol as child label
String manaCost = (String)value;
manaPanel.removeAll();
manaPanel.setLayout(new BoxLayout(manaPanel, BoxLayout.X_AXIS));
if(manaCost != null){
StringTokenizer tok = new StringTokenizer(manaCost, " ");
while (tok.hasMoreTokens()) {
String symbol = tok.nextToken();
JLabel symbolLabel = new JLabel();
//symbolLabel.setBorder(new LineBorder(new Color(150, 150, 150))); // debug
symbolLabel.setBorder(new EmptyBorder(0, symbolHorizontalMargin,0, 0));
BufferedImage image = ManaSymbols.getSizedManaSymbol(symbol, symbolWidth);
if (image != null){
// icon
symbolLabel.setIcon(new ImageIcon(image));
}else
{
// text
symbolLabel.setText("{" + symbol + "}");
symbolLabel.setOpaque(baseLabel.isOpaque());
symbolLabel.setForeground(baseLabel.getForeground());
symbolLabel.setBackground(baseLabel.getBackground());
}
manaPanel.add(symbolLabel);
}
}
return manaPanel;
}
}

View file

@ -5,19 +5,6 @@
*/
package org.mage.card.arcane;
import mage.ObjectColor;
import mage.cards.ArtRect;
import mage.cards.FrameStyle;
import mage.client.dialog.PreferencesDialog;
import mage.constants.CardType;
import mage.constants.MageObjectType;
import mage.constants.SubType;
import mage.util.SubTypeList;
import mage.view.CardView;
import mage.view.PermanentView;
import org.apache.log4j.Logger;
import javax.swing.*;
import java.awt.*;
import java.awt.font.*;
import java.awt.geom.Rectangle2D;
@ -31,6 +18,18 @@ import java.text.CharacterIterator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.swing.*;
import mage.ObjectColor;
import mage.cards.ArtRect;
import mage.cards.FrameStyle;
import mage.client.dialog.PreferencesDialog;
import mage.constants.CardType;
import mage.constants.MageObjectType;
import mage.constants.SubType;
import mage.util.SubTypeList;
import mage.view.CardView;
import mage.view.PermanentView;
import org.apache.log4j.Logger;
/*
@ -77,9 +76,9 @@ public class ModernCardRenderer extends CardRenderer {
}
private static Font loadFont(String name) {
try(InputStream in = ModernCardRenderer.class.getResourceAsStream("/cardrender/" + name + ".ttf")) {
try (InputStream in = ModernCardRenderer.class.getResourceAsStream("/cardrender/" + name + ".ttf")) {
return Font.createFont(
Font.TRUETYPE_FONT,in);
Font.TRUETYPE_FONT, in);
} catch (IOException e) {
LOGGER.info("Failed to load font `" + name + "`, couldn't find resource.");
} catch (FontFormatException e) {
@ -107,7 +106,7 @@ public class ModernCardRenderer extends CardRenderer {
public static final Color BORDER_RED = new Color(201, 71, 58);
public static final Color BORDER_GREEN = new Color(4, 136, 69);
public static final Color BORDER_GOLD = new Color(255, 228, 124);
public static final Color BORDER_COLORLESS = new Color(238, 242, 242);
public static final Color BORDER_COLORLESS = new Color(208, 212, 212);
public static final Color BORDER_LAND = new Color(190, 173, 115);
public static final Color BOX_WHITE = new Color(244, 245, 239);
@ -116,7 +115,7 @@ public class ModernCardRenderer extends CardRenderer {
public static final Color BOX_RED = new Color(246, 208, 185);
public static final Color BOX_GREEN = new Color(205, 221, 213);
public static final Color BOX_GOLD = new Color(223, 195, 136);
public static final Color BOX_COLORLESS = new Color(220, 228, 232);
public static final Color BOX_COLORLESS = new Color(200, 208, 212);
public static final Color BOX_LAND = new Color(220, 215, 213);
public static final Color BOX_INVENTION = new Color(209, 97, 33);
public static final Color BOX_VEHICLE = new Color(155, 105, 60);
@ -129,21 +128,21 @@ public class ModernCardRenderer extends CardRenderer {
public static final Color BOX_GOLD_NIGHT = new Color(171, 134, 70);
public static final Color BOX_COLORLESS_NIGHT = new Color(118, 147, 158);
public static final Color LAND_TEXTBOX_WHITE = new Color(248, 232, 188, 244);
public static final Color LAND_TEXTBOX_BLUE = new Color(189, 212, 236, 244);
public static final Color LAND_TEXTBOX_BLACK = new Color(174, 164, 162, 244);
public static final Color LAND_TEXTBOX_RED = new Color(242, 168, 133, 244);
public static final Color LAND_TEXTBOX_GREEN = new Color(198, 220, 198, 244);
public static final Color LAND_TEXTBOX_GOLD = new Color(236, 229, 207, 244);
public static final Color LAND_TEXTBOX_WHITE = new Color(248, 232, 188, 234);
public static final Color LAND_TEXTBOX_BLUE = new Color(189, 212, 236, 234);
public static final Color LAND_TEXTBOX_BLACK = new Color(174, 164, 162, 234);
public static final Color LAND_TEXTBOX_RED = new Color(242, 168, 133, 234);
public static final Color LAND_TEXTBOX_GREEN = new Color(198, 220, 198, 234);
public static final Color LAND_TEXTBOX_GOLD = new Color(236, 229, 207, 234);
public static final Color TEXTBOX_WHITE = new Color(252, 249, 244, 244);
public static final Color TEXTBOX_BLUE = new Color(229, 238, 247, 244);
public static final Color TEXTBOX_BLACK = new Color(241, 241, 240, 244);
public static final Color TEXTBOX_RED = new Color(243, 224, 217, 244);
public static final Color TEXTBOX_GREEN = new Color(217, 232, 223, 244);
public static final Color TEXTBOX_GOLD = new Color(240, 234, 209, 244);
public static final Color TEXTBOX_COLORLESS = new Color(219, 229, 233, 244);
public static final Color TEXTBOX_LAND = new Color(218, 214, 212, 244);
public static final Color TEXTBOX_WHITE = new Color(252, 249, 244, 234);
public static final Color TEXTBOX_BLUE = new Color(229, 238, 247, 234);
public static final Color TEXTBOX_BLACK = new Color(241, 241, 240, 234);
public static final Color TEXTBOX_RED = new Color(243, 224, 217, 234);
public static final Color TEXTBOX_GREEN = new Color(217, 232, 223, 234);
public static final Color TEXTBOX_GOLD = new Color(240, 234, 209, 234);
public static final Color TEXTBOX_COLORLESS = new Color(199, 209, 213, 234);
public static final Color TEXTBOX_LAND = new Color(218, 214, 212, 234);
public static final Color ERROR_COLOR = new Color(255, 0, 255);
@ -280,6 +279,8 @@ public class ModernCardRenderer extends CardRenderer {
// Just draw a brown rectangle
drawCardBack(g);
} else {
BufferedImage bufferedImage = new BufferedImage(300, 300, BufferedImage.TYPE_INT_RGB);
// Set texture to paint with
g.setPaint(getBackgroundPaint(cardView.getColor(), cardView.getCardTypes(), cardView.getSubTypes()));
@ -349,11 +350,18 @@ public class ModernCardRenderer extends CardRenderer {
@Override
protected void drawArt(Graphics2D g) {
if (artImage != null && !cardView.isFaceDown()) {
boolean useFaceArt = false;
if (faceArtImage != null) {
useFaceArt = true;
}
// Invention rendering, art fills the entire frame
if (useInventionFrame()) {
useFaceArt = false;
drawArtIntoRect(g,
borderWidth, borderWidth,
cardWidth - 2*borderWidth, cardHeight - 2*borderWidth,
cardWidth - 2 * borderWidth, cardHeight - 2 * borderWidth,
getArtRect(), false);
}
@ -361,17 +369,18 @@ public class ModernCardRenderer extends CardRenderer {
Rectangle2D sourceRect = getArtRect();
if (cardView.getMageObjectType() == MageObjectType.SPELL) {
useFaceArt = false;
ArtRect rect = cardView.getArtRect();
if (rect == ArtRect.SPLIT_FUSED) {
// Special handling for fused, draw the art from both halves stacked on top of one and other
// each filling half of the art rect
drawArtIntoRect(g,
totalContentInset + 1, totalContentInset + boxHeight,
contentWidth - 2, (typeLineY - totalContentInset - boxHeight)/2,
contentWidth - 2, (typeLineY - totalContentInset - boxHeight) / 2,
ArtRect.SPLIT_LEFT.rect, useInventionFrame());
drawArtIntoRect(g,
totalContentInset + 1, totalContentInset + boxHeight + (typeLineY - totalContentInset - boxHeight)/2,
contentWidth - 2, (typeLineY - totalContentInset - boxHeight)/2,
totalContentInset + 1, totalContentInset + boxHeight + (typeLineY - totalContentInset - boxHeight) / 2,
contentWidth - 2, (typeLineY - totalContentInset - boxHeight) / 2,
ArtRect.SPLIT_RIGHT.rect, useInventionFrame());
return;
} else if (rect != ArtRect.NORMAL) {
@ -381,10 +390,17 @@ public class ModernCardRenderer extends CardRenderer {
}
// Normal drawing of art from a source part of the card frame into the rect
drawArtIntoRect(g,
totalContentInset + 1, totalContentInset + boxHeight,
contentWidth - 2, typeLineY - totalContentInset - boxHeight,
sourceRect, shouldPreserveAspect);
if (useFaceArt) {
drawFaceArtIntoRect(g,
totalContentInset + 1, totalContentInset + boxHeight,
contentWidth - 2, typeLineY - totalContentInset - boxHeight,
sourceRect, shouldPreserveAspect);
} else {
drawArtIntoRect(g,
totalContentInset + 1, totalContentInset + boxHeight,
contentWidth - 2, typeLineY - totalContentInset - boxHeight,
sourceRect, shouldPreserveAspect);
}
}
}
@ -421,6 +437,7 @@ public class ModernCardRenderer extends CardRenderer {
g.setPaint(new Color(255, 255, 255, 150));
} else {
g.setPaint(textboxPaint);
}
g.fillRect(
totalContentInset + 1, typeLineY,
@ -477,6 +494,9 @@ public class ModernCardRenderer extends CardRenderer {
// Draw the transform circle
int nameOffset = drawTransformationCircle(g, borderPaint);
// Draw the transform circle
nameOffset = drawTransformationCircle(g, borderPaint);
// Draw the name line
drawNameLine(g, cardView.getDisplayName(), manaCostString,
totalContentInset + nameOffset, totalContentInset,
@ -541,7 +561,7 @@ public class ModernCardRenderer extends CardRenderer {
// Draw the mana symbols
if (!cardView.isAbility() && !cardView.isFaceDown()) {
ManaSymbols.draw(g, manaCost, x + w - manaCostWidth, y + boxTextOffset, boxTextHeight);
ManaSymbols.draw(g, manaCost, x + w - manaCostWidth, y + boxTextOffset, boxTextHeight, Color.black, 2);
}
}
@ -824,7 +844,7 @@ public class ModernCardRenderer extends CardRenderer {
String symbs = symbol;
int symbHeight = (int) (0.8 * h);
int manaCostWidth = CardRendererUtils.getManaCostWidth(symbs, symbHeight);
ManaSymbols.draw(g, symbs, x + (w - manaCostWidth) / 2, y + (h - symbHeight) / 2, symbHeight);
ManaSymbols.draw(g, symbs, x + (w - manaCostWidth) / 2, y + (h - symbHeight) / 2, symbHeight, Color.black, 2);
}
// Get the first line of the textbox, the keyword string
@ -849,6 +869,9 @@ public class ModernCardRenderer extends CardRenderer {
inset = cardWidth / 12;
}
int availWidth = w - inset;
if (availWidth < 0) {
return 0;
}
FontRenderContext frc = g.getFontRenderContext();
AttributedCharacterIterator textIter = text.getIterator();

View file

@ -6,7 +6,6 @@ import mage.client.dialog.PreferencesDialog;
import mage.client.util.GUISizeHelper;
import mage.constants.Rarity;
import mage.interfaces.plugin.CardPlugin;
import mage.utils.CardUtil;
import mage.view.CardView;
import mage.view.CounterView;
import mage.view.PermanentView;
@ -19,10 +18,10 @@ import org.mage.card.arcane.*;
import org.mage.plugins.card.dl.DownloadGui;
import org.mage.plugins.card.dl.DownloadJob;
import org.mage.plugins.card.dl.Downloader;
import org.mage.plugins.card.dl.sources.CardFrames;
import org.mage.plugins.card.dl.sources.DirectLinksForDownload;
import org.mage.plugins.card.dl.sources.GathererSets;
import org.mage.plugins.card.dl.sources.GathererSymbols;
import org.mage.plugins.card.dl.sources.ScryfallSymbolsSource;
import org.mage.plugins.card.images.ImageCache;
import org.mage.plugins.card.info.CardInfoPaneImpl;
@ -525,41 +524,49 @@ public class CardPluginImpl implements CardPlugin {
/**
* Download various symbols (mana, tap, set).
*
* @param imagesPath Path to check in and store symbols to. Can be null, in
* such case default path should be used.
* @param imagesDir Path to check in and store symbols to. Can't be null.
*/
@Override
public void downloadSymbols(String imagesPath) {
public void downloadSymbols(String imagesDir) {
final DownloadGui g = new DownloadGui(new Downloader());
Iterable<DownloadJob> it = new GathererSymbols(imagesPath);
Iterable<DownloadJob> it;
it = new GathererSymbols();
for (DownloadJob job : it) {
g.getDownloader().add(job);
}
it = new GathererSets(imagesPath);
it = new GathererSets();
for (DownloadJob job : it) {
g.getDownloader().add(job);
}
it = new CardFrames(imagesPath);
it = new ScryfallSymbolsSource();
for (DownloadJob job : it) {
g.getDownloader().add(job);
}
it = new DirectLinksForDownload(imagesPath);
/*
it = new CardFrames(imagesDir); // TODO: delete frames download (not need now)
for (DownloadJob job : it) {
g.getDownloader().add(job);
}
*/
it = new DirectLinksForDownload();
for (DownloadJob job : it) {
g.getDownloader().add(job);
}
JDialog d = new JDialog((Frame) null, "Download pictures", false);
JDialog d = new JDialog((Frame) null, "Download symbols", false);
d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
d.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
g.getDownloader().dispose();
ManaSymbols.loadImages();
// TODO: check reload process after download (icons do not update)
}
});
d.setLayout(new BorderLayout());

View file

@ -1,26 +0,0 @@
package org.mage.plugins.card.constants;
import java.awt.Rectangle;
import java.io.File;
public final class Constants {
public static final String RESOURCE_PATH_SET = File.separator + "sets" + File.separator;
public static final String RESOURCE_PATH_MANA_SMALL = File.separator + "symbols" + File.separator + "small";
public static final String RESOURCE_PATH_MANA_LARGE = File.separator + "symbols" + File.separator + "large";
public static final String RESOURCE_PATH_MANA_MEDIUM = File.separator + "symbols" + File.separator + "medium";
public static final String RESOURCE_PATH_SET_SMALL = RESOURCE_PATH_SET + File.separator + "small" + File.separator;
public static final Rectangle CARD_SIZE_FULL = new Rectangle(101, 149);
public static final Rectangle THUMBNAIL_SIZE_FULL = new Rectangle(102, 146);
public interface IO {
String imageBaseDir = "plugins" + File.separator + "images";
String IMAGE_PROPERTIES_FILE = "image.url.properties";
}
public static final String CARD_IMAGE_PATH_TEMPLATE = '.' + File.separator + "plugins" + File.separator + "images/{set}/{name}.{collector}.full.jpg";
}

View file

@ -28,7 +28,6 @@ import org.mage.plugins.card.utils.CardImageUtils;
public class DownloadJob extends AbstractLaternaBean {
public enum State {
NEW, WORKING, FINISHED, ABORTED
}

View file

@ -11,9 +11,12 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import mage.client.constants.Constants;
import org.mage.plugins.card.dl.DownloadJob;
import static org.mage.plugins.card.dl.DownloadJob.fromURL;
import static org.mage.plugins.card.dl.DownloadJob.toFile;
import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
/**
* Used when we need to point to direct links to download resources from.
@ -22,7 +25,7 @@ import static org.mage.plugins.card.dl.DownloadJob.toFile;
*/
public class DirectLinksForDownload implements Iterable<DownloadJob> {
private static final String backsideUrl = "http://upload.wikimedia.org/wikipedia/en/a/aa/Magic_the_gathering-card_back.jpg";
private static final String backsideUrl = "https://upload.wikimedia.org/wikipedia/en/a/aa/Magic_the_gathering-card_back.jpg";
private static final Map<String, String> directLinks = new LinkedHashMap<>();
@ -33,15 +36,13 @@ public class DirectLinksForDownload implements Iterable<DownloadJob> {
directLinks.put(cardbackFilename, backsideUrl);
}
private static final String DEFAULT_IMAGES_PATH = File.separator + "default";
private static final File DEFAULT_OUT_DIR = new File("plugins" + File.separator + "images" + DEFAULT_IMAGES_PATH);
public static File outDir = DEFAULT_OUT_DIR;
public static File outDir;
public DirectLinksForDownload(String path) {
if (path == null) {
useDefaultDir();
} else {
changeOutDir(path);
public DirectLinksForDownload() {
outDir = new File(getImagesDir() + Constants.RESOURCE_PATH_DEFAUL_IMAGES);
if (!outDir.exists()){
outDir.mkdirs();
}
}
@ -55,20 +56,4 @@ public class DirectLinksForDownload implements Iterable<DownloadJob> {
}
return jobs.iterator();
}
private void changeOutDir(String path) {
File file = new File(path + DEFAULT_IMAGES_PATH);
if (file.exists()) {
outDir = file;
} else {
file.mkdirs();
if (file.exists()) {
outDir = file;
}
}
}
private void useDefaultDir() {
outDir = DEFAULT_OUT_DIR;
}
}

View file

@ -8,17 +8,41 @@ import java.util.HashMap;
import java.util.Iterator;
import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.client.constants.Constants;
import mage.constants.Rarity;
import org.apache.log4j.Logger;
import org.mage.plugins.card.dl.DownloadJob;
import static org.mage.plugins.card.dl.DownloadJob.fromURL;
import static org.mage.plugins.card.dl.DownloadJob.toFile;
import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
public class GathererSets implements Iterable<DownloadJob> {
private static final String SETS_PATH = File.separator + "sets";
private static final File DEFAULT_OUT_DIR = new File("plugins" + File.separator + "images" + SETS_PATH);
private static File outDir = DEFAULT_OUT_DIR;
private class CheckResult {
private static final String[] symbols = {"10E", "9ED", "8ED", "7ED", "6ED", "5ED", "4ED", "3ED", "2ED", "LEB", "LEA",
String code;
ExpansionSet set;
boolean haveCommon;
boolean haveUncommon;
boolean haveRare;
boolean haveMyth;
private CheckResult(String ACode, ExpansionSet ASet, boolean AHaveCommon, boolean AHaveUncommon, boolean AHhaveRare, boolean AHaveMyth) {
code = ACode;
set = ASet;
haveCommon = AHaveCommon;
haveUncommon = AHaveUncommon;
haveRare = AHhaveRare;
haveMyth = AHaveMyth;
}
}
private static File outDir;
private static final int DAYS_BEFORE_RELEASE_TO_DOWNLOAD = +14; // Try to load the symbolsBasic eralies 14 days before release date
private static final Logger logger = Logger.getLogger(GathererSets.class);
private static final String[] symbolsBasic = {"10E", "9ED", "8ED", "7ED", "6ED", "5ED", "4ED", "3ED", "2ED", "LEB", "LEA",
"HOP",
"ARN", "ATQ", "LEG", "DRK", "FEM", "HML",
"ICE", "ALL", "CSP",
@ -36,14 +60,19 @@ public class GathererSets implements Iterable<DownloadJob> {
"LRW", "MOR",
"SHM", "EVE",
"MED", "ME2", "ME3", "ME4",
"POR", "PO2", "PTK",
"POR", "P02", "PTK",
"ARC", "DD3EVG",
"W16", "W17"};
"W16", "W17",
//"APAC" -- gatherer do not have that set, scrly have PALP
//"ARENA" -- is't many set with different codes, not one
"CLASH", "CP", "DD3GVL", "DPA", "EURO", "FNMP", "GPX", "GRC", "GUR", "H17", "JR", "MBP", "MGDC", "MLP", "MPRP", "MPS-AKH", "PTC", "S00", "S99", "SUS", "SWS", "UGIN", "UGL", "V10", "V17", "WMCQ", // need to fix
"H09", "PD2", "PD3", "UNH", "CM1", "E02", "V11", "M25", "UST", "IMA", "DD2", "EVG", "DDC", "DDE", "DDD", "DDT", "8EB", "9EB", "CHR" // ok
// current testing
};
private static final String[] withMythics = {"M10", "M11", "M12", "M13", "M14", "M15", "ORI",
"ANB",
private static final String[] symbolsBasicWithMyth = {"M10", "M11", "M12", "M13", "M14", "M15", "ORI",
"DDF", "DDG", "DDH", "DDI", "DDJ", "DDK", "DDL", "DDM", "DDN",
"DD3DVD", "DD3GLV", "DD3JVC", "DDO", "DDP", "DDQ", "DDR", "DDS",
"DD3DVD", "DD3JVC", "DDO", "DDP", "DDQ", "DDR", "DDS", "DDT",
"ALA", "CON", "ARB",
"ZEN", "WWK", "ROE",
"SOM", "MBS", "NPH",
@ -60,131 +89,249 @@ public class GathererSets implements Iterable<DownloadJob> {
"SOI", "EMN",
"KLD", "AER",
"AKH", "HOU",
"XLN", "C17",
"RIX", "DOM", "M19", // not released
"E01"
};
private static final String[] onlyMythics = {
"DRB", "V09", "V12", "V12", "V13", "V14", "V15", "V16", "EXP"
private static final String[] symbolsOnlyMyth = {
"DRB", "V09", "V12", "V13", "V14", "V15", "V16", "EXP"
};
private static final String[] onlyMythicsAsSpecial = {
private static final String[] symbolsOnlySpecial = {
"MPS"
};
private static final HashMap<String, String> symbolsReplacements = new HashMap<>();
private static final HashMap<String, String> codeReplacements = new HashMap<>();
static {
symbolsReplacements.put("2ED", "2U");
symbolsReplacements.put("3ED", "3E");
symbolsReplacements.put("4ED", "4E");
symbolsReplacements.put("5ED", "5E");
symbolsReplacements.put("6ED", "6E");
symbolsReplacements.put("7ED", "7E");
symbolsReplacements.put("ALL", "AL");
symbolsReplacements.put("APC", "AP");
symbolsReplacements.put("ARN", "AN");
symbolsReplacements.put("ATQ", "AQ");
symbolsReplacements.put("CMA", "CM1");
symbolsReplacements.put("DD3DVD", "DD3_DVD");
symbolsReplacements.put("DD3EVG", "DD3_EVG");
symbolsReplacements.put("DD3GLV", "DD3_GLV");
symbolsReplacements.put("DD3JVC", "DD3_JVC");
symbolsReplacements.put("DRK", "DK");
symbolsReplacements.put("EXO", "EX");
symbolsReplacements.put("FEM", "FE");
symbolsReplacements.put("HML", "HM");
symbolsReplacements.put("ICE", "IA");
symbolsReplacements.put("INV", "IN");
symbolsReplacements.put("LEA", "1E");
symbolsReplacements.put("LEB", "2E");
symbolsReplacements.put("LEG", "LE");
symbolsReplacements.put("MPS", "MPS_KLD");
symbolsReplacements.put("MIR", "MI");
symbolsReplacements.put("MMQ", "MM");
symbolsReplacements.put("NEM", "NE");
symbolsReplacements.put("ODY", "OD");
symbolsReplacements.put("PCY", "PR");
symbolsReplacements.put("PLS", "PS");
symbolsReplacements.put("POR", "PO");
symbolsReplacements.put("PO2", "P2");
symbolsReplacements.put("PTK", "PK");
symbolsReplacements.put("STH", "ST");
symbolsReplacements.put("TMP", "TE");
symbolsReplacements.put("UDS", "CG");
symbolsReplacements.put("ULG", "GU");
symbolsReplacements.put("USG", "UZ");
symbolsReplacements.put("VIS", "VI");
symbolsReplacements.put("WTH", "WL");
codeReplacements.put("2ED", "2U");
codeReplacements.put("3ED", "3E");
codeReplacements.put("4ED", "4E");
codeReplacements.put("5ED", "5E");
codeReplacements.put("6ED", "6E");
codeReplacements.put("7ED", "7E");
codeReplacements.put("ALL", "AL");
codeReplacements.put("APC", "AP");
codeReplacements.put("ARN", "AN");
codeReplacements.put("ATQ", "AQ");
codeReplacements.put("CMA", "CM1");
codeReplacements.put("DD3DVD", "DD3_DVD");
codeReplacements.put("DD3EVG", "DD3_EVG");
codeReplacements.put("DD3JVC", "DD3_JVC");
codeReplacements.put("DRK", "DK");
codeReplacements.put("EXO", "EX");
codeReplacements.put("FEM", "FE");
codeReplacements.put("HML", "HM");
codeReplacements.put("ICE", "IA");
codeReplacements.put("INV", "IN");
codeReplacements.put("LEA", "1E");
codeReplacements.put("LEB", "2E");
codeReplacements.put("LEG", "LE");
codeReplacements.put("MPS", "MPS_KLD");
codeReplacements.put("MIR", "MI");
codeReplacements.put("MMQ", "MM");
codeReplacements.put("NEM", "NE");
codeReplacements.put("ODY", "OD");
codeReplacements.put("PCY", "PR");
codeReplacements.put("PLS", "PS");
codeReplacements.put("POR", "PO");
codeReplacements.put("P02", "P2");
codeReplacements.put("PTK", "PK");
codeReplacements.put("STH", "ST");
codeReplacements.put("TMP", "TE");
codeReplacements.put("UDS", "CG");
codeReplacements.put("ULG", "GU");
codeReplacements.put("USG", "UZ");
codeReplacements.put("VIS", "VI");
codeReplacements.put("WTH", "WL");
codeReplacements.put("8EB", "8ED"); // inner xmage set for 8th edition
codeReplacements.put("9EB", "8ED"); // inner xmage set for 9th edition
codeReplacements.put("CHR", "CH");
}
public GathererSets(String path) {
if (path == null) {
useDefaultDir();
} else {
changeOutDir(path);
public GathererSets() {
outDir = new File(getImagesDir() + Constants.RESOURCE_PATH_SYMBOLS);
if (!outDir.exists()) {
outDir.mkdirs();
}
}
// checks for wrong card settings and support (easy to control what all good)
private static final HashMap<String, CheckResult> setsToDownload = new HashMap<>();
private static final HashMap<String, String> codesToIgnoreCheck = new HashMap<>();
static {
// xMage have inner sets for 8th and 9th Edition for booster workaround (cards from core game do not include in boosters)
// see https://mtg.gamepedia.com/8th_Edition/Core_Game
// check must ignore that sets
codesToIgnoreCheck.put("8EB", "8th Edition Box");
codesToIgnoreCheck.put("9EB", "9th Edition Box");
}
private void CheckSearchResult(String searchCode, ExpansionSet foundedExp, boolean canDownloadTask,
boolean haveCommon, boolean haveUncommon, boolean haveRare, boolean haveMyth) {
// duplicated in settings
CheckResult res = setsToDownload.get(searchCode);
if (res != null) {
logger.error(String.format("Symbols: founded duplicated code: %s", searchCode));
} else {
res = new CheckResult(searchCode, foundedExp, haveCommon, haveUncommon, haveRare, haveMyth);
setsToDownload.put(searchCode, res);
}
// not found
if (foundedExp == null) {
logger.error(String.format("Symbols: can't find set by code: %s", searchCode));
return;
}
// checks for founded sets only
// to early to download
if (!canDownloadTask) {
Calendar c = Calendar.getInstance();
c.setTime(foundedExp.getReleaseDate());
c.add(Calendar.DATE, -1 * DAYS_BEFORE_RELEASE_TO_DOWNLOAD);
logger.warn(String.format("Symbols: early to download: %s (%s), available after %s",
searchCode, foundedExp.getName(), c.getTime()));
}
}
private void AnalyseSearchResult() {
// analyze supported sets and show wrong settings
Date startedDate = new Date();
for (ExpansionSet set : Sets.getInstance().values()) {
// ignore some inner sets
if (codesToIgnoreCheck.get(set.getCode()) != null) {
continue;
}
CheckResult res = setsToDownload.get(set.getCode());
// 1. not configured at all
if (res == null) {
logger.warn(String.format("Symbols: set is not configured: %s (%s)", set.getCode(), set.getName()));
continue; // can't do other checks
}
if (logger.isDebugEnabled()) {
// 2. missing rarity icon:
// WARNING, need too much time (60+ secs), only for debug mode
///*
if ((set.getCardsByRarity(Rarity.COMMON).size() > 0) && !res.haveCommon) {
logger.error(String.format("Symbols: set have common cards, but don't download icon: %s (%s)", set.getCode(), set.getName()));
}
if ((set.getCardsByRarity(Rarity.UNCOMMON).size() > 0) && !res.haveUncommon) {
logger.error(String.format("Symbols: set have uncommon cards, but don't download icon: %s (%s)", set.getCode(), set.getName()));
}
if ((set.getCardsByRarity(Rarity.RARE).size() > 0) && !res.haveRare) {
logger.error(String.format("Symbols: set have rare cards, but don't download icon: %s (%s)", set.getCode(), set.getName()));
}
if ((set.getCardsByRarity(Rarity.MYTHIC).size() > 0) && !res.haveMyth) {
logger.error(String.format("Symbols: set have mythic cards, but don't download icon: %s (%s)", set.getCode(), set.getName()));
}
//*/
// 3. info: sets with alternative numbers
for (ExpansionSet.SetCardInfo card : set.getSetCardInfo()) {
if (String.valueOf(card.getCardNumberAsInt()).length() != card.getCardNumber().length()) {
logger.info(String.format("Symbols: set have alternative card but do not config to it: %s (%s)", set.getCode(), set.getName()));
break;
}
}
// 4. info: sets with missing cards for boosters (todo: what about +20 number for alternative land arts?)
if (set.getMaxCardNumberInBooster() != Integer.MAX_VALUE) {
for (ExpansionSet.SetCardInfo card : set.getSetCardInfo()) {
if (card.getCardNumberAsInt() > set.getMaxCardNumberInBooster()) {
if (card.getRarity() == Rarity.LAND) {
logger.info(String.format("Symbols: set's booster have land above max card number: %s (%s), %s - %s", set.getCode(), set.getName(), card.getCardNumber(), card.getName()));
} else {
logger.info(String.format("Symbols: set's booster missing nonland card:: %s (%s), %s - %s", set.getCode(), set.getName(), card.getCardNumber(), card.getName()));
}
}
}
}
}
}
Date endedDate = new Date();
long secs = (endedDate.getTime() - startedDate.getTime()) / 1000;
logger.debug(String.format("Symbols: check completed after %d seconds", secs));
}
@Override
public Iterator<DownloadJob> iterator() {
Calendar c = Calendar.getInstance();
c.setTime(new Date());
c.add(Calendar.DATE, +14); // Try to load the symbols eralies 14 days before release date
c.add(Calendar.DATE, DAYS_BEFORE_RELEASE_TO_DOWNLOAD);
Date compareDate = c.getTime();
ArrayList<DownloadJob> jobs = new ArrayList<>();
for (String symbol : symbols) {
boolean canDownload;
setsToDownload.clear();
for (String symbol : symbolsBasic) {
ExpansionSet exp = Sets.findSet(symbol);
canDownload = false;
if (exp != null && exp.getReleaseDate().before(compareDate)) {
canDownload = true;
jobs.add(generateDownloadJob(symbol, "C", "C"));
jobs.add(generateDownloadJob(symbol, "U", "U"));
jobs.add(generateDownloadJob(symbol, "R", "R"));
}
CheckSearchResult(symbol, exp, canDownload, true, true, true, false);
}
for (String symbol : withMythics) {
for (String symbol : symbolsBasicWithMyth) {
ExpansionSet exp = Sets.findSet(symbol);
canDownload = false;
if (exp != null && exp.getReleaseDate().before(compareDate)) {
canDownload = true;
jobs.add(generateDownloadJob(symbol, "C", "C"));
jobs.add(generateDownloadJob(symbol, "U", "U"));
jobs.add(generateDownloadJob(symbol, "R", "R"));
jobs.add(generateDownloadJob(symbol, "M", "M"));
}
CheckSearchResult(symbol, exp, canDownload, true, true, true, true);
}
for (String symbol : onlyMythics) {
for (String symbol : symbolsOnlyMyth) {
ExpansionSet exp = Sets.findSet(symbol);
canDownload = false;
if (exp != null && exp.getReleaseDate().before(compareDate)) {
canDownload = true;
jobs.add(generateDownloadJob(symbol, "M", "M"));
}
CheckSearchResult(symbol, exp, canDownload, false, false, false, true);
}
for (String symbol : onlyMythicsAsSpecial) {
for (String symbol : symbolsOnlySpecial) {
ExpansionSet exp = Sets.findSet(symbol);
canDownload = false;
if (exp != null && exp.getReleaseDate().before(compareDate)) {
canDownload = true;
jobs.add(generateDownloadJob(symbol, "M", "S"));
}
CheckSearchResult(symbol, exp, canDownload, false, false, false, true);
}
// check wrong settings
AnalyseSearchResult();
return jobs.iterator();
}
private DownloadJob generateDownloadJob(String set, String rarity, String urlRarity) {
File dst = new File(outDir, set + '-' + rarity + ".jpg");
if (symbolsReplacements.containsKey(set)) {
set = symbolsReplacements.get(set);
if (codeReplacements.containsKey(set)) {
set = codeReplacements.get(set);
}
String url = "http://gatherer.wizards.com/Handlers/Image.ashx?type=symbol&set=" + set + "&size=small&rarity=" + urlRarity;
return new DownloadJob(set + '-' + rarity, fromURL(url), toFile(dst));
}
private void changeOutDir(String path) {
File file = new File(path + SETS_PATH);
if (file.exists()) {
outDir = file;
} else {
file.mkdirs();
if (file.exists()) {
outDir = file;
}
}
}
private void useDefaultDir() {
outDir = DEFAULT_OUT_DIR;
}
}

View file

@ -9,9 +9,12 @@ import com.google.common.collect.AbstractIterator;
import java.io.File;
import static java.lang.String.format;
import java.util.Iterator;
import mage.client.constants.Constants;
import org.mage.plugins.card.dl.DownloadJob;
import static org.mage.plugins.card.dl.DownloadJob.fromURL;
import static org.mage.plugins.card.dl.DownloadJob.toFile;
import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
/**
* The class GathererSymbols.
@ -23,9 +26,7 @@ public class GathererSymbols implements Iterable<DownloadJob> {
//TODO chaos and planeswalker symbol
//chaos: http://gatherer.wizards.com/Images/Symbols/chaos.gif
private static final String SYMBOLS_PATH = File.separator + "symbols";
private static final File DEFAULT_OUT_DIR = new File("plugins" + File.separator + "images" + SYMBOLS_PATH);
private static File outDir = DEFAULT_OUT_DIR;
private static File outDir;
private static final String urlFmt = "http://gatherer.wizards.com/handlers/image.ashx?size=%1$s&name=%2$s&type=symbol";
@ -38,11 +39,11 @@ public class GathererSymbols implements Iterable<DownloadJob> {
"X", "S", "T", "Q", "C", "E"};
private static final int minNumeric = 0, maxNumeric = 16;
public GathererSymbols(String path) {
if (path == null) {
useDefaultDir();
} else {
changeOutDir(path);
public GathererSymbols() {
outDir = new File(getImagesDir() + Constants.RESOURCE_PATH_SYMBOLS);
if (!outDir.exists()){
outDir.mkdirs();
}
}
@ -115,20 +116,4 @@ public class GathererSymbols implements Iterable<DownloadJob> {
}
};
}
private void changeOutDir(String path) {
File file = new File(path + SYMBOLS_PATH);
if (file.exists()) {
outDir = file;
} else {
file.mkdirs();
if (file.exists()) {
outDir = file;
}
}
}
private void useDefaultDir() {
outDir = DEFAULT_OUT_DIR;
}
}

View file

@ -199,12 +199,12 @@ public enum MagicCardsImageSource implements CardImageSource {
add("E01");
add("HOU");
add("C17");
// add("XLN");
// add("DDT");
// add("IMA");
// add("E02");
// add("V17");
// add("UST");
add("XLN");
add("DDT");
add("IMA");
add("E02");
add("V17");
add("UST");
// add("RIX");
// add("A25");
// add("DOM");
@ -262,6 +262,7 @@ public enum MagicCardsImageSource implements CardImageSource {
put("DDQ", "duel-decks-blessed-vs-cursed");
put("DDR", "duel-decks-nissa-vs-ob-nixilis");
put("DDS", "duel-decks-mind-vs-might");
put("DDS", "duel-decks-merfolk-vs-goblin");
put("DGM", "dragons-maze");
put("DKA", "dark-ascension");
put("DRB", "from-the-vault-dragons");

View file

@ -228,11 +228,11 @@ public enum MagidexImageSource implements CardImageSource {
supportedSets.add("E01");
supportedSets.add("HOU");
supportedSets.add("C17");
// supportedSets.add("XLN");
// supportedSets.add("DDT");
// supportedSets.add("IMA");
// supportedSets.add("E02");
// supportedSets.add("V17");
supportedSets.add("XLN");
supportedSets.add("DDT");
supportedSets.add("IMA");
supportedSets.add("E02");
supportedSets.add("V17");
// supportedSets.add("UST");
// supportedSets.add("RIX");
// supportedSets.add("A25");

View file

@ -253,11 +253,14 @@ public enum MythicspoilerComSource implements CardImageSource {
supportedSets.add("C17");
supportedSets.add("IMA");
supportedSets.add("XLN");
supportedSets.add("UST");
supportedSets.add("RIX");
sets = new LinkedHashMap<>();
setsAliases = new HashMap<>();
setsAliases.put("exp", "bfz");
setsAliases.put("xln", "ixa");
setsAliases.put("nem", "nms");
cardNameAliases = new HashMap<>();
// set+wrong name from web side => correct card name
cardNameAliases.put("MM2-otherwordlyjourney", "otherworldlyjourney");
@ -278,7 +281,8 @@ public enum MythicspoilerComSource implements CardImageSource {
cardNameAliases.put("XLN-lookoutsdecision", "lookoutsdispersal");
cardNameAliases.put("XLN-infuriatedgladiodon", "ragingswordtooth");
cardNameAliases.put("XLN-redoubledvolley", "repeatingbarrage");
cardNameAliases.put("UST-captialoffense", "capitaloffense");
cardNameAliases.put("RIX-tetzimocdeathprimordial", "tetzimocprimaldeath");
// <card name, card link>
manualLinks = new HashMap<>();
HashMap<String, String> links = new HashMap<>();
@ -294,6 +298,16 @@ public enum MythicspoilerComSource implements CardImageSource {
links.put("spitfirebastion", "spitfirebastion");
manualLinks.put("XLN", links);
HashMap<String, String> linksRix = new HashMap<>();
linksRix.put("vaultofcatlacan", "vaultofcatlacan");
linksRix.put("atzalcaveofeternity", "atzalcaveofeternity");
linksRix.put("wingedtempleoforazca", "wingedtempleoforazca");
linksRix.put("metzalitoweroftriumph", "metzalitoweroftriumph");
linksRix.put("tomboftheduskrose", "tomboftheduskrose");
linksRix.put("sanctumofthesun", "sanctumofthesun");
linksRix.put("goldforgegarrison", "goldforgegarrison");
manualLinks.put("RIX", linksRix);
cardNameAliasesStart = new HashMap<>();
HashSet<String> names = new HashSet<>();
names.add("eldrazidevastator.jpg");
@ -411,6 +425,8 @@ public enum MythicspoilerComSource implements CardImageSource {
Map<String, String> setLinks = sets.computeIfAbsent(cardSet, k -> getSetLinks(cardSet));
String searchName = card.getDownloadName().toLowerCase()
.replaceAll(" ", "")
.replaceAll("\\.", "")
.replaceAll("&", "and")
.replaceAll("-", "")
.replaceAll("'", "")
.replaceAll(",", "")

View file

@ -8,7 +8,7 @@ import java.util.Set;
import org.mage.plugins.card.images.CardDownloadData;
/**
* @author Quercitron
* @author Quercitron, JayDi85
*
*/
public enum ScryfallImageSource implements CardImageSource {
@ -200,12 +200,14 @@ public enum ScryfallImageSource implements CardImageSource {
supportedSets.add("HOU");
supportedSets.add("C17");
supportedSets.add("XLN");
// supportedSets.add("DDT");
supportedSets.add("DDT");
supportedSets.add("IMA");
// supportedSets.add("E02");
// supportedSets.add("V17");
// supportedSets.add("UST");
// supportedSets.add("RIX");
supportedSets.add("E02");
supportedSets.add("V17");
supportedSets.add("UST");
supportedSets.add("RIX");
supportedSets.add("WMCQ");
supportedSets.add("PPRO");
// supportedSets.add("A25");
// supportedSets.add("DOM");
// supportedSets.add("M19");
@ -214,10 +216,24 @@ public enum ScryfallImageSource implements CardImageSource {
@Override
public String generateURL(CardDownloadData card) throws Exception {
// special card number like "103a" already compatible
if (card.isCollectorIdWithStr()) {
return "https://img.scryfall.com/cards/large/en/" + formatSetName(card.getSet()) + "/"
+ card.getCollectorId() + ".jpg";
}
// double faced cards do not supporte by API (need direct link for img)
// example: https://img.scryfall.com/cards/large/en/xln/173b.jpg
if (card.isTwoFacedCard()) {
return "https://img.scryfall.com/cards/large/en/" + formatSetName(card.getSet()) + "/"
+ card.getCollectorId() + (card.isSecondSide() ? "b" : "a") + ".jpg";
}
// basic cards by api call (redirect to img link)
// example: https://api.scryfall.com/cards/xln/121?format=image
return "https://api.scryfall.com/cards/" + formatSetName(card.getSet()) + "/"
+ card.getCollectorId()
+ (card.isSecondSide() ? "b" : "")
+ "?format=image";
+ card.getCollectorId() + "?format=image";
}
@Override
@ -275,6 +291,7 @@ public enum ScryfallImageSource implements CardImageSource {
put("DD3EVG", "evg");
put("MPS-AKH", "mp2");
put("MBP", "pmei");
put("WMCQ", "pwcq");
}
};

View file

@ -0,0 +1,171 @@
package org.mage.plugins.card.dl.sources;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.mage.plugins.card.dl.DownloadJob;
import static org.mage.card.arcane.ManaSymbols.getSymbolFileNameAsSVG;
import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
// TODO: add force to download symbols (rewrite exist files)
/**
*
* @author jaydi85@gmail.com
*
*/
public class ScryfallSymbolsSource implements Iterable<DownloadJob> {
static final String SOURCE_URL = "https://assets.scryfall.com/assets/scryfall.css"; // search css-file on https://scryfall.com/docs/api/colors
static final String STATE_PROP_NAME = "state";
static final String DOWNLOAD_TEMP_FILE = getImagesDir() + File.separator + "temp" + File.separator + "scryfall-symbols-source.txt";
// card-symbol-(.{1,10}){background-image.+base64,(.+)("\)})
// see https://regex101.com/
static final String REGEXP_MANA_PATTERN = "card-symbol-(.{1,10})\\{background-image.+base64,(.+)(\"\\)\\})";
protected static final org.apache.log4j.Logger LOGGER = org.apache.log4j.Logger.getLogger(ScryfallSymbolsSource.class);
private static final int SYMBOLS_NUMBER_START = 0;
private static final int SYMBOLS_NUMBER_END = 20;
// copy-past symbols list from gatherer download
private static final String[] SYMBOLS_LIST = {"W", "U", "B", "R", "G",
"W/U", "U/B", "B/R", "R/G", "G/W", "W/B", "U/R", "B/G", "R/W", "G/U",
"2/W", "2/U", "2/B", "2/R", "2/G",
"WP", "UP", "BP", "RP", "GP",
"X", "S", "T", "Q", "C", "E"};
@Override
public Iterator<DownloadJob> iterator() {
ArrayList<DownloadJob> jobs = new ArrayList<>();
// all symbols on one page
jobs.add(generateDownloadJob());
return jobs.iterator();
}
private void parseData(String sourcePath){
String sourceData = "";
try {
sourceData = new String(Files.readAllBytes(Paths.get(sourcePath)));
}catch (IOException e) {
LOGGER.error("Can't open file to parse data: " + sourcePath + " , reason: " + e.getMessage());
}
// gen symbols list
ArrayList<String> allMageSymbols = new ArrayList<>();
for(int i = 0; i < SYMBOLS_LIST.length; i++){
allMageSymbols.add(SYMBOLS_LIST[i]);
}
for(Integer i = SYMBOLS_NUMBER_START; i <= SYMBOLS_NUMBER_END; i++){
allMageSymbols.add(String.valueOf(SYMBOLS_NUMBER_START + i));
}
Map<String, String> foundedData = new HashMap<>();
// search raw data
sourceData = sourceData.replaceAll(".card-symbol", "\n.card-symbol"); // css as one line, but need multiline
Pattern regex = Pattern.compile(REGEXP_MANA_PATTERN);
Matcher regexMatcher = regex.matcher(sourceData);
while (regexMatcher.find()) {
String symbolCode = regexMatcher.group(1).trim();
String symbolData = regexMatcher.group(2).trim().replace(" ", "").replaceAll("\n", ""); // decoder need only wrapped text as one line
foundedData.put(symbolCode, symbolData);
}
// dirs maker
File dir = getSymbolFileNameAsSVG("W").getParentFile();
if(!dir.exists()){
dir.mkdirs();
}
// decode and save data (only if not exist)
for(String needCode: allMageSymbols){
String searchCode = needCode.replace("/", "");
if(!foundedData.containsKey(searchCode))
{
LOGGER.warn("Can't found symbol code from scryfall: " + searchCode);
continue;
}
File destFile = getSymbolFileNameAsSVG(searchCode);
if (destFile.exists() && (destFile.length() > 0)){
continue;
}
try {
// base64 transform
String data64 = foundedData.get(searchCode);
Base64.Decoder dec = Base64.getDecoder();
byte[] fileData = dec.decode(data64);
FileOutputStream stream = new FileOutputStream(destFile);
stream.write(fileData);
stream.close();
LOGGER.info("New svg symbol downloaded: " + needCode);
} catch (Exception e) {
LOGGER.error("Can't decode svg icon and save to file: " + destFile.getPath() + ", reason: " + e.getMessage());
}
}
}
private class ScryfallSymbolsDownloadJob extends DownloadJob{
// listener for data parse after download complete
private class ScryDownloadOnFinishedListener implements PropertyChangeListener {
private String downloadedFile;
public ScryDownloadOnFinishedListener(String ADestFile){
this.downloadedFile = ADestFile;
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (!evt.getPropertyName().equals(STATE_PROP_NAME)){
throw new IllegalArgumentException("Unknown download property " + evt.getPropertyName());
}
if (evt.getNewValue() != State.FINISHED){
return;
}
// parse data and save to dest
parseData(this.downloadedFile);
}
}
private String destFile = "";
public ScryfallSymbolsDownloadJob() {
super("Scryfall symbols source", fromURL(SOURCE_URL), toFile(DOWNLOAD_TEMP_FILE));
this.destFile = DOWNLOAD_TEMP_FILE;
this.addPropertyChangeListener(STATE_PROP_NAME, new ScryDownloadOnFinishedListener(this.destFile));
// clear dest file (always download new data)
File file = new File(this.destFile);
if (file.exists()){
file.delete();
}
}
}
private DownloadJob generateDownloadJob() {
return new ScryfallSymbolsDownloadJob();
}
}

View file

@ -45,6 +45,10 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.prefs.Preferences;
import mage.cards.Sets;
import mage.cards.repository.CardCriteria;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
import mage.client.MageFrame;
import mage.client.dialog.PreferencesDialog;
import mage.remote.Connection;
@ -258,11 +262,11 @@ public enum WizardCardsImageSource implements CardImageSource {
supportedSets.add("HOU");
supportedSets.add("C17");
supportedSets.add("XLN");
// supportedSets.add("DDT"); // Duel Decks: Merfolk vs. Goblins
// supportedSets.add("IMA"); // Iconic Msters
// supportedSets.add("E02"); // Explorers of Ixalan
// supportedSets.add("V17"); // From the Vault: Transform
// supportedSets.add("UST"); // Unstable
supportedSets.add("DDT"); // Duel Decks: Merfolk vs. Goblins
supportedSets.add("IMA"); // Iconic Msters
supportedSets.add("E02"); // Explorers of Ixalan
supportedSets.add("V17"); // From the Vault: Transform
supportedSets.add("UST"); // Unstable
// supportedSets.add("RIX"); // Rivals of Ixalan
// supportedSets.add("A25"); // Masters 25
// supportedSets.add("DOM"); // Dominaria
@ -332,6 +336,7 @@ public enum WizardCardsImageSource implements CardImageSource {
setsAliases.put("DDQ", "Duel Decks: Blessed vs. Cursed");
setsAliases.put("DDR", "Duel Decks: Nissa vs. Ob Nixilis");
setsAliases.put("DDS", "Duel Decks: Mind vs. Might");
setsAliases.put("DDT", "Duel Decks: Merfolk vs. Goblins");
setsAliases.put("DGM", "Dragon's Maze");
setsAliases.put("DIS", "Dissension");
setsAliases.put("DKA", "Dark Ascension");
@ -359,6 +364,7 @@ public enum WizardCardsImageSource implements CardImageSource {
setsAliases.put("HOP", "Planechase");
setsAliases.put("HOU", "Hour of Devastation");
setsAliases.put("ICE", "Ice Age");
setsAliases.put("IMA", "Iconic Masters");
setsAliases.put("INV", "Invasion");
setsAliases.put("ISD", "Innistrad");
setsAliases.put("JOU", "Journey into Nyx");
@ -472,11 +478,65 @@ public enum WizardCardsImageSource implements CardImageSource {
return null;
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
String collectorId = card.getCollectorId();
String cardSet = card.getSet();
if (collectorId == null || cardSet == null) {
throw new Exception("Wrong parameters for image: collector id: " + collectorId + ",card set: " + cardSet);
}
if (card.isFlippedSide()) { //doesn't support rotated images
return null;
}
Map<String, String> setLinks = sets.computeIfAbsent(cardSet, k -> getSetLinks(cardSet));
if (setLinks == null || setLinks.isEmpty()) {
return null;
}
String searchKey = card.getDownloadName().toLowerCase().replace(" ", "").replace("&", "//");
String link = setLinks.get(searchKey);
if (link == null) {
int length = collectorId.length();
// Try to find card image with added letter (e.g. from Unstable)
if (Character.isLetter(collectorId.charAt(length - 1))) {
String key = searchKey + collectorId.charAt(length - 1);
link = setLinks.get(key);
}
// Try to find image with added card number (e.g. basic lands)
if (link == null) {
String key = searchKey + collectorId;
link = setLinks.get(key);
if (link == null) {
int number = Integer.parseInt(collectorId.substring(0, length));
if (number > 0) {
List<String> l = new ArrayList<>(setLinks.values());
if (l.size() >= number) {
link = l.get(number - 1);
} else {;
link = l.get(number - 21);
if (link != null) {
link = link.replace(Integer.toString(number - 20), (Integer.toString(number - 20) + 'a'));
}
}
}
}
}
}
if (link != null && !link.startsWith("http://")) {
link = "http://gatherer.wizards.com" + link;
}
return link;
}
private Map<String, String> getSetLinks(String cardSet) {
LinkedHashMap<String, String> setLinks = new LinkedHashMap<>();
ExecutorService executor = Executors.newFixedThreadPool(10);
try {
String setNames = setsAliases.get(cardSet);
if (setNames == null) {
setNames = Sets.getInstance().get(cardSet).getName();
}
String preferedLanguage = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PREF_LANGUAGE, "en");
for (String setName : setNames.split("\\^")) {
// String URLSetName = URLEncoder.encode(setName, "UTF-8");
@ -502,8 +562,22 @@ public enum WizardCardsImageSource implements CardImageSource {
}
String cardName = normalizeName(cardsImages.get(i).attr("alt"));
if (cardName != null && !cardName.isEmpty()) {
Runnable task = new GetImageLinkTask(multiverseId, cardName, preferedLanguage, setLinks);
executor.execute(task);
if (cardName.equals("Forest") || cardName.equals("Swamp") || cardName.equals("Mountain") || cardName.equals("Island")
|| cardName.equals("Plains") || cardName.equals("Wastes")) {
getLandVariations(setLinks, cardSet, multiverseId, cardName);
} else {
String numberChar = "";
int pos1 = cardName.indexOf("(");
if (pos1 > 0) {
int pos2 = cardName.indexOf("(", pos1 + 1);
if (pos2 > 0) {
numberChar = cardName.substring(pos2 + 1, pos2 + 2);
cardName = cardName.substring(0, pos1);
}
}
Integer preferedMultiverseId = getLocalizedMultiverseId(preferedLanguage, multiverseId);
setLinks.put(cardName.toLowerCase() + numberChar, generateLink(preferedMultiverseId));
}
}
}
page++;
@ -552,23 +626,38 @@ public enum WizardCardsImageSource implements CardImageSource {
return doc;
}
private Map<String, String> getLandVariations(int multiverseId, String cardName) throws IOException, NumberFormatException {
private void getLandVariations(LinkedHashMap<String, String> setLinks, String cardSet, int multiverseId, String cardName) throws IOException, NumberFormatException {
CardCriteria criteria = new CardCriteria();
criteria.nameExact(cardName);
criteria.setCodes(cardSet);
List<CardInfo> cards = CardRepository.instance.findCards(criteria);
String urlLandDocument = "http://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=" + multiverseId;
Document landDoc = getDocument(urlLandDocument);
Elements variations = landDoc.select("a.variationlink");
Map<String, String> links = new HashMap<>();
if (!variations.isEmpty()) {
int landNumber = 1;
if (variations.size() > cards.size()) {
logger.warn("More links for lands than cards in DB found for set: " + cardSet + " Name: " + cardName);
}
if (variations.size() < cards.size()) {
logger.warn("Less links for lands than cards in DB found for set: " + cardSet + " Name: " + cardName);
}
int iteration = 0;
for (Element variation : variations) {
String colNumb = String.valueOf(iteration);
if (cards.size() > iteration) {
CardInfo cardInfo = cards.get(iteration);
if (cardInfo != null) {
colNumb = cardInfo.getCardNumber();
}
}
Integer landMultiverseId = Integer.parseInt(variation.attr("href").replaceAll("[^\\d]", ""));
links.put((cardName + landNumber).toLowerCase(), generateLink(landMultiverseId));
landNumber++;
setLinks.put((cardName).toLowerCase() + colNumb, generateLink(landMultiverseId));
iteration++;
}
} else {
links.put(cardName.toLowerCase(), generateLink(multiverseId));
setLinks.put(cardName.toLowerCase(), generateLink(multiverseId));
}
return links;
}
private static String generateLink(int landMultiverseId) {
@ -623,50 +712,8 @@ public enum WizardCardsImageSource implements CardImageSource {
.replace("\u00DB", "U").replace("\u00FB", "u")
.replace("\u00DC", "U").replace("\u00FC", "u")
.replace("\u00E9", "e").replace("&", "//")
.replace(" ", "")
.replace("Hintreland Scourge", "Hinterland Scourge");
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
String collectorId = card.getCollectorId();
String cardSet = card.getSet();
if (collectorId == null || cardSet == null) {
throw new Exception("Wrong parameters for image: collector id: " + collectorId + ",card set: " + cardSet);
}
if (card.isFlippedSide()) { //doesn't support rotated images
return null;
}
String setNames = setsAliases.get(cardSet);
if (setNames != null) {
Map<String, String> setLinks = sets.computeIfAbsent(cardSet, k -> getSetLinks(cardSet));
if (setLinks == null || setLinks.isEmpty()) {
return null;
}
String link = setLinks.get(card.getDownloadName().toLowerCase());
if (link == null) {
int length = collectorId.length();
if (Character.isLetter(collectorId.charAt(length - 1))) {
length -= 1;
}
int number = Integer.parseInt(collectorId.substring(0, length));
List<String> l = new ArrayList<>(setLinks.values());
if (l.size() >= number) {
link = l.get(number - 1);
} else {;
link = l.get(number - 21);
if (link != null) {
link = link.replace(Integer.toString(number - 20), (Integer.toString(number - 20) + 'a'));
}
}
}
if (link != null && !link.startsWith("http://")) {
link = "http://gatherer.wizards.com" + link;
}
return link;
}
return null;
}
@ -680,44 +727,43 @@ public enum WizardCardsImageSource implements CardImageSource {
return 60.0f;
}
private final class GetImageLinkTask implements Runnable {
private int multiverseId;
private String cardName;
private String preferedLanguage;
private LinkedHashMap setLinks;
public GetImageLinkTask(int multiverseId, String cardName, String preferedLanguage, LinkedHashMap setLinks) {
try {
this.multiverseId = multiverseId;
this.cardName = cardName;
this.preferedLanguage = preferedLanguage;
this.setLinks = setLinks;
} catch (Exception ex) {
logger.error(ex.getMessage());
logger.error("multiverseId: " + multiverseId);
logger.error("cardName: " + cardName);
logger.error("preferedLanguage: " + preferedLanguage);
logger.error("setLinks: " + setLinks.toString());
}
}
@Override
public void run() {
try {
if (cardName.equals("Forest") || cardName.equals("Swamp") || cardName.equals("Mountain") || cardName.equals("Island") || cardName.equals("Plains")) {
setLinks.putAll(getLandVariations(multiverseId, cardName));
} else {
Integer preferedMultiverseId = getLocalizedMultiverseId(preferedLanguage, multiverseId);
setLinks.put(cardName.toLowerCase(), generateLink(preferedMultiverseId));
}
} catch (IOException | NumberFormatException ex) {
logger.error("Exception when parsing the wizards page: " + ex.getMessage());
}
}
}
// private final class GetImageLinkTask implements Runnable {
//
// private int multiverseId;
// private String cardName;
// private String preferedLanguage;
// private LinkedHashMap setLinks;
//
// public GetImageLinkTask(int multiverseId, String cardName, String preferedLanguage, LinkedHashMap setLinks) {
// try {
// this.multiverseId = multiverseId;
// this.cardName = cardName;
// this.preferedLanguage = preferedLanguage;
// this.setLinks = setLinks;
// } catch (Exception ex) {
// logger.error(ex.getMessage());
// logger.error("multiverseId: " + multiverseId);
// logger.error("cardName: " + cardName);
// logger.error("preferedLanguage: " + preferedLanguage);
// logger.error("setLinks: " + setLinks.toString());
// }
// }
//
// @Override
// public void run() {
// try {
// if (cardName.equals("Forest") || cardName.equals("Swamp") || cardName.equals("Mountain") || cardName.equals("Island") || cardName.equals("Plains")) {
// setLinks.putAll(getLandVariations(multiverseId, cardName));
// } else {
// Integer preferedMultiverseId = getLocalizedMultiverseId(preferedLanguage, multiverseId);
// setLinks.put(cardName.toLowerCase(), generateLink(preferedMultiverseId));
// }
// } catch (IOException | NumberFormatException ex) {
// logger.error("Exception when parsing the wizards page: " + ex.getMessage());
// }
// }
//
// }
@Override
public int getTotalImages() {
return -1;

View file

@ -1,5 +1,7 @@
package org.mage.plugins.card.images;
import mage.util.CardUtil;
import java.util.Objects;
/**
@ -128,6 +130,15 @@ public class CardDownloadData {
return collectorId;
}
public Integer getCollectorIdAsInt() {
return CardUtil.parseCardNumberAsInt(collectorId);
}
public boolean isCollectorIdWithStr(){
// card have special numbers like "103a", "180b" (scryfall style)
return !getCollectorId().equals(getCollectorIdAsInt().toString());
}
public String getName() {
return name;
}

View file

@ -27,13 +27,9 @@ import mage.cards.repository.CardCriteria;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
import mage.client.MageFrame;
import mage.client.constants.Constants;
import mage.client.dialog.PreferencesDialog;
import mage.client.util.sets.ConstructedFormats;
import mage.remote.Connection;
import static mage.remote.Connection.ProxyType.HTTP;
import static mage.remote.Connection.ProxyType.NONE;
import static mage.remote.Connection.ProxyType.SOCKS;
import net.java.truevfs.access.TFile;
import net.java.truevfs.access.TFileOutputStream;
import net.java.truevfs.access.TVFS;
@ -43,8 +39,12 @@ import org.mage.plugins.card.dl.sources.*;
import org.mage.plugins.card.properties.SettingsManager;
import org.mage.plugins.card.utils.CardImageUtils;
import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
public class DownloadPictures extends DefaultBoundedRangeModel implements Runnable {
// don't forget to remove new sets from ignore.urls to download (propeties file in resources)
private static DownloadPictures instance;
private static final Logger logger = Logger.getLogger(DownloadPictures.class);
@ -352,6 +352,8 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
if (cardImageSource.isTokenSource() && cardImageSource.isImageProvided(data.getSet(), data.getName())) {
numberTokenImagesAvailable++;
cardsToDownload.add(data);
}else{
//logger.warn("Source do not support token (set " + data.getSet() + ", token " + data.getName() + ")");
}
} else {
if (selectedSetCodes != null && selectedSetCodes.contains(data.getSet())) {
@ -430,7 +432,12 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
throw new IllegalStateException("Second side card can't have empty name.");
}
url = new CardDownloadData(card.getSecondSideName(), card.getSetCode(), card.getCardNumber(), card.usesVariousArt(), 0, "", "", false, card.isDoubleFaced(), true);
CardInfo secondSideCard = CardRepository.instance.findCard(card.getSecondSideName());
if (secondSideCard == null){
throw new IllegalStateException("Can''t find second side card in database: " + card.getSecondSideName());
}
url = new CardDownloadData(card.getSecondSideName(), card.getSetCode(), secondSideCard.getCardNumber(), card.usesVariousArt(), 0, "", "", false, card.isDoubleFaced(), true);
url.setType2(isType2);
allCardsUrls.add(url);
}
@ -462,7 +469,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
*/
List<CardDownloadData> cardsToDownload = Collections.synchronizedList(new ArrayList<>());
allCardsUrls.parallelStream().forEach(card -> {
TFile file = new TFile(CardImageUtils.generateImagePath(card));
File file = new TFile(CardImageUtils.buildImagePathToCard(card));
logger.debug(card.getName() + " (is_token=" + card.isToken() + "). Image is here:" + file.getAbsolutePath() + " (exists=" + file.exists() + ')');
if (!file.exists()) {
logger.debug("Missing: " + file.getAbsolutePath());
@ -544,7 +551,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
public void run() {
this.cardIndex = 0;
File base = new File(Constants.IO.imageBaseDir);
File base = new File(getImagesDir());
if (!base.exists()) {
base.mkdir();
}
@ -678,38 +685,78 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
@Override
public void run() {
StringBuilder filePath = new StringBuilder();
File temporaryFile = null;
TFile outputFile = null;
if (cancel) {
synchronized (sync) {
update(cardIndex + 1, count);
}
return;
}
TFile fileTempImage;
TFile destFile;
try {
filePath.append(Constants.IO.imageBaseDir);
if (!useSpecifiedPaths && card != null) {
filePath.append(card.hashCode()).append('.').append(card.getName().replace(":", "").replace("//", "-")).append(".jpg");
temporaryFile = new File(filePath.toString());
}
String imagePath;
if (useSpecifiedPaths) {
if (card != null && card.isToken()) {
imagePath = CardImageUtils.getTokenBasePath() + actualFilename;
} else if (card != null) {
imagePath = CardImageUtils.getImageBasePath() + actualFilename;
} else {
imagePath = Constants.IO.imageBaseDir;
}
String tmpFile = filePath + "temporary" + actualFilename;
temporaryFile = new File(tmpFile);
if (!temporaryFile.exists()) {
temporaryFile.getParentFile().mkdirs();
if (card == null){
synchronized (sync) {
update(cardIndex + 1, count);
}
} else {
imagePath = CardImageUtils.generateImagePath(card);
return;
}
outputFile = new TFile(imagePath);
if (!outputFile.exists()) {
outputFile.getParentFile().mkdirs();
// gen temp file (download to images folder)
String tempPath = getImagesDir() + File.separator + "downloading" + File.separator;
if(useSpecifiedPaths){
fileTempImage = new TFile(tempPath + actualFilename + "-" + card.hashCode() + ".jpg");
}else{
fileTempImage = new TFile(tempPath + CardImageUtils.prepareCardNameForFile(card.getName()) + "-" + card.hashCode() + ".jpg");
}
if(!fileTempImage.getParentFile().exists()){
fileTempImage.getParentFile().mkdirs();
}
// gen dest file name
if(useSpecifiedPaths)
{
if(card.isToken()){
destFile = new TFile(CardImageUtils.buildImagePathToSet(card) + actualFilename + ".jpg");
}else{
destFile = new TFile(CardImageUtils.buildImagePathToTokens() + actualFilename + ".jpg");
}
}else{
destFile = new TFile(CardImageUtils.buildImagePathToCard(card));
}
// FILE already exists (in zip or in dir)
if (destFile.exists()){
synchronized (sync) {
update(cardIndex + 1, count);
}
return;
}
// zip can't be read
TFile testArchive = destFile.getTopLevelArchive();
if (testArchive != null && testArchive.exists()) {
try {
testArchive.list();
} catch (Exception e) {
logger.error("Error reading archive, may be it was corrapted. Try to delete it: " + testArchive.toString());
synchronized (sync) {
update(cardIndex + 1, count);
}
return;
}
}
/*
if(!destFile.getParentFile().exists()){
destFile.getParentFile().mkdirs();
}
*/
/*
// WTF start?! TODO: wtf
File existingFile = new File(imagePath.replaceFirst("\\w{3}.zip", ""));
if (existingFile.exists()) {
try {
@ -727,7 +774,87 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
}
return;
}
// WTF end?!
*/
// START to download
cardImageSource.doPause(url.getPath());
URLConnection httpConn = url.openConnection(p);
httpConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2");
httpConn.connect();
int responseCode = ((HttpURLConnection) httpConn).getResponseCode();
if (responseCode == 200){
// download OK
// save data to temp
BufferedOutputStream out;
try (BufferedInputStream in = new BufferedInputStream(httpConn.getInputStream())) {
out = new BufferedOutputStream(new TFileOutputStream(fileTempImage));
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) != -1) {
// user cancelled
if (cancel) {
in.close();
out.flush();
out.close();
// stop download, save current state and exit
TFile archive = destFile.getTopLevelArchive();
///* not need to unmout/close - it's auto action
if (archive != null && archive.exists()){
logger.info("User canceled download. Closing archive file: " + destFile.toString());
try {
TVFS.umount(archive);
}catch (Exception e) {
logger.error("Can't close archive file: " + e.getMessage(), e);
}
}//*/
try {
TFile.rm(fileTempImage);
}catch (Exception e) {
logger.error("Can't delete temp file: " + e.getMessage(), e);
}
return;
}
out.write(buf, 0, len);
}
}
// TODO: remove to finnaly section?
out.flush();
out.close();
// TODO: add two faces card correction? (WTF)
// SAVE final data
if (fileTempImage.exists()) {
if (!destFile.getParentFile().exists()){
destFile.getParentFile().mkdirs();
}
new TFile(fileTempImage).cp_rp(destFile);
try {
TFile.rm(fileTempImage);
}catch (Exception e) {
logger.error("Can't delete temp file: " + e.getMessage(), e);
}
}
}else{
// download ERROR
logger.warn("Image download for " + card.getName()
+ (!card.getDownloadName().equals(card.getName()) ? " downloadname: " + card.getDownloadName() : "")
+ " (" + card.getSet() + ") failed - responseCode: " + responseCode + " url: " + url.toString()
);
if (logger.isDebugEnabled()) {
// Shows the returned html from the request to the web server
logger.debug("Returned HTML ERROR:\n" + convertStreamToString(((HttpURLConnection) httpConn).getErrorStream()));
}
}
/*
// Logger.getLogger(this.getClass()).info(url.toString());
boolean useTempFile = false;
int responseCode = 0;
@ -736,7 +863,6 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
if (temporaryFile != null && temporaryFile.length() > 100) {
useTempFile = true;
} else {
cardImageSource.doPause(url.getPath());
httpConn = url.openConnection(p);
httpConn.connect();
@ -768,6 +894,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
out.close();
}
// TODO: WTF?! start
if (card != null && card.isTwoFacedCard()) {
BufferedImage image = ImageIO.read(temporaryFile);
if (image.getHeight() == 470) {
@ -790,6 +917,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
outputFile.getParentFile().mkdirs();
new TFile(temporaryFile).cp_rp(outputFile);
}
// WTF?! end
} else {
if (card != null && !useSpecifiedPaths) {
logger.warn("Image download for " + card.getName()
@ -800,16 +928,15 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
logger.debug("Returned HTML ERROR:\n" + convertStreamToString(((HttpURLConnection) httpConn).getErrorStream()));
}
}
*/
} catch (AccessDeniedException e) {
logger.error("The file " + (outputFile != null ? outputFile.toString() : "to add the image of " + card.getName() + '(' + card.getSet() + ')') + " can't be accessed. Try rebooting your system to remove the file lock.");
logger.error("Can't access to files: " + card.getName() + "(" + card.getSet() + "). Try rebooting your system to remove the file lock.");
} catch (Exception e) {
logger.error(e, e);
logger.error(e.getMessage(), e);
} finally {
if (temporaryFile != null) {
temporaryFile.delete();
}
}
synchronized (sync) {
update(cardIndex + 1, count);
}
@ -823,7 +950,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(0.96f);
File tempFile = new File(Constants.IO.imageBaseDir + File.separator + image.hashCode() + file.getName());
File tempFile = new File(getImagesDir() + File.separator + image.hashCode() + file.getName());
FileImageOutputStream output = new FileImageOutputStream(tempFile);
writer.setOutput(output);
IIOImage image2 = new IIOImage(image, null, null);
@ -846,7 +973,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
} else {
List<CardDownloadData> remainingCards = Collections.synchronizedList(new ArrayList<>());
DownloadPictures.this.allCardsMissingImage.parallelStream().forEach(cardDownloadData -> {
TFile file = new TFile(CardImageUtils.generateImagePath(cardDownloadData));
TFile file = new TFile(CardImageUtils.buildImagePathToCard(cardDownloadData));
if (!file.exists()) {
remainingCards.add(cardDownloadData);
}

View file

@ -3,7 +3,9 @@ package org.mage.plugins.card.images;
import com.google.common.base.Function;
import com.google.common.collect.ComputationException;
import com.google.common.collect.MapMaker;
import java.awt.Graphics2D;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
@ -18,9 +20,9 @@ import net.java.truevfs.access.TFile;
import net.java.truevfs.access.TFileInputStream;
import net.java.truevfs.access.TFileOutputStream;
import org.apache.log4j.Logger;
import org.mage.plugins.card.constants.Constants;
import org.mage.plugins.card.dl.sources.DirectLinksForDownload;
import org.mage.plugins.card.utils.CardImageUtils;
import mage.client.constants.Constants;
/**
* This class stores ALL card images in a cache with soft values. this means
@ -44,6 +46,7 @@ public final class ImageCache {
private static final Logger LOGGER = Logger.getLogger(ImageCache.class);
private static final Map<String, BufferedImage> IMAGE_CACHE;
private static final Map<String, BufferedImage> FACE_IMAGE_CACHE;
/**
* Common pattern for keys. Format: "<cardname>#<setname>#<collectorID>"
@ -81,15 +84,17 @@ public final class ImageCache {
CardDownloadData info = new CardDownloadData(name, set, collectorId, usesVariousArt, type, tokenSetCode, tokenDescriptor);
boolean cardback = false;
String path;
if (collectorId.isEmpty() || "0".equals(collectorId)) {
info.setToken(true);
path = CardImageUtils.generateTokenImagePath(info);
if (path == null) {
path = DirectLinksForDownload.outDir + File.separator + DirectLinksForDownload.cardbackFilename;
cardback = true;
path = DirectLinksForDownload.outDir + File.separator + DirectLinksForDownload.cardbackFilename; // TODO: replace empty token by other default card, not cardback
}
} else {
path = CardImageUtils.generateImagePath(info);
path = CardImageUtils.buildImagePathToCard(info);
}
if (path == null) {
@ -101,6 +106,7 @@ public final class ImageCache {
}
if (thumbnail && path.endsWith(".jpg")) {
// need thumbnail image
String thumbnailPath = buildThumbnailPath(path);
TFile thumbnailFile = null;
try {
@ -123,14 +129,29 @@ public final class ImageCache {
+ ", thumbnail file is probably broken, attempting to recreate it...");
thumbnailImage = makeThumbnailByFile(key, file, thumbnailPath);
}
if (cardback){
// unknown tokens on opponent desk
thumbnailImage = getRoundCorner(thumbnailImage);
}
return thumbnailImage;
} else {
return makeThumbnailByFile(key, file, thumbnailPath);
}
} else {
BufferedImage image = loadImage(file);
image = getWizardsCard(image);
return image;
if (cardback){
// need cardback image
BufferedImage image = loadImage(file);
image = getRoundCorner(image);
return image;
}else {
// need normal card image
BufferedImage image = loadImage(file);
image = getWizardsCard(image);
image = getRoundCorner(image);
return image;
}
}
} else {
throw new RuntimeException(
@ -145,6 +166,56 @@ public final class ImageCache {
}
}
public BufferedImage makeThumbnailByFile(String key, TFile file, String thumbnailPath) {
BufferedImage image = loadImage(file);
image = getWizardsCard(image);
image = getRoundCorner(image);
if (image == null) {
return null;
}
LOGGER.debug("creating thumbnail for " + key);
return makeThumbnail(image, thumbnailPath);
}
});
FACE_IMAGE_CACHE = new MapMaker().softValues().makeComputingMap(new Function<String, BufferedImage>() {
@Override
public BufferedImage apply(String key) {
try {
Matcher m = KEY_PATTERN.matcher(key);
if (m.matches()) {
String name = m.group(1);
String set = m.group(2);
//Integer artid = Integer.parseInt(m.group(2));
String path;
path = CardImageUtils.generateFaceImagePath(name, set);
if (path == null) {
return null;
}
TFile file = getTFile(path);
if (file == null) {
return null;
}
BufferedImage image = loadImage(file);
return image;
} else {
throw new RuntimeException(
"Requested face image doesn't fit the requirement for key (<cardname>#<artid>#: " + key);
}
} catch (Exception ex) {
if (ex instanceof ComputationException) {
throw (ComputationException) ex;
} else {
throw new ComputationException(ex);
}
}
}
public BufferedImage makeThumbnailByFile(String key, TFile file, String thumbnailPath) {
BufferedImage image = loadImage(file);
image = getWizardsCard(image);
@ -189,10 +260,10 @@ public final class ImageCache {
info.setToken(true);
path = CardImageUtils.generateFullTokenImagePath(info);
if (path == null) {
path = DirectLinksForDownload.outDir + File.separator + DirectLinksForDownload.cardbackFilename;
path = DirectLinksForDownload.outDir + File.separator + DirectLinksForDownload.cardbackFilename; // TODO: replace empty token by other default card, not cardback
}
} else {
path = CardImageUtils.generateImagePath(info);
path = CardImageUtils.buildImagePathToCard(info);
}
if (thumbnail && path.endsWith(".jpg")) {
@ -207,6 +278,12 @@ public final class ImageCache {
private ImageCache() {
}
public static BufferedImage getCardbackImage() {
BufferedImage image = ImageCache.loadImage(new TFile(DirectLinksForDownload.outDir + File.separator + DirectLinksForDownload.cardbackFilename));
image = getRoundCorner(image);
return image;
}
public static BufferedImage getMorphImage() {
CardDownloadData info = new CardDownloadData("Morph", "KTK", "0", false, 0, "KTK", "");
info.setToken(true);
@ -215,7 +292,10 @@ public final class ImageCache {
return null;
}
TFile file = getTFile(path);
return loadImage(file);
BufferedImage image = loadImage(file);
image = getRoundCorner(image);
return image;
}
public static BufferedImage getManifestImage() {
@ -226,7 +306,10 @@ public final class ImageCache {
return null;
}
TFile file = getTFile(path);
return loadImage(file);
BufferedImage image = loadImage(file);
image = getRoundCorner(image);
return image;
}
private static String buildThumbnailPath(String path) {
@ -239,6 +322,32 @@ public final class ImageCache {
return thumbnailPath;
}
public static BufferedImage getRoundCorner(BufferedImage image){
if (image != null) {
BufferedImage cornerImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
// corner
float ROUNDED_CORNER_SIZE = 0.11f; // see CardPanelComponentImpl
int cornerSizeBorder = Math.max(4, Math.round(image.getWidth() * ROUNDED_CORNER_SIZE));
// corner mask
Graphics2D gg = cornerImage.createGraphics();
gg.setComposite(AlphaComposite.Src);
gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
gg.setColor(Color.white);
gg.fill(new RoundRectangle2D.Float(0, 0, cornerImage.getWidth(), cornerImage.getHeight(), cornerSizeBorder, cornerSizeBorder));
// image draw to buffer
gg.setComposite(AlphaComposite.SrcAtop);
gg.drawImage(image, 0, 0, null);
gg.dispose();
return cornerImage;
} else {
return image;
}
}
public static BufferedImage getWizardsCard(BufferedImage image) {
if (image != null && image.getWidth() == 265 && image.getHeight() == 370) {
BufferedImage crop = new BufferedImage(256, 360, BufferedImage.TYPE_INT_RGB);
@ -251,6 +360,23 @@ public final class ImageCache {
}
}
public static boolean isFaceImagePresent(CardView card) {
String path;
path = CardImageUtils.generateFaceImagePath(card.getName(), card.getExpansionSetCode());
if (path == null) {
return false;
}
TFile file = getTFile(path);
if (file == null) {
return false;
}
if (file.exists()) {
return true;
}
return false;
}
public static BufferedImage getThumbnail(CardView card) {
return getImage(getKey(card, card.getName(), "#thumb"));
}
@ -263,6 +389,10 @@ public final class ImageCache {
return getImage(getKey(card, card.getName(), ""));
}
public static BufferedImage getImageFaceOriginal(CardView card) {
return getFaceImage(getFaceKey(card, card.getName(), card.getExpansionSetCode()));
}
public static BufferedImage getImageOriginalAlternateName(CardView card) {
return getImage(getKey(card, card.getAlternateName(), ""));
}
@ -288,6 +418,27 @@ public final class ImageCache {
}
}
/**
* Returns the Image corresponding to the key
*/
private static BufferedImage getFaceImage(String key) {
try {
return FACE_IMAGE_CACHE.get(key);
} catch (NullPointerException ex) {
// unfortunately NullOutputException, thrown when apply() returns
// null, is not public
// NullOutputException is a subclass of NullPointerException
// legitimate, happens when a card has no image
return null;
} catch (ComputationException ex) {
if (ex.getCause() instanceof NullPointerException) {
return null;
}
LOGGER.error(ex, ex);
return null;
}
}
/**
* Returns the Image corresponding to the key only if it already exists in
* the cache.
@ -296,6 +447,14 @@ public final class ImageCache {
return IMAGE_CACHE.containsKey(key) ? IMAGE_CACHE.get(key) : null;
}
/**
* Returns the Image corresponding to the key only if it already exists in
* the cache.
*/
private static BufferedImage tryGetFaceImage(String key) {
return FACE_IMAGE_CACHE.containsKey(key) ? FACE_IMAGE_CACHE.get(key) : null;
}
/**
* Returns the map key for a card, without any suffixes for the image size.
*/
@ -307,6 +466,13 @@ public final class ImageCache {
+ (card.getTokenDescriptor() != null ? '#' + card.getTokenDescriptor() : "#");
}
/**
* Returns the map key for a card, without any suffixes for the image size.
*/
private static String getFaceKey(CardView card, String name, String set) {
return name + '#' + set + "####";
}
// /**
// * Returns the map key for the flip image of a card, without any suffixes for the image size.
// */
@ -409,6 +575,25 @@ public final class ImageCache {
return TransformedImageCache.getResizedImage(original, (int) (original.getWidth() * scale), (int) (original.getHeight() * scale));
}
/**
* Returns the image appropriate to display the card in the picture panel
*
* @param card
* @param width
* @param height
* @return
*/
public static BufferedImage getFaceImage(CardView card, int width, int height) {
String key = getFaceKey(card, card.getName(), card.getExpansionSetCode());
BufferedImage original = getFaceImage(key);
if (original == null) {
LOGGER.debug(key + " (faceimage) not found");
return null;
}
return original;
}
/**
* Returns the image appropriate to display for a card in a picture panel,
* but only it was ALREADY LOADED. That is, the call is immediate and will

View file

@ -6,7 +6,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Properties;
import org.mage.plugins.card.constants.Constants;
import mage.client.constants.Constants;
public class SettingsManager {

View file

@ -1,9 +1,9 @@
package org.mage.plugins.card.utils;
import java.io.File;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.HashMap;
import java.util.Objects;
import java.util.prefs.Preferences;
import mage.client.MageFrame;
import mage.client.constants.Constants;
@ -48,7 +48,7 @@ public final class CardImageUtils {
log.warn("Token image file not found: " + card.getSet() + " - " + card.getTokenSetCode() + " - " + card.getName());
return null;
}
/**
*
* @param card
@ -63,7 +63,7 @@ public final class CardImageUtils {
}
private static String getTokenImagePath(CardDownloadData card) {
String filename = generateImagePath(card);
String filename = buildImagePathToCard(card);
TFile file = new TFile(filename);
if (!file.exists()) {
@ -74,12 +74,12 @@ public final class CardImageUtils {
if (!file.exists()) {
CardDownloadData updated = new CardDownloadData(card);
updated.setName(card.getName() + " 1");
filename = generateImagePath(updated);
filename = buildImagePathToCard(updated);
file = new TFile(filename);
if (!file.exists()) {
updated = new CardDownloadData(card);
updated.setName(card.getName() + " 2");
filename = generateImagePath(updated);
filename = buildImagePathToCard(updated);
}
}
@ -121,94 +121,136 @@ public final class CardImageUtils {
return set;
}
private static String getImageDir(CardDownloadData card, String imagesPath) {
public static String prepareCardNameForFile(String cardName) {
return cardName.replace(":", "").replace("\"", "").replace("//", "-");
}
public static String getImagesDir() {
// return real images dir (path without separator)
String path = null;
// user path
if (!PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_USE_DEFAULT, "true").equals("true")) {
path = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PATH, null);
}
// default path
if (path == null) {
path = Constants.IO.DEFAULT_IMAGES_DIR;
}
while (path.endsWith(File.separator)) {
path = path.substring(0, path.length() - 1);
}
return path;
}
public static String buildImagePathToTokens() {
String imagesPath = getImagesDir() + File.separator;
if (PreferencesDialog.isSaveImagesToZip()) {
return imagesPath + "TOK.zip" + File.separator;
} else {
return imagesPath + "TOK" + File.separator;
}
}
private static String buildImagePathToTokenDescriptor(CardDownloadData card) {
return buildImagePathToTokens() + card.getTokenDescriptor() + ".full.jpg";
}
public static String buildImagePathToSet(CardDownloadData card) {
if (card.getSet() == null) {
return "";
throw new IllegalArgumentException("Card " + card.getName() + " have empty set.");
}
String set = updateSet(card.getSet(), false).toUpperCase();
String imagesDir = (imagesPath != null ? imagesPath : Constants.IO.imageBaseDir);
String set = updateSet(card.getSet(), false).toUpperCase(); // TODO: research auto-replace... old code?
if (card.isToken()) {
return buildTokenPath(imagesDir, set);
return buildImagePathToSetAsToken(set);
} else {
return buildPath(imagesDir, set);
return buildImagePathToSetAsCard(set);
}
}
public static String getImageBasePath() {
String useDefault = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_USE_DEFAULT, "true");
String imagesPath = Objects.equals(useDefault, "true") ? Constants.IO.imageBaseDir : PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PATH, null);
private static String buildImagePathToSetAsCard(String set) {
String imagesPath = getImagesDir() + File.separator;
if (imagesPath != null && !imagesPath.endsWith(TFile.separator)) {
imagesPath += TFile.separator;
}
return imagesPath;
}
public static String getTokenBasePath() {
String imagesPath = getImageBasePath();
String finalPath = "";
if (PreferencesDialog.isSaveImagesToZip()) {
finalPath = imagesPath + "TOK" + ".zip" + TFile.separator;
return imagesPath + set + ".zip" + File.separator + set + File.separator;
} else {
finalPath = imagesPath + "TOK" + TFile.separator;
}
return finalPath;
}
private static String getTokenDescriptorImagePath(CardDownloadData card) {
return getTokenBasePath() + card.getTokenDescriptor() + ".full.jpg";
}
private static String buildTokenPath(String imagesDir, String set) {
if (PreferencesDialog.isSaveImagesToZip()) {
return imagesDir + TFile.separator + "TOK" + ".zip" + TFile.separator + set;
} else {
return imagesDir + TFile.separator + "TOK" + TFile.separator + set;
return imagesPath + set + File.separator;
}
}
private static String buildPath(String imagesDir, String set) {
if (PreferencesDialog.isSaveImagesToZip()) {
return imagesDir + TFile.separator + set + ".zip" + TFile.separator + set;
} else {
return imagesDir + TFile.separator + set;
}
private static String buildImagePathToSetAsToken(String set) {
return buildImagePathToTokens() + set + File.separator;
}
public static String generateImagePath(CardDownloadData card) {
String useDefault = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_USE_DEFAULT, "true");
String imagesPath = Objects.equals(useDefault, "true") ? null : PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PATH, null);
public static String buildImagePathToCard(CardDownloadData card) {
String imageDir = getImageDir(card, imagesPath);
String imageName;
String setPath = buildImagePathToSet(card);
String type = card.getType() != 0 ? ' ' + Integer.toString(card.getType()) : "";
String name = card.getFileName().isEmpty() ? card.getName().replace(":", "").replace("//", "-") : card.getFileName();
String prefixType = "";
if (card.getType() != 0) {
prefixType = " " + Integer.toString(card.getType());
}
String cardName = card.getFileName();
if (cardName.isEmpty()) {
cardName = prepareCardNameForFile(card.getName());
}
String finalFileName = "";
if (card.getUsesVariousArt()) {
imageName = name + '.' + card.getCollectorId() + ".full.jpg";
finalFileName = cardName + '.' + card.getCollectorId() + ".full.jpg";
} else {
imageName = name + type + ".full.jpg";
}
if (new TFile(imageDir).exists() && !new TFile(imageDir + TFile.separator + imageName).exists()) {
for (String fileName : new TFile(imageDir).list()) {
if (fileName.toLowerCase().equals(imageName.toLowerCase())) {
imageName = fileName;
break;
if (card.getUsesVariousArt()){
// only various arts can be same name, but different postfixes (a,b,c,d,e)
int len = card.getCollectorId().length();
if (Character.isLetter(card.getCollectorId().charAt(len - 1))) {
finalFileName = cardName + card.getCollectorId().charAt(len - 1) + ".full.jpg";
} else {
finalFileName = cardName + prefixType + ".full.jpg";
}
} else {
// normal cards with same names;
finalFileName = cardName + prefixType + ".full.jpg";
}
}
return imageDir + TFile.separator + imageName;
// if image file exists, correct name (for case sensitive systems)
// use TFile for zips
TFile dirFile = new TFile(setPath);
TFile imageFile = new TFile(setPath + finalFileName);
// warning, zip files can be broken
try {
if (dirFile.exists() && !imageFile.exists()) {
// search like names
for (String fileName : dirFile.list()) {
if (fileName.toLowerCase().equals(finalFileName.toLowerCase())) {
finalFileName = fileName;
break;
}
}
}
} catch (Exception ex) {
log.error("Can't read card name from file, may be it broken: " + setPath);
}
return setPath + finalFileName;
}
public static String generateFaceImagePath(String cardname, String set) {
return getImagesDir() + File.separator + "FACE" + File.separator + set + File.separator + prepareCardNameForFile(cardname) + ".jpg";
}
public static String generateTokenDescriptorImagePath(CardDownloadData card) {
// String useDefault = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_USE_DEFAULT, "true");
// String imagesPath = Objects.equals(useDefault, "true") ? null : PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PATH, null);
String straightImageFile = getTokenDescriptorImagePath(card);
String straightImageFile = buildImagePathToTokenDescriptor(card);
TFile file = new TFile(straightImageFile);
if (file.exists()) {
return straightImageFile;

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 849 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 563 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 541 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 644 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 595 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 831 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -501,6 +501,7 @@
|Generate|TOK:E01|Soldier|||SoldierToken|
|Generate|TOK:E01|Spirit|||SpiritWhiteToken|
|Generate|TOK:E01|Zombie|||ZombieToken|
|Generate|TOK:E02|Saproling|||SaprolingToken|
|Generate|TOK:EMA|Assembly-Worker|||AssemblyWorkerToken|
|Generate|TOK:EMA|Beast|||CarnivoreToken|
|Generate|TOK:EMA|Carnivore||
@ -1062,6 +1063,7 @@
|Generate|TOK:USG|Minion|||MinionToken|
|Generate|TOK:USG|Saproling|||SaprolingToken|
|Generate|TOK:UST|Dragon|||DragonTokenGold|
|Generate|TOK:UST|StormCrow|||StormCrowToken|
|Generate|TOK:V10|Wolf|||WolfToken|
|Generate|TOK:V11|Faerie Rogue|||OonaQueenFaerieToken|
|Generate|TOK:V12|Spirit|||SpiritToken|
@ -1118,4 +1120,4 @@
|Generate|TOK:ZEN|Snake|||SnakeToken|
|Generate|TOK:ZEN|Vampire||
|Generate|TOK:ZEN|Wolf|||WolfToken|
|Generate|TOK:ZEN|Zombie Giant|||QuestForTheGravelordZombieToken|
|Generate|TOK:ZEN|Zombie Giant|||QuestForTheGravelordZombieToken|

View file

@ -29,7 +29,6 @@ ulg=ul
6ed=6e
btd=bd
sth=sh
nem=ne
por=po
s99=st
lgn=le
@ -74,6 +73,6 @@ dd3evg=ddaevg
dd3gvl=ddagvl
dd3jvc=ddajvc
# Remove setname as soon as the images can be downloaded
ignore.urls=TOK,DDT,V17,RIX,E02,M19,M25,DOM,UST,H17
ignore.urls=TOK,M19,M25,DOM,H17
# sets ordered by release time (newest goes first)
token.lookup.order=M19,M25,DOM,E02,RIX,UST,XLN,IMA,H17,C17,V17,E01,DDT,CMA,HOU,MM3,DDS,AKH,DD3DVD,DD3EVG,DD3GVL,DD3JVC,H09,AER,PCA,C16,V16,MPS,KLD,DDR,CN2,EMN,EMA,SOI,DDQ,CP,CMA,ARENA,SUS,APAC,EURO,UGIN,C15,OGW,EXP,DDP,BFZ,DRB,V09,V10,V11,V12,V13,V14,V15,TPR,MPRP,DD3,DDO,ORI,MM2,PTC,DTK,FRF,KTK,M15,VMA,CNS,JOU,BNG,THS,DDL,M14,MMA,DGM,GTC,RTR,M13,AVR,DDI,DKA,ISD,M12,NPH,MBS,SOM,M11,ROE,DDE,WWK,ZEN,M10,GVL,ARB,DVD,CFX,JVC,ALA,EVE,SHM,EVG,MOR,LRW,10E,CLS,CHK,GRC

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

View file

@ -0,0 +1,43 @@
package mage.client.util;
import org.junit.Assert;
import org.junit.Test;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import static mage.client.MageFrame.isChrismasTime;
public class ChrismasTest {
private Date getDate(int Year, int Month, int Day){
Calendar cal = new GregorianCalendar(Year, Month - 1, Day);
cal.add(Calendar.HOUR, 10);
return cal.getTime();
}
@Test
public void testChrismasDays() throws Exception {
// chrismas from 15 december to 15 january
Assert.assertEquals(false, isChrismasTime(getDate(2017, 11, 1)));
Assert.assertEquals(false, isChrismasTime(getDate(2017, 11, 15)));
Assert.assertEquals(false, isChrismasTime(getDate(2017, 11, 30)));
Assert.assertEquals(false, isChrismasTime(getDate(2017, 12, 1)));
Assert.assertEquals(false, isChrismasTime(getDate(2017, 12, 14)));
Assert.assertEquals(true, isChrismasTime(getDate(2017, 12, 15)));
Assert.assertEquals(true, isChrismasTime(getDate(2017, 12, 16)));
Assert.assertEquals(true, isChrismasTime(getDate(2017, 12, 31)));
Assert.assertEquals(true, isChrismasTime(getDate(2018, 1, 1)));
Assert.assertEquals(true, isChrismasTime(getDate(2018, 1, 14)));
Assert.assertEquals(true, isChrismasTime(getDate(2018, 1, 15)));
Assert.assertEquals(false, isChrismasTime(getDate(2018, 1, 16)));
Assert.assertEquals(false, isChrismasTime(getDate(2018, 1, 31)));
Assert.assertEquals(false, isChrismasTime(getDate(2018, 2, 1)));
Assert.assertEquals(false, isChrismasTime(getDate(2018, 12, 1)));
Assert.assertEquals(true, isChrismasTime(getDate(2018, 12, 20)));
Assert.assertEquals(true, isChrismasTime(getDate(2019, 1, 10)));
Assert.assertEquals(false, isChrismasTime(getDate(2019, 1, 25)));
}
}

View file

@ -25,8 +25,8 @@ public abstract class MageCard extends JPanel {
public abstract CardView getOriginal();
// sets the vertical text offset for the card name on the image
public abstract void setTextOffset(int yOffset);
// sets the vertical text offset for the card name on the image, use to move caption to card center
public abstract void setCardCaptionTopOffset(int yOffsetPercent);
public abstract void setCardBounds(int x, int y, int width, int height);

View file

@ -32,10 +32,9 @@ public interface CardPlugin extends Plugin {
/**
* Download various symbols (mana, tap, set).
*
* @param imagesPath Path to check in and store symbols to. Can be null, in
* such case default path should be used.
* @param imagesDir Path to check in and store symbols to. Can't be null.
*/
void downloadSymbols(String imagesPath);
void downloadSymbols(String imagesDir);
void onAddCard(MagePermanent card, int count);

View file

@ -41,7 +41,7 @@ public class MageVersion implements Serializable, Comparable<MageVersion> {
public final static int MAGE_VERSION_MAJOR = 1;
public final static int MAGE_VERSION_MINOR = 4;
public final static int MAGE_VERSION_PATCH = 26;
public final static String MAGE_VERSION_MINOR_PATCH = "V7";
public final static String MAGE_VERSION_MINOR_PATCH = "V11b";
public final static String MAGE_VERSION_INFO = "";
private final int major;

View file

@ -114,7 +114,39 @@ public class AusHighlander extends Constructed {
int totalPoints = 0;
for (Map.Entry<String, Integer> entry : counts.entrySet()) {
String cn = entry.getKey();
if (cn.equals("Ancestral Recall")
|| cn.equals("Black Lotus")
|| cn.equals("Time Vault")) {
totalPoints += 4;
invalid.put(cn, "4 points");
}
if (cn.equals("Demonic Tutor")
|| cn.equals("Imperial Seal")
|| cn.equals("Mox Emerald")
|| cn.equals("Mox Jet")
|| cn.equals("Mox Pearl")
|| cn.equals("Mox Ruby")
|| cn.equals("Sol Ring")
|| cn.equals("Time Walk")
|| cn.equals("Tinker")
|| cn.equals("Vampiric Tutor")
|| cn.equals("Yawgmoth's Will")
|| cn.equals("Mox Sapphire.")) {
totalPoints += 3;
invalid.put(cn, "3 points");
}
if (cn.equals("Channel")
|| cn.equals("Dig Through Time")
|| cn.equals("Library of Alexandria")
|| cn.equals("Mana Crypt")
|| cn.equals("Mystical Tutor")
|| cn.equals("Protean Hulk")
|| cn.equals("Skullclamp")
|| cn.equals("Strip Mine")
|| cn.equals("Tolarian Academy.")) {
totalPoints += 2;
invalid.put(cn, "2 points");
}
if (cn.equals("Back to Basics")
|| cn.equals("Balance")
|| cn.equals("Birthing Pod")
@ -139,8 +171,8 @@ public class AusHighlander extends Constructed {
|| cn.equals("Natural Order")
|| cn.equals("Oath of Druids")
|| cn.equals("Personal Tutor")
|| cn.equals("Sensei's Divining Top")
|| cn.equals("Snapcaster Mage")
|| cn.equals("Steelshaper's Gift")
|| cn.equals("Stoneforge Mystic")
|| cn.equals("Survival of the Fittest")
|| cn.equals("Tainted Pact")
@ -151,50 +183,15 @@ public class AusHighlander extends Constructed {
|| cn.equals("Umezawa's Jitte")
|| cn.equals("Wasteland")
|| cn.equals("Wheel of Fortune")
|| cn.equals("Worldly Tutor")
|| cn.equals("Yawgmoth's Bargain")) {
|| cn.equals("Yawgmoth's Bargain")
|| cn.equals("Worldly Tutor")) {
totalPoints += 1;
invalid.put(cn, "1 point");
}
if (cn.equals("Channel")
|| cn.equals("Dig Through Time")
|| cn.equals("Library of Alexandria")
|| cn.equals("Mana Crypt")
|| cn.equals("Mox Emerald")
|| cn.equals("Mox Jet")
|| cn.equals("Mox Pearl")
|| cn.equals("Mox Ruby")
|| cn.equals("Mox Sapphire")
|| cn.equals("Mystical Tutor")
|| cn.equals("Protean Hulk")
|| cn.equals("Skullclamp")
|| cn.equals("Strip Mine")
|| cn.equals("Tolarian Academy")) {
totalPoints += 2;
invalid.put(cn, "2 points");
}
if (cn.equals("Demonic Tutor")
|| cn.equals("Imperial Seal")
|| cn.equals("Sol Ring")
|| cn.equals("Time Walk")
|| cn.equals("Tinker")
|| cn.equals("Vampiric Tutor")
|| cn.equals("Yawgmoth's Will")) {
totalPoints += 3;
invalid.put(cn, "3 points");
}
if (cn.equals("Ancestral Recall")
|| cn.equals("Black Lotus")
|| cn.equals("Time Vault")) {
totalPoints += 4;
invalid.put(cn, "4 points");
}
}
if (totalPoints > 7) {
invalid.put("Total points too high", "Your calculated point total was " + totalPoints);
invalid.put("Only you can see this!", "Your opponents will not be able to see this message or what cards are in your deck!");
valid = false;
}
return valid;

View file

@ -92,15 +92,14 @@ public class CanadianHighlander extends Constructed {
String cn = entry.getKey();
if (cn.equals("Balance")
|| cn.equals("Dig Through Time")
|| cn.equals("Doomsday")
|| cn.equals("Enlightened Tutor")
|| cn.equals("Fastbond")
|| cn.equals("Intuition")
|| cn.equals("Library of Alexandria")
|| cn.equals("Lim-Dul's Vault")
|| cn.equals("Mana Vault")
|| cn.equals("Merchant Scroll")
|| cn.equals("Mind Twist")
|| cn.equals("Oath of Druids")
|| cn.equals("Personal Tutor")
|| cn.equals("Stoneforge Mystic")
|| cn.equals("Tainted Pact")
@ -112,8 +111,8 @@ public class CanadianHighlander extends Constructed {
totalPoints += 1;
invalid.put(entry.getKey(), " 1 point " + cn);
}
if (cn.equals("Doomsday")
|| cn.equals("Gifts Ungiven")
if (cn.equals("Gifts Ungiven")
|| cn.equals("Hermit Druid")
|| cn.equals("Imperial Seal")
|| cn.equals("Mana Crypt")
|| cn.equals("Mystical Tutor")
@ -125,19 +124,19 @@ public class CanadianHighlander extends Constructed {
invalid.put(entry.getKey(), " 2 points " + cn);
}
if (cn.equals("Birthing Pod")
|| cn.equals("Hermit Druid")
|| cn.equals("Mox Emerald")
|| cn.equals("Mox Jet")
|| cn.equals("Mox Pearl")
|| cn.equals("Mox Ruby")
|| cn.equals("Mox Sapphire")
|| cn.equals("Protean Hulk")
|| cn.equals("Sol Ring")
|| cn.equals("Vampiric Tutor")) {
totalPoints += 3;
invalid.put(entry.getKey(), " 3 points " + cn);
}
if (cn.equals("Demonic Tutor")
|| cn.equals("Sol Ring")) {
|| cn.equals("Tinker")) {
totalPoints += 4;
invalid.put(entry.getKey(), " 4 points " + cn);
}
@ -147,13 +146,12 @@ public class CanadianHighlander extends Constructed {
invalid.put(entry.getKey(), " 5 points " + cn);
}
if (cn.equals("Ancestral Recall")
|| cn.equals("Time Walk")) {
|| cn.equals("Time Vault")) {
totalPoints += 6;
invalid.put(entry.getKey(), " 5 points " + cn);
invalid.put(entry.getKey(), " 6 points " + cn);
}
if (cn.equals("Black Lotus")
|| cn.equals("Flash")
|| cn.equals("Time Vault")) {
|| cn.equals("Flash")) {
totalPoints += 7;
invalid.put(entry.getKey(), " 7 points " + cn);
}

View file

@ -44,6 +44,7 @@ public class DuelCommander extends Commander {
banned.add("Eidolon of the Great Revel");
banned.add("Emrakul, the Aeons Torn");
banned.add("Entomb");
banned.add("Fastbond");
banned.add("Fireblast");
banned.add("Food Chain");
banned.add("Gaea's Cradle");

View file

@ -0,0 +1,152 @@
/*
* Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.deck;
import java.util.*;
import java.util.Map.Entry;
import mage.abilities.common.CanBeYourCommanderAbility;
import mage.abilities.keyword.PartnerAbility;
import mage.cards.Card;
import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.cards.decks.Constructed;
import mage.cards.decks.Deck;
import mage.constants.SetType;
import mage.filter.FilterMana;
/**
*
* @author spjspj
*/
public class FreeformCommander extends Constructed {
protected List<String> bannedCommander = new ArrayList<>();
private static final Map<String, Integer> pdAllowed = new HashMap<>();
private static boolean setupAllowed = false;
public FreeformCommander() {
this("Freeform Commander");
for (ExpansionSet set : Sets.getInstance().values()) {
setCodes.add(set.getCode());
}
}
public FreeformCommander(String name) {
super(name);
}
@Override
public boolean validate(Deck deck) {
boolean valid = true;
FilterMana colorIdentity = new FilterMana();
if (deck.getCards().size() + deck.getSideboard().size() != 100) {
invalid.put("Deck", "Must contain 100 cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards");
valid = false;
}
List<String> basicLandNames = new ArrayList<>(Arrays.asList("Forest", "Island", "Mountain", "Swamp", "Plains", "Wastes"));
Map<String, Integer> counts = new HashMap<>();
countCards(counts, deck.getCards());
countCards(counts, deck.getSideboard());
for (Map.Entry<String, Integer> entry : counts.entrySet()) {
if (entry.getValue() > 1) {
if (!basicLandNames.contains(entry.getKey())) {
invalid.put(entry.getKey(), "Too many: " + entry.getValue());
valid = false;
}
}
}
generateFreeformHash();
if (deck.getSideboard().size() < 1 || deck.getSideboard().size() > 2) {
invalid.put("Commander", "Sideboard must contain only the commander(s)");
valid = false;
} else {
for (Card commander : deck.getSideboard()) {
if (!(commander.isCreature() ||
commander.isLegendary())) {
invalid.put("Commander", "For Freeform Commander, the commander must be a creature or be legendary. Yours was: " + commander.getName());
valid = false;
}
if (deck.getSideboard().size() == 2 && !commander.getAbilities().contains(PartnerAbility.getInstance())) {
invalid.put("Commander", "Commander without Partner (" + commander.getName() + ')');
valid = false;
}
FilterMana commanderColor = commander.getColorIdentity();
if (commanderColor.isWhite()) {
colorIdentity.setWhite(true);
}
if (commanderColor.isBlue()) {
colorIdentity.setBlue(true);
}
if (commanderColor.isBlack()) {
colorIdentity.setBlack(true);
}
if (commanderColor.isRed()) {
colorIdentity.setRed(true);
}
if (commanderColor.isGreen()) {
colorIdentity.setGreen(true);
}
}
}
for (Card card : deck.getCards()) {
if (!cardHasValidColor(colorIdentity, card)) {
invalid.put(card.getName(), "Invalid color (" + colorIdentity.toString() + ')');
valid = false;
}
}
for (Card card : deck.getSideboard()) {
if (!isSetAllowed(card.getExpansionSetCode())) {
if (!legalSets(card)) {
invalid.put(card.getName(), "Not allowed Set: " + card.getExpansionSetCode());
valid = false;
}
}
}
return valid;
}
public boolean cardHasValidColor(FilterMana commander, Card card) {
FilterMana cardColor = card.getColorIdentity();
return !(cardColor.isBlack() && !commander.isBlack()
|| cardColor.isBlue() && !commander.isBlue()
|| cardColor.isGreen() && !commander.isGreen()
|| cardColor.isRed() && !commander.isRed()
|| cardColor.isWhite() && !commander.isWhite());
}
public void generateFreeformHash() {
return;
}
}

View file

@ -0,0 +1,43 @@
/*
* Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.deck;
import mage.cards.decks.Constructed;
/**
*
* @author LevelX2
*/
public class IxalanBlock extends Constructed {
public IxalanBlock() {
super("Constructed - Ixalan Block");
setCodes.add("XLN");
setCodes.add("RIX");
}
}

View file

@ -0,0 +1,43 @@
/*
* Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.deck;
import mage.cards.decks.Constructed;
/**
*
* @author LevelX2
*/
public class LorwynBlock extends Constructed {
public LorwynBlock() {
super("Constructed - Lorwyn Block");
setCodes.add("LRW");
setCodes.add("MOR");
}
}

View file

@ -0,0 +1,49 @@
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.26</version>
</parent>
<artifactId>mage-game-freeformcommanderfreeforall</artifactId>
<packaging>jar</packaging>
<name>Mage Game Freeform Commander Free For All</name>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>mage</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
<finalName>mage-game-freeforall</finalName>
</build>
<properties/>
</project>

View file

@ -0,0 +1,77 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.game;
import java.util.UUID;
import mage.constants.MultiplayerAttackOption;
import mage.constants.RangeOfInfluence;
import mage.game.match.MatchType;
/**
*
* @author spjspj
*/
public class FreeformCommanderFreeForAll extends GameCommanderImpl {
private int numPlayers;
public FreeformCommanderFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) {
super(attackOption, range, freeMulligans, startLife);
}
public FreeformCommanderFreeForAll(final FreeformCommanderFreeForAll game) {
super(game);
this.numPlayers = game.numPlayers;
}
@Override
protected void init(UUID choosingPlayerId) {
startingPlayerSkipsDraw = false;
super.init(choosingPlayerId);
}
@Override
public MatchType getGameType() {
return new FreeformCommanderFreeForAllType();
}
@Override
public int getNumPlayers() {
return numPlayers;
}
public void setNumPlayers(int numPlayers) {
this.numPlayers = numPlayers;
}
@Override
public FreeformCommanderFreeForAll copy() {
return new FreeformCommanderFreeForAll(this);
}
}

View file

@ -0,0 +1,55 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.game;
import mage.game.match.MatchImpl;
import mage.game.match.MatchOptions;
/**
*
* @author spjspj
*/
public class FreeformCommanderFreeForAllMatch extends MatchImpl {
public FreeformCommanderFreeForAllMatch(MatchOptions options) {
super(options);
}
@Override
public void startGame() throws GameException {
int startLife = 40;
boolean alsoHand = true;
FreeformCommanderFreeForAll game = new FreeformCommanderFreeForAll(options.getAttackOption(), options.getRange(), options.getFreeMulligans(), startLife);
game.setStartMessage(this.createGameStartMessage());
game.setAlsoHand(alsoHand);
game.setAlsoLibrary(true);
initGame(game);
games.add(game);
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.game;
import mage.game.match.MatchType;
/**
*
* @author spjspj
*/
public class FreeformCommanderFreeForAllType extends MatchType {
public FreeformCommanderFreeForAllType() {
this.name = "Freeform Commander Free For All";
this.maxPlayers = 10;
this.minPlayers = 3;
this.numTeams = 0;
this.useAttackOption = true;
this.useRange = true;
this.sideboardingAllowed = false;
}
protected FreeformCommanderFreeForAllType(final FreeformCommanderFreeForAllType matchType) {
super(matchType);
}
@Override
public FreeformCommanderFreeForAllType copy() {
return new FreeformCommanderFreeForAllType(this);
}
}

View file

@ -0,0 +1,55 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.26</version>
</parent>
<artifactId>mage-game-momirfreeforall</artifactId>
<packaging>jar</packaging>
<name>Mage Game Momir Basic Free for All</name>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>mage</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>mage-game-freeforall</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
<finalName>mage-game-momir</finalName>
</build>
<properties/>
</project>

View file

@ -0,0 +1,55 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.game;
import mage.game.match.MatchImpl;
import mage.game.match.MatchOptions;
/**
*
* @author nigelzor
*/
public class MomirFreeForAllMatch extends MatchImpl {
public MomirFreeForAllMatch(MatchOptions options) {
super(options);
}
@Override
public void startGame() throws GameException {
// Momir Vig, Simic Visionary gives +4 starting life
int startLife = 24;
MomirGame game = new MomirGame(options.getAttackOption(), options.getRange(), options.getFreeMulligans(), startLife);
game.setStartMessage(this.createGameStartMessage());
this.initGame(game);
games.add(game);
}
}

View file

@ -0,0 +1,57 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.game;
import mage.game.match.MatchType;
/**
*
* @author nigelzor
*/
public class MomirFreeForAllType extends MatchType {
public MomirFreeForAllType() {
this.name = "Momir Basic Free For All";
this.maxPlayers = 10;
this.minPlayers = 2;
this.numTeams = 0;
this.useAttackOption = true;
this.useRange = true;
this.sideboardingAllowed = false;
}
protected MomirFreeForAllType(final MomirFreeForAllType matchType){
super(matchType);
}
@Override
public MomirFreeForAllType copy() {
return new MomirFreeForAllType(this);
}
}

View file

@ -0,0 +1,105 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.game;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.InfoEffect;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
import mage.constants.MultiplayerAttackOption;
import mage.constants.PhaseStep;
import mage.constants.RangeOfInfluence;
import mage.constants.Zone;
import mage.game.command.emblems.MomirEmblem;
import mage.game.match.MatchType;
import mage.game.turn.TurnMod;
import mage.players.Player;
/**
*
* @author nigelzor
*/
public class MomirGame extends FreeForAll {
private int numPlayers;
public MomirGame(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) {
super(attackOption, range, freeMulligans, startLife);
}
public MomirGame(final MomirGame game) {
super(game);
}
@Override
public MatchType getGameType() {
return new MomirFreeForAllType();
}
@Override
public int getNumPlayers() {
return numPlayers;
}
@Override
protected void init(UUID choosingPlayerId) {
Ability ability = new SimpleStaticAbility(Zone.COMMAND, new InfoEffect("Vanguard effects"));
for (UUID playerId : state.getPlayerList(startingPlayerId)) {
Player player = getPlayer(playerId);
if (player != null) {
CardInfo cardInfo = CardRepository.instance.findCard("Momir Vig, Simic Visionary");
addEmblem(new MomirEmblem(), cardInfo.getCard(), playerId);
}
}
getState().addAbility(ability, null);
super.init(choosingPlayerId);
state.getTurnMods().add(new TurnMod(startingPlayerId, PhaseStep.DRAW));
}
@Override
public Set<UUID> getOpponents(UUID playerId) {
Set<UUID> opponents = new HashSet<>();
for (UUID opponentId : this.getPlayer(playerId).getInRange()) {
if (!opponentId.equals(playerId)) {
opponents.add(opponentId);
}
}
return opponents;
}
@Override
public MomirGame copy() {
return new MomirGame(this);
}
}

View file

@ -1,5 +0,0 @@
#Generated by Maven
#Fri Sep 15 22:14:29 CEST 2017
version=1.4.26
groupId=org.mage
artifactId=mage-game-pennydreadfulcommanderfreeforall

View file

@ -489,7 +489,9 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
maxSeconds = 3600;
}
logger.debug("maxThink: " + maxSeconds + " seconds ");
return task.get(maxSeconds, TimeUnit.SECONDS);
if (task.get(maxSeconds, TimeUnit.SECONDS) != null) {
return task.get(maxSeconds, TimeUnit.SECONDS);
}
} catch (TimeoutException e) {
logger.info("simulating - timed out");
task.cancel(true);
@ -519,7 +521,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
logger.trace("interrupted - " + val);
return val;
}
if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.gameOver(null)) {
if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.checkIfGameIsOver()) {
logger.trace("Add actions -- reached end state, node count=" + SimulationNode2.nodeCount + ", depth=" + depth);
val = GameStateEvaluator2.evaluate(playerId, game);
UUID currentPlayerId = node.getGame().getPlayerList().get();
@ -540,7 +542,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
}
}
if (game.gameOver(null)) {
if (game.checkIfGameIsOver()) {
val = GameStateEvaluator2.evaluate(playerId, game);
} else if (!node.getChildren().isEmpty()) {
//declared attackers or blockers or triggered abilities
@ -588,7 +590,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
logger.debug("Sim Prio [" + depth + "] -- repeated action: " + action.toString());
continue;
}
if (!sim.gameOver(null) && action.isUsesStack()) {
if (!sim.checkIfGameIsOver() && action.isUsesStack()) {
// only pass if the last action uses the stack
UUID nextPlayerId = sim.getPlayerList().get();
do {
@ -765,14 +767,9 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
return super.choose(outcome, choice, game);
}
if (!choice.isChosen()) {
for (String achoice : choices) {
choice.setChoice(achoice);
if (choice.isChosen()) {
choices.clear();
return true;
}
if(!choice.setChoiceByAnswers(choices, true)){
choice.setRandomChoice();
}
return false;
}
return true;
}
@ -864,7 +861,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
break;
case CLEANUP:
game.getPhase().getStep().beginStep(game, activePlayerId);
if (!game.checkStateAndTriggered() && !game.gameOver(null)) {
if (!game.checkStateAndTriggered() && !game.checkIfGameIsOver()) {
game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext());
game.getTurn().setPhase(new BeginningPhase());
game.getPhase().setStep(new UntapStep());

Some files were not shown because too many files have changed in this diff Show more