diff --git a/Mage.Client/pom.xml b/Mage.Client/pom.xml index aa5782dc7bc..6da7a3174ca 100644 --- a/Mage.Client/pom.xml +++ b/Mage.Client/pom.xml @@ -57,6 +57,11 @@ swingx 1.6.1 + + org.jetlang + jetlang + 0.2.4 + diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index 346a95e7b42..cb54fd0c846 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -143,6 +143,21 @@ public class MageFrame extends javax.swing.JFrame { Separator separator = new javax.swing.JToolBar.Separator(); mageToolbar.add(separator); + JButton btnDownloadSymbols = new JButton("Symbols"); + btnDownloadSymbols.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1)); + btnDownloadSymbols.setFocusable(false); + btnDownloadSymbols.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnDownloadSymbols.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnDownloadSymbols.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnSymbolsActionPerformed(evt); + } + }); + mageToolbar.add(btnDownloadSymbols); + + separator = new javax.swing.JToolBar.Separator(); + mageToolbar.add(separator); + JButton btnDownload = new JButton("Images"); btnDownload.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1)); btnDownload.setFocusable(false); @@ -173,6 +188,12 @@ public class MageFrame extends javax.swing.JFrame { } Plugins.getInstance().downloadImage(allCards); } + + private void btnSymbolsActionPerformed(java.awt.event.ActionEvent evt) { + if (JOptionPane.showConfirmDialog(null, "Do you want to download mana symbols?") == JOptionPane.OK_OPTION) { + Plugins.getInstance().downloadSymbols(); + } + } public void showGame(UUID gameId, UUID playerId) { this.tablesPane.hideTables(); diff --git a/Mage.Client/src/main/java/mage/client/plugins/MagePlugins.java b/Mage.Client/src/main/java/mage/client/plugins/MagePlugins.java index ca033451877..ff274153e4e 100644 --- a/Mage.Client/src/main/java/mage/client/plugins/MagePlugins.java +++ b/Mage.Client/src/main/java/mage/client/plugins/MagePlugins.java @@ -27,6 +27,7 @@ public interface MagePlugins { boolean isCounterPluginLoaded(); void sortPermanents(Map ui, Collection permanents); void downloadImage(Set allCards); + void downloadSymbols(); int getGamesPlayed(); void addGamesPlayed(); } diff --git a/Mage.Client/src/main/java/mage/client/plugins/impl/Plugins.java b/Mage.Client/src/main/java/mage/client/plugins/impl/Plugins.java index 0b328227cfa..7b913e05acf 100644 --- a/Mage.Client/src/main/java/mage/client/plugins/impl/Plugins.java +++ b/Mage.Client/src/main/java/mage/client/plugins/impl/Plugins.java @@ -112,6 +112,11 @@ public class Plugins implements MagePlugins { public void downloadImage(Set allCards) { if (this.cardPlugin != null) this.cardPlugin.downloadImages(allCards); } + + @Override + public void downloadSymbols() { + if (this.cardPlugin != null) this.cardPlugin.downloadSymbols(); + } @Override public int getGamesPlayed() { diff --git a/Mage.Common/src/mage/interfaces/plugin/CardPlugin.java b/Mage.Common/src/mage/interfaces/plugin/CardPlugin.java index e181f9065ac..dd1fba9d9b9 100644 --- a/Mage.Common/src/mage/interfaces/plugin/CardPlugin.java +++ b/Mage.Common/src/mage/interfaces/plugin/CardPlugin.java @@ -28,4 +28,5 @@ public interface CardPlugin extends Plugin { MagePermanent getMageCard(CardView permanent, CardDimensions dimension, UUID gameId, ActionCallback callback); void sortPermanents(Map ui, Collection cards); void downloadImages(Set allCards); + void downloadSymbols(); } diff --git a/Mage.Plugins/Mage.Card.Plugin/pom.xml b/Mage.Plugins/Mage.Card.Plugin/pom.xml index f8ca19ceb0c..c1307599b06 100644 --- a/Mage.Plugins/Mage.Card.Plugin/pom.xml +++ b/Mage.Plugins/Mage.Card.Plugin/pom.xml @@ -45,6 +45,12 @@ 0.8.4 provided + + org.jetlang + jetlang + 0.2.4 + provided + diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/card/arcane/CardPanel.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/card/arcane/CardPanel.java index d72c9581a6f..d61515020ef 100644 --- a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/card/arcane/CardPanel.java +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/card/arcane/CardPanel.java @@ -314,10 +314,13 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti super.paintChildren(g); if (showCastingCost && !isAnimationPanel && cardWidth < 200 && cardWidth > 60) { - //TODO:uncomment - /*int width = ManaSymbols.getWidth(gameCard.getManaCost()); - ManaSymbols.draw(g, gameCard.getManaCost(), cardXOffset + 8, cardHeight - 9); - */ + String manaCost = ManaSymbols.getStringManaCost(gameCard.getManaCost()); + int width = ManaSymbols.getWidth(manaCost); + if (hasImage) { + ManaSymbols.draw(g, manaCost, cardXOffset + cardWidth - width - 5, cardYOffset + 5); + } else { + ManaSymbols.draw(g, manaCost, cardXOffset + 8, cardHeight - 9); + } } } diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/card/arcane/ManaSymbols.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/card/arcane/ManaSymbols.java index 8427bc63380..39e0e27b6bc 100644 --- a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/card/arcane/ManaSymbols.java +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/card/arcane/ManaSymbols.java @@ -2,13 +2,19 @@ package org.mage.card.arcane; import java.awt.Graphics; import java.awt.Image; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import java.io.File; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.StringTokenizer; import java.util.regex.Pattern; import org.apache.log4j.Logger; import org.mage.plugins.card.constants.Constants; +import org.mage.plugins.card.images.ImageCache; +import org.mage.plugins.card.utils.BufferedImageBuilder; public class ManaSymbols { private static final Logger log = Logger.getLogger(ManaSymbols.class); @@ -18,9 +24,16 @@ public class ManaSymbols { static public void loadImages () { String[] symbols = new String[] {"0", "1", "10", "11", "12", "15", "16", "2", "3", "4", "5", "6", "7", "8", "9", "B", "BG", "BR", "G", "GU", "GW", "R", "RG", "RW", "S", "T", "U", "UB", "UR", "W", "WB", "WU", "X", "Y", "Z", "slash"}; - //TODO: replace by downloading - for (String symbol : symbols) - manaImages.put(symbol, UI.getImageIcon(Constants.RESOURCE_PATH_MANA + "/" + symbol + ".png").getImage()); + for (String symbol : symbols) { + File file = new File(Constants.RESOURCE_PATH_MANA + "/" + symbol + ".jpg"); + BufferedImageBuilder builder = new BufferedImageBuilder(); + Rectangle r = new Rectangle(11, 11); + try { + Image image = UI.getImageIcon(file.getAbsolutePath()).getImage(); + BufferedImage resized = ImageCache.getResizedImage(builder.bufferImage(image, BufferedImage.TYPE_INT_ARGB), r); + manaImages.put(symbol, resized); + } catch (Exception e) {} + } } static public void draw (Graphics g, String manaCost, int x, int y) { @@ -32,7 +45,7 @@ public class ManaSymbols { String symbol = tok.nextToken().substring(0); Image image = manaImages.get(symbol); if (image == null) { - log.error("Symbol not recognized \"" + symbol + "\" in mana cost: " + manaCost); + //log.error("Symbol not recognized \"" + symbol + "\" in mana cost: " + manaCost); continue; } g.drawImage(image, x, y, null); @@ -40,7 +53,15 @@ public class ManaSymbols { } } - static public int getWidth (String manaCost) { + static public String getStringManaCost(List manaCost) { + StringBuilder sb = new StringBuilder(); + for (String s : manaCost) { + sb.append(s); + } + return sb.toString().replace("{", "").replace("}", " ").trim(); + } + + static public int getWidth(String manaCost) { int width = 0; manaCost = manaCost.replace("\\", ""); StringTokenizer tok = new StringTokenizer(manaCost, " "); diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/CardPluginImpl.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/CardPluginImpl.java index f0d9188022c..abff2f7ecfe 100644 --- a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/CardPluginImpl.java +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/CardPluginImpl.java @@ -1,6 +1,10 @@ package org.mage.plugins.card; +import java.awt.BorderLayout; +import java.awt.Frame; import java.awt.Rectangle; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -9,6 +13,7 @@ import java.util.Set; import java.util.UUID; import javax.swing.JComponent; +import javax.swing.JDialog; import javax.swing.JLayeredPane; import javax.swing.JScrollPane; @@ -27,7 +32,12 @@ import net.xeoh.plugins.base.annotations.meta.Author; import org.apache.log4j.Logger; import org.mage.card.arcane.CardPanel; +import org.mage.card.arcane.ManaSymbols; import org.mage.plugins.card.constants.Constants; +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.GathererSymbols; import org.mage.plugins.card.images.DownloadPictures; /** @@ -68,6 +78,7 @@ public class CardPluginImpl implements CardPlugin { @PluginLoaded public void newPlugin(CardPlugin plugin) { + ManaSymbols.loadImages(); log.info(plugin.toString() + " has been loaded."); } @@ -80,6 +91,7 @@ public class CardPluginImpl implements CardPlugin { CardPanel cardPanel = new CardPanel(permanent, gameId, true, callback); cardPanel.setShowCastingCost(true); cardPanel.setCardBounds(0, 0, dimension.frameWidth, dimension.frameHeight); + cardPanel.setShowCastingCost(true); return cardPanel; } @@ -88,6 +100,7 @@ public class CardPluginImpl implements CardPlugin { CardPanel cardPanel = new CardPanel(permanent, gameId, true, callback); cardPanel.setShowCastingCost(true); cardPanel.setCardBounds(0, 0, dimension.frameWidth, dimension.frameHeight); + cardPanel.setShowCastingCost(true); return cardPanel; } @@ -390,4 +403,28 @@ public class CardPluginImpl implements CardPlugin { public void downloadImages(Set allCards) { DownloadPictures.startDownload(null, allCards); } + + @Override + public void downloadSymbols() { + final DownloadGui g = new DownloadGui(new Downloader()); + + Iterable it = new GathererSymbols(); + + for(DownloadJob job:it) { + g.getDownloader().add(job); + } + + JDialog d = new JDialog((Frame) null, "Download pictures", false); + d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + d.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + g.getDownloader().dispose(); + } + }); + d.setLayout(new BorderLayout()); + d.add(g); + d.pack(); + d.setVisible(true); + } } diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/constants/Constants.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/constants/Constants.java index 0713b66a342..2fdade1ba80 100644 --- a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/constants/Constants.java +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/constants/Constants.java @@ -4,24 +4,14 @@ import java.awt.Rectangle; import java.io.File; public class Constants { - public static final String RESOURCE_PATH = "/images"; - public static final String RESOURCE_PATH_MANA = resourcePath("mana"); + public static final String RESOURCE_PATH_MANA = IO.imageBaseDir + "symbols" + File.separator + "large"; + public static final Rectangle CARD_SIZE_FULL = new Rectangle(101, 149); public interface IO { - public static final String imageBaseDir = "." + File.separator + "plugins" + File.separator + "images" + File.separator; + public static final String imageBaseDir = "plugins" + File.separator + "images" + File.separator; public static final 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"; - - /** - * Build resource path. - * - * @param folder - * @return - */ - private static String resourcePath(String folder) { - return RESOURCE_PATH + "/" + folder; - } } diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/DownloadGui.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/DownloadGui.java new file mode 100644 index 00000000000..5e971cae91f --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/DownloadGui.java @@ -0,0 +1,195 @@ +/** + * DownloadGui.java + * + * Created on 25.08.2010 + */ + +package org.mage.plugins.card.dl; + + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.IndexedPropertyChangeEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.BorderFactory; +import javax.swing.BoundedRangeModel; +import javax.swing.BoxLayout; +import javax.swing.DefaultBoundedRangeModel; +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.JScrollPane; + +import org.mage.plugins.card.dl.DownloadJob.State; + + +/** + * The class DownloadGui. + * + * @version V0.0 25.08.2010 + * @author Clemens Koza + */ +public class DownloadGui extends JPanel { + private static final long serialVersionUID = -7346572382493844327L; + + private final Downloader d; + private final DownloadListener l = new DownloadListener(); + private final BoundedRangeModel model = new DefaultBoundedRangeModel(0, 0, 0, 0); + private final JProgressBar progress = new JProgressBar(model); + + private final Map progresses = new HashMap(); + private final JPanel panel = new JPanel(); + + public DownloadGui(Downloader d) { + super(new BorderLayout()); + this.d = d; + d.addPropertyChangeListener(l); + + JPanel p = new JPanel(new BorderLayout()); + p.setBorder(BorderFactory.createTitledBorder("Progress:")); + p.add(progress); + JButton b = new JButton("X"); + b.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + getDownloader().dispose(); + } + }); + p.add(b, BorderLayout.EAST); + add(p, BorderLayout.NORTH); + + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + JScrollPane pane = new JScrollPane(panel); + pane.setPreferredSize(new Dimension(500, 300)); + add(pane); + for(int i = 0; i < d.getJobs().size(); i++) + addJob(i, d.getJobs().get(i)); + } + + public Downloader getDownloader() { + return d; + } + + private class DownloadListener implements PropertyChangeListener { + @Override + public void propertyChange(PropertyChangeEvent evt) { + String name = evt.getPropertyName(); + if(evt.getSource() instanceof DownloadJob) { + DownloadPanel p = progresses.get(evt.getSource()); + if("state".equals(name)) { + if(evt.getOldValue() == State.FINISHED || evt.getOldValue() == State.ABORTED) { + changeProgress(-1, 0); + } + if(evt.getNewValue() == State.FINISHED || evt.getOldValue() == State.ABORTED) { + changeProgress(+1, 0); + } + if(p != null) { + p.setVisible(p.getJob().getState() != State.FINISHED); + p.revalidate(); + } + } else if("message".equals(name)) { + if(p != null) { + JProgressBar bar = p.getBar(); + String message = p.getJob().getMessage(); + bar.setStringPainted(message != null); + bar.setString(message); + } + } + } else if(evt.getSource() == d) { + if("jobs".equals(name)) { + IndexedPropertyChangeEvent ev = (IndexedPropertyChangeEvent) evt; + int index = ev.getIndex(); + + DownloadJob oldValue = (DownloadJob) ev.getOldValue(); + if(oldValue != null) removeJob(index, oldValue); + + DownloadJob newValue = (DownloadJob) ev.getNewValue(); + if(newValue != null) addJob(index, newValue); + } + } + } + } + + private synchronized void addJob(int index, DownloadJob job) { + job.addPropertyChangeListener(l); + changeProgress(0, +1); + DownloadPanel p = new DownloadPanel(job); + progresses.put(job, p); + panel.add(p, index); + panel.revalidate(); + } + + private synchronized void removeJob(int index, DownloadJob job) { + assert progresses.get(job) == panel.getComponent(index); + job.removePropertyChangeListener(l); + changeProgress(0, -1); + progresses.remove(job); + panel.remove(index); + panel.revalidate(); + } + + private synchronized void changeProgress(int progress, int total) { + progress += model.getValue(); + total += model.getMaximum(); + model.setMaximum(total); + model.setValue(progress); + this.progress.setStringPainted(true); + this.progress.setString(progress + "/" + total); + } + + private class DownloadPanel extends JPanel { + private static final long serialVersionUID = 1187986738303477168L; + + private DownloadJob job; + private JProgressBar bar; + + public DownloadPanel(DownloadJob job) { + super(new BorderLayout()); + this.job = job; + + setBorder(BorderFactory.createTitledBorder(job.getName())); + add(bar = new JProgressBar(job.getProgress())); + JButton b = new JButton("X"); + b.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + switch(getJob().getState()) { + case NEW: + case WORKING: + getJob().setState(State.ABORTED); + } + } + }); + add(b, BorderLayout.EAST); + + if(job.getState() == State.FINISHED | job.getState() == State.ABORTED) { + changeProgress(+1, 0); + } + setVisible(job.getState() != State.FINISHED); + + String message = job.getMessage(); + bar.setStringPainted(message != null); + bar.setString(message); + + Dimension d = getPreferredSize(); + d.width = Integer.MAX_VALUE; + setMaximumSize(d); +// d.width = 500; +// setMinimumSize(d); + } + + public DownloadJob getJob() { + return job; + } + + public JProgressBar getBar() { + return bar; + } + } +} diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/DownloadJob.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/DownloadJob.java new file mode 100644 index 00000000000..bdd95bd4c4e --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/DownloadJob.java @@ -0,0 +1,213 @@ +/** + * DownloadJob.java + * + * Created on 25.08.2010 + */ + +package org.mage.plugins.card.dl; + + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Proxy; +import java.net.URL; +import java.net.URLConnection; + +import javax.swing.BoundedRangeModel; +import javax.swing.DefaultBoundedRangeModel; + +import org.mage.plugins.card.dl.beans.properties.Property; +import org.mage.plugins.card.dl.lm.AbstractLaternaBean; + + +/** + * The class DownloadJob. + * + * @version V0.0 25.08.2010 + * @author Clemens Koza + */ +public class DownloadJob extends AbstractLaternaBean { + public static enum State { + NEW, WORKING, FINISHED, ABORTED; + } + + private final String name; + private final Source source; + private final Destination destination; + private final Property state = properties.property("state", State.NEW); + private final Property message = properties.property("message"); + private final Property error = properties.property("error"); + private final BoundedRangeModel progress = new DefaultBoundedRangeModel(); + + public DownloadJob(String name, Source source, Destination destination) { + this.name = name; + this.source = source; + this.destination = destination; + } + + /** + * Sets the job's state. If the state is {@link State#ABORTED}, it instead sets the error to "ABORTED" + */ + public void setState(State state) { + if(state == State.ABORTED) setError("ABORTED"); + else this.state.setValue(state); + } + + /** + * Sets the job's state to {@link State#ABORTED} and the error message to the given message. Logs a warning + * with the given message. + */ + public void setError(String message) { + setError(message, null); + } + + /** + * Sets the job's state to {@link State#ABORTED} and the error to the given exception. Logs a warning with the + * given exception. + */ + public void setError(Exception error) { + setError(null, error); + } + + /** + * Sets the job's state to {@link State#ABORTED} and the error to the given exception. Logs a warning with the + * given message and exception. + */ + public void setError(String message, Exception error) { + if(message == null) message = error.toString(); + log.warn(message, error); + this.state.setValue(State.ABORTED); + this.error.setValue(error); + this.message.setValue(message); + } + + /** + * Sets the job's message. + */ + public void setMessage(String message) { + this.message.setValue(message); + } + + public BoundedRangeModel getProgress() { + return progress; + } + + public State getState() { + return state.getValue(); + } + + public Exception getError() { + return error.getValue(); + } + + public String getMessage() { + return message.getValue(); + } + + + public String getName() { + return name; + } + + public Source getSource() { + return source; + } + + public Destination getDestination() { + return destination; + } + + public static Source fromURL(final String url) { + return fromURL(null, url); + } + + public static Source fromURL(final URL url) { + return fromURL(null, url); + } + + public static Source fromURL(final Proxy proxy, final String url) { + return new Source() { + private URLConnection c; + + public URLConnection getConnection() throws IOException { + if(c == null) c = proxy == null? new URL(url).openConnection():new URL(url).openConnection(proxy); + return c; + } + + @Override + public InputStream open() throws IOException { + return getConnection().getInputStream(); + } + + @Override + public int length() throws IOException { + return getConnection().getContentLength(); + } + }; + } + + public static Source fromURL(final Proxy proxy, final URL url) { + return new Source() { + private URLConnection c; + + public URLConnection getConnection() throws IOException { + if(c == null) c = proxy == null? url.openConnection():url.openConnection(proxy); + return c; + } + + @Override + public InputStream open() throws IOException { + return getConnection().getInputStream(); + } + + @Override + public int length() throws IOException { + return getConnection().getContentLength(); + } + }; + } + + public static Destination toFile(final String file) { + return toFile(new File(file)); + } + + public static Destination toFile(final File file) { + return new Destination() { + @Override + public OutputStream open() throws IOException { + File parent = file.getAbsoluteFile().getParentFile(); + //Trying to create the directory before checking it exists makes it threadsafe + if(!parent.mkdirs() && !parent.exists()) throw new IOException(parent + + ": directory could not be created"); + return new FileOutputStream(file); + } + + @Override + public boolean exists() { + return file.isFile(); + } + + @Override + public void delete() throws IOException { + if(file.exists() && !file.delete()) throw new IOException(file + " couldn't be deleted"); + } + }; + } + + public static interface Source { + public InputStream open() throws IOException; + + public int length() throws IOException; + } + + public static interface Destination { + public OutputStream open() throws IOException; + + public boolean exists() throws IOException; + + public void delete() throws IOException; + } +} diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/Downloader.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/Downloader.java new file mode 100644 index 00000000000..e00ccf2f840 --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/Downloader.java @@ -0,0 +1,157 @@ +/** + * Downloader.java + * + * Created on 25.08.2010 + */ + +package org.mage.plugins.card.dl; + + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.swing.BoundedRangeModel; + +import org.apache.log4j.Logger; +import org.jetlang.channels.Channel; +import org.jetlang.channels.MemoryChannel; +import org.jetlang.core.Callback; +import org.jetlang.core.Disposable; +import org.jetlang.fibers.Fiber; +import org.jetlang.fibers.PoolFiberFactory; +import org.mage.plugins.card.dl.DownloadJob.Destination; +import org.mage.plugins.card.dl.DownloadJob.Source; +import org.mage.plugins.card.dl.DownloadJob.State; +import org.mage.plugins.card.dl.lm.AbstractLaternaBean; + + + +/** + * The class Downloader. + * + * @version V0.0 25.08.2010 + * @author Clemens Koza + */ +public class Downloader extends AbstractLaternaBean implements Disposable { + + private static final Logger log = Logger.getLogger(Downloader.class); + + private final List jobs = properties.list("jobs"); + private final Channel channel = new MemoryChannel(); + + private final ExecutorService pool = Executors.newCachedThreadPool(); + private final List fibers = new ArrayList(); + + public Downloader() { + PoolFiberFactory f = new PoolFiberFactory(pool); + //subscribe multiple fibers for parallel execution + for(int i = 0, numThreads = 10; i < numThreads; i++) { + Fiber fiber = f.create(); + fiber.start(); + fibers.add(fiber); + channel.subscribe(fiber, new DownloadCallback()); + } + } + + @Override + public void dispose() { + for(DownloadJob j:getJobs()) { + switch(j.getState()) { + case NEW: + case WORKING: + j.setState(State.ABORTED); + } + } + + for(Fiber f:fibers) + f.dispose(); + pool.shutdown(); + } + + @Override + protected void finalize() throws Throwable { + dispose(); + super.finalize(); + } + + public void add(DownloadJob job) { + if(job.getState() == State.WORKING) throw new IllegalArgumentException("Job already running"); + if(job.getState() == State.FINISHED) throw new IllegalArgumentException("Job already finished"); + job.setState(State.NEW); + jobs.add(job); + channel.publish(job); + } + + public List getJobs() { + return jobs; + } + + /** + * Performs the download job: Transfers data from {@link Source} to {@link Destination} and updates the + * download job's state to reflect the progress. + */ + private class DownloadCallback implements Callback { + @Override + public void onMessage(DownloadJob job) { + //the job won't be processed by multiple threads + synchronized(job) { + if(job.getState() != State.NEW) return; + job.setState(State.WORKING); + } + try { + Source src = job.getSource(); + Destination dst = job.getDestination(); + BoundedRangeModel progress = job.getProgress(); + + if(dst.exists()) { + progress.setMaximum(1); + progress.setValue(1); + } else { + progress.setMaximum(src.length()); + InputStream is = new BufferedInputStream(src.open()); + try { + OutputStream os = new BufferedOutputStream(dst.open()); + try { + byte[] buf = new byte[8 * 1024]; + int total = 0; + for(int len; (len = is.read(buf)) != -1;) { + if(job.getState() == State.ABORTED) throw new IOException("Job was aborted"); + progress.setValue(total += len); + os.write(buf, 0, len); + } + } catch(IOException ex) { + try { + dst.delete(); + } catch(IOException ex1) { + log.warn("While deleting", ex1); + } + throw ex; + } finally { + try { + os.close(); + } catch(IOException ex) { + log.warn("While closing", ex); + } + } + } finally { + try { + is.close(); + } catch(IOException ex) { + log.warn("While closing", ex); + } + } + } + job.setState(State.FINISHED); + } catch(IOException ex) { + job.setError(ex); + } + } + } +} diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/AbstractBoundBean.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/AbstractBoundBean.java new file mode 100644 index 00000000000..82f551c6fc7 --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/AbstractBoundBean.java @@ -0,0 +1,37 @@ +/** + * AbstractBoundBean.java + * + * Created on 24.08.2010 + */ + +package org.mage.plugins.card.dl.beans; + + +import java.beans.PropertyChangeListener; + + +/** + * The class AbstractBoundBean. + * + * @version V0.0 24.08.2010 + * @author Clemens Koza + */ +public abstract class AbstractBoundBean implements BoundBean { + protected PropertyChangeSupport s = new PropertyChangeSupport(this); + + public void addPropertyChangeListener(PropertyChangeListener listener) { + s.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + s.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + s.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + s.removePropertyChangeListener(propertyName, listener); + } +} diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/BoundBean.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/BoundBean.java new file mode 100644 index 00000000000..a0a87ba9455 --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/BoundBean.java @@ -0,0 +1,27 @@ +/** + * BoundBean.java + * + * Created on 24.08.2010 + */ + +package org.mage.plugins.card.dl.beans; + + +import java.beans.PropertyChangeListener; + + +/** + * The class BoundBean. + * + * @version V0.0 24.08.2010 + * @author Clemens Koza + */ +public interface BoundBean { + public void addPropertyChangeListener(PropertyChangeListener listener); + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener); + + public void removePropertyChangeListener(PropertyChangeListener listener); + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener); +} diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/EventListenerList.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/EventListenerList.java new file mode 100644 index 00000000000..2814e8dbbb1 --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/EventListenerList.java @@ -0,0 +1,121 @@ +/** + * EventListenerList.java + * + * Created on 08.04.2010 + */ + +package org.mage.plugins.card.dl.beans; + + +import static java.util.Arrays.*; + +import java.util.ArrayList; +import java.util.EventListener; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +import com.google.common.base.Function; +import com.google.common.collect.AbstractIterator; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + + +/** + * The class EventListenerList. + * + * @version V0.0 08.04.2010 + * @author Clemens Koza + */ +public class EventListenerList extends javax.swing.event.EventListenerList { + private static final long serialVersionUID = -7545754245081842909L; + + /** + * Returns an iterable over all listeners for the specified classes. the listener classes are in the specified + * order. for every class, listeners are in the reverse order of registering. A listener contained multiple + * times (for a single or multiple classes) is only returned the first time it occurs. + */ + public Iterable getIterable(final Class... listenerClass) { + //transform class -> iterable + List> l = Lists.transform(asList(listenerClass), new ClassToIterableFunction()); + + //compose iterable (use an arraylist to memoize the function's results) + final Iterable it = Iterables.concat(new ArrayList>(l)); + + //transform to singleton iterators + return new Iterable() { + public Iterator iterator() { + return new SingletonIterator(it.iterator()); + } + }; + } + + /** + * Returns an iterator over all listeners for the specified classes. the listener classes are in the specified + * order. for every class, listeners are in the reverse order of registering. A listener contained multiple + * times (for a single or multiple classes) is only returned the first time it occurs. + */ + public Iterator getIterator(Class... listenerClass) { + return getIterable(listenerClass).iterator(); + } + + /** + * Iterates backwards over the listeners registered for a class by using the original array. The Listener runs + * backwards, just as listener notification usually works. + */ + private class ListenerIterator extends AbstractIterator { + private final Class listenerClass; + private Object[] listeners = listenerList; + private int index = listeners.length; + + private ListenerIterator(Class listenerClass) { + this.listenerClass = listenerClass; + } + + @Override + @SuppressWarnings("unchecked") + protected T computeNext() { + for(index -= 2; index >= 0; index -= 2) { + if(listenerClass == listeners[index]) return (T) listeners[index + 1]; + } + return endOfData(); + } + } + + /** + * Transforms a class to the associated listener iterator + */ + private class ClassToIterableFunction implements Function, Iterable> { + + public Iterable apply(final Class from) { + return new Iterable() { + + public Iterator iterator() { + return new ListenerIterator(from); + } + }; + } + } + + /** + * Filters the delegate iterator so that every but the first occurrence of every element is ignored. + */ + private static class SingletonIterator extends AbstractIterator { + private Iterator it; + private HashSet previous = new HashSet(); + + public SingletonIterator(Iterator it) { + this.it = it; + } + + + @Override + protected T computeNext() { + while(it.hasNext()) { + T next = it.next(); + if(previous.add(next)) return next; + } + return endOfData(); + } + } +} diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/PropertyChangeSupport.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/PropertyChangeSupport.java new file mode 100644 index 00000000000..961f408ba61 --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/PropertyChangeSupport.java @@ -0,0 +1,31 @@ +/** + * PropertyChangeSupport.java + * + * Created on 16.07.2010 + */ + +package org.mage.plugins.card.dl.beans; + + + + +/** + * The class PropertyChangeSupport. + * + * @version V0.0 16.07.2010 + * @author Clemens Koza + */ +public class PropertyChangeSupport extends java.beans.PropertyChangeSupport { + private static final long serialVersionUID = -4241465377828790076L; + + private Object sourceBean; + + public PropertyChangeSupport(Object sourceBean) { + super(sourceBean); + this.sourceBean = sourceBean; + } + + public Object getSourceBean() { + return sourceBean; + } +} diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/package-info.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/package-info.java new file mode 100644 index 00000000000..f1cf99d2b69 --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/package-info.java @@ -0,0 +1,17 @@ +/** + * This package contains bean-related utilities, most importantly + *
    + *
  • {@link net.slightlymagic.beans.BoundBean} and {@link net.slightlymagic.beans.AbstractBoundBean}, an interface and an + * abstract class for easier property change support for bean classes
  • + *
  • {@link net.slightlymagic.beans.properties.Properties} and its implementations. These make it easy for beans + * to use delegates, by providing a centralized configuration for bean properties. For example, a {@link + * net.slightlymagic.beans.properties.bound.BoundProperties} object creates properties that do automatic property + * change notifications. What exact configuration is used is thus hidden from the delegate.
  • + *
  • The {@link net.slightlymagic.beans.relational.Relations} class provides relational properties that model + * bidirectional 1:1, 1:n and m:n relationships.
  • + *
+ */ + +package org.mage.plugins.card.dl.beans; + + diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/AbstractProperties.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/AbstractProperties.java new file mode 100644 index 00000000000..3f992d255c1 --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/AbstractProperties.java @@ -0,0 +1,47 @@ +/** + * AbstractProperties.java + * + * Created on 24.08.2010 + */ + +package org.mage.plugins.card.dl.beans.properties; + + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.mage.plugins.card.dl.beans.properties.basic.BasicProperty; + + +/** + * The class AbstractProperties. + * + * @version V0.0 24.08.2010 + * @author Clemens Koza + */ +public abstract class AbstractProperties implements Properties { + public Property property(String name, T value) { + return property(name, new BasicProperty(value)); + } + + public Property property(String name) { + return property(name, new BasicProperty()); + } + + public List list(String name) { + return list(name, new ArrayList()); + } + + public Set set(String name) { + return set(name, new HashSet()); + } + + public Map map(String name) { + return map(name, new HashMap()); + } + +} diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/AbstractProperty.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/AbstractProperty.java new file mode 100644 index 00000000000..13f105ebb23 --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/AbstractProperty.java @@ -0,0 +1,38 @@ +/** + * AbstractProperty.java + * + * Created on 24.08.2010 + */ + +package org.mage.plugins.card.dl.beans.properties; + + +import static java.lang.String.*; + + +/** + * The class AbstractProperty. + * + * @version V0.0 24.08.2010 + * @author Clemens Koza + */ +public abstract class AbstractProperty implements Property { + @Override + public int hashCode() { + T value = getValue(); + return value == null? 0:value.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof Property)) return false; + Object value = getValue(); + Object other = ((Property) obj).getValue(); + return value == other || (value != null && value.equals(other)); + } + + @Override + public String toString() { + return valueOf(getValue()); + } +} diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/CompoundProperties.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/CompoundProperties.java new file mode 100644 index 00000000000..cd751cb7fd5 --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/CompoundProperties.java @@ -0,0 +1,61 @@ +/** + * CompoundProperties.java + * + * Created on 24.08.2010 + */ + +package org.mage.plugins.card.dl.beans.properties; + + +import static java.util.Arrays.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + + +/** + * The class CompoundProperties. + * + * @version V0.0 24.08.2010 + * @author Clemens Koza + */ +public class CompoundProperties extends AbstractProperties { + private List delegates; + + public CompoundProperties(Properties... delegates) { + this.delegates = asList(delegates); + Collections.reverse(this.delegates); + } + + public CompoundProperties(List delegates) { + this.delegates = new ArrayList(delegates); + Collections.reverse(this.delegates); + } + + public Property property(String name, Property property) { + for(Properties p:delegates) + property = p.property(name, property); + return property; + } + + public List list(String name, List list) { + for(Properties p:delegates) + list = p.list(name, list); + return list; + } + + public Set set(String name, Set set) { + for(Properties p:delegates) + set = p.set(name, set); + return set; + } + + public Map map(String name, Map map) { + for(Properties p:delegates) + map = p.map(name, map); + return map; + } +} diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/Properties.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/Properties.java new file mode 100644 index 00000000000..80d45f7494c --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/Properties.java @@ -0,0 +1,44 @@ +/** + * Properties.java + * + * Created on 24.08.2010 + */ + +package org.mage.plugins.card.dl.beans.properties; + + +import java.beans.PropertyChangeListener; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.mage.plugins.card.dl.beans.properties.bound.BoundProperties; + + +/** + * The class Properties. A Properties object is a factory for bean properties. For example, the + * {@link BoundProperties} class produces properties that can be observed using {@link PropertyChangeListener}s. + * + * @version V0.0 24.08.2010 + * @author Clemens Koza + */ +public interface Properties { + public Property property(String name, Property property); + + public List list(String name, List list); + + public Set set(String name, Set set); + + public Map map(String name, Map map); + + + public Property property(String name, T value); + + public Property property(String name); + + public List list(String name); + + public Set set(String name); + + public Map map(String name); +} diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/Property.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/Property.java new file mode 100644 index 00000000000..47668e4d372 --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/Property.java @@ -0,0 +1,32 @@ +/** + * Property.java + * + * Created on 24.08.2010 + */ + +package org.mage.plugins.card.dl.beans.properties; + + +/** + * The class Property. + * + * @version V0.0 24.08.2010 + * @author Clemens Koza + */ +public interface Property { + public void setValue(T value); + + public T getValue(); + + /** + * A property's hash code is its value's hashCode, or {@code null} if the value is null. + */ + @Override + public int hashCode(); + + /** + * Two properties are equal if their values are equal. + */ + @Override + public boolean equals(Object obj); +} diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/basic/BasicProperties.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/basic/BasicProperties.java new file mode 100644 index 00000000000..a7bb00d54de --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/basic/BasicProperties.java @@ -0,0 +1,40 @@ +/** + * BoundProperties.java + * + * Created on 24.08.2010 + */ + +package org.mage.plugins.card.dl.beans.properties.basic; + + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.mage.plugins.card.dl.beans.properties.AbstractProperties; +import org.mage.plugins.card.dl.beans.properties.Property; + + +/** + * The class BoundProperties. + * + * @version V0.0 24.08.2010 + * @author Clemens Koza + */ +public class BasicProperties extends AbstractProperties { + public Property property(String name, Property value) { + return value; + } + + public List list(String name, List list) { + return list; + } + + public Set set(String name, Set set) { + return set; + } + + public Map map(String name, Map map) { + return map; + } +} diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/basic/BasicProperty.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/basic/BasicProperty.java new file mode 100644 index 00000000000..388d2c25734 --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/basic/BasicProperty.java @@ -0,0 +1,37 @@ +/** + * BasicProperty.java + * + * Created on 16.07.2010 + */ + +package org.mage.plugins.card.dl.beans.properties.basic; + + +import org.mage.plugins.card.dl.beans.properties.AbstractProperty; + + +/** + * The class BasicProperty. + * + * @version V0.0 16.07.2010 + * @author Clemens Koza + */ +public class BasicProperty extends AbstractProperty { + private T value; + + public BasicProperty() { + this(null); + } + + public BasicProperty(T initialValue) { + value = initialValue; + } + + public void setValue(T value) { + this.value = value; + } + + public T getValue() { + return value; + } +} diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/bound/BoundProperties.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/bound/BoundProperties.java new file mode 100644 index 00000000000..4ed79704eb5 --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/bound/BoundProperties.java @@ -0,0 +1,56 @@ +/** + * BoundProperties.java + * + * Created on 24.08.2010 + */ + +package org.mage.plugins.card.dl.beans.properties.bound; + + +import static org.mage.plugins.card.dl.beans.collections.ListenableCollections.listenableList; +import static org.mage.plugins.card.dl.beans.collections.ListenableCollections.listenableMap; +import static org.mage.plugins.card.dl.beans.collections.ListenableCollections.listenableSet; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.mage.plugins.card.dl.beans.PropertyChangeSupport; +import org.mage.plugins.card.dl.beans.properties.AbstractProperties; +import org.mage.plugins.card.dl.beans.properties.Property; + + +/** + * The class BoundProperties. + * + * @version V0.0 24.08.2010 + * @author Clemens Koza + */ +public class BoundProperties extends AbstractProperties { + public final PropertyChangeSupport s; + + public BoundProperties(Object sourceBean) { + this(new PropertyChangeSupport(sourceBean)); + } + + public BoundProperties(PropertyChangeSupport s) { + if(s == null) throw new IllegalArgumentException("s == null"); + this.s = s; + } + + public Property property(String name, Property property) { + return new BoundProperty(s, name, property); + } + + public List list(String name, List list) { + return listenableList(list, new PropertyChangeListListener(s, name)); + } + + public Set set(String name, Set set) { + return listenableSet(set, new PropertyChangeSetListener(s, set, name)); + } + + public Map map(String name, Map map) { + return listenableMap(map, new PropertyChangeMapListener(s, map, name)); + } +} diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/bound/BoundProperty.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/bound/BoundProperty.java new file mode 100644 index 00000000000..4f85a026efb --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/bound/BoundProperty.java @@ -0,0 +1,44 @@ +/** + * BasicProperty.java + * + * Created on 16.07.2010 + */ + +package org.mage.plugins.card.dl.beans.properties.bound; + + +import java.beans.PropertyChangeSupport; + +import org.mage.plugins.card.dl.beans.properties.AbstractProperty; +import org.mage.plugins.card.dl.beans.properties.Property; + + +/** + * The class BasicProperty. + * + * @version V0.0 16.07.2010 + * @author Clemens Koza + */ +public class BoundProperty extends AbstractProperty { + private PropertyChangeSupport s; + private String name; + private Property property; + + public BoundProperty(PropertyChangeSupport s, String name, Property property) { + if(property == null) throw new IllegalArgumentException(); + this.s = s; + this.name = name; + this.property = property; + + } + + public void setValue(T value) { + T old = getValue(); + property.setValue(value); + s.firePropertyChange(name, old, getValue()); + } + + public T getValue() { + return property.getValue(); + } +} diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/bound/PropertyChangeListListener.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/bound/PropertyChangeListListener.java new file mode 100644 index 00000000000..54b34c6a3fa --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/bound/PropertyChangeListListener.java @@ -0,0 +1,43 @@ +/** + * PropertyChangeListListener.java + * + * Created on 16.07.2010 + */ + +package org.mage.plugins.card.dl.beans.properties.bound; + +import org.mage.plugins.card.dl.beans.PropertyChangeSupport; +import org.mage.plugins.card.dl.beans.collections.ListenableCollections.ListListener; + + + + +/** + * The class PropertyChangeListListener. + * + * @version V0.0 16.07.2010 + * @author Clemens Koza + */ +public class PropertyChangeListListener implements ListListener { + private static final long serialVersionUID = 625853864429729560L; + + private PropertyChangeSupport s; + private String propertyName; + + public PropertyChangeListListener(PropertyChangeSupport s, String propertyName) { + this.s = s; + this.propertyName = propertyName; + } + + public void add(int index, E newValue) { + s.fireIndexedPropertyChange(propertyName, index, null, newValue); + } + + public void set(int index, E oldValue, E newValue) { + s.fireIndexedPropertyChange(propertyName, index, oldValue, newValue); + } + + public void remove(int index, E oldValue) { + s.fireIndexedPropertyChange(propertyName, index, oldValue, null); + } +} diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/bound/PropertyChangeMapListener.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/bound/PropertyChangeMapListener.java new file mode 100644 index 00000000000..c43a78944d4 --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/bound/PropertyChangeMapListener.java @@ -0,0 +1,126 @@ +/** + * PropertyChangeMapListener.java + * + * Created on 16.07.2010 + */ + +package org.mage.plugins.card.dl.beans.properties.bound; + + +import java.beans.PropertyChangeEvent; +import java.util.Map; + +import org.mage.plugins.card.dl.beans.PropertyChangeSupport; +import org.mage.plugins.card.dl.beans.collections.ListenableCollections.MapListener; + + +/** + * The class PropertyChangeMapListener. This listener alway fires events with {@link Map} -> {@link Map} as the + * value parameters, as nonindexed collection properties. The events will be {@link MapEvent} instances. + * + * @version V0.0 16.07.2010 + * @author Clemens Koza + */ +public class PropertyChangeMapListener implements MapListener { + private static final long serialVersionUID = 625853864429729560L; + + private PropertyChangeSupport s; + private Map map; + private String propertyName; + + public PropertyChangeMapListener(PropertyChangeSupport s, Map map, String propertyName) { + this.s = s; + this.map = map; + this.propertyName = propertyName; + } + + public void put(K key, V newValue) { + s.firePropertyChange(new MapPutEvent(s.getSourceBean(), propertyName, map, key, newValue)); + } + + public void set(K key, V oldValue, V newValue) { + s.firePropertyChange(new MapSetEvent(s.getSourceBean(), propertyName, map, key, oldValue, newValue)); + } + + public void remove(K key, V oldValue) { + s.firePropertyChange(new MapRemoveEvent(s.getSourceBean(), propertyName, map, key, oldValue)); + } + + public static abstract class MapEvent extends PropertyChangeEvent { + private static final long serialVersionUID = -651568020675693544L; + + private Map map; + private K key; + + public MapEvent(Object source, String propertyName, Map map, K key) { + super(source, propertyName, null, null); + this.map = map; + this.key = key; + } + + @Override + public Map getOldValue() { + //old and new value must not be equal + return null; + } + + @Override + public Map getNewValue() { + return map; + } + + public K getKey() { + return key; + } + } + + public static class MapPutEvent extends MapEvent { + private static final long serialVersionUID = 6006291474676939650L; + + private V newElement; + + public MapPutEvent(Object source, String propertyName, Map map, K key, V newElement) { + super(source, propertyName, map, key); + this.newElement = newElement; + } + + public V getNewElement() { + return newElement; + } + } + + public static class MapSetEvent extends MapEvent { + private static final long serialVersionUID = -2419438379909500079L; + + private V oldElement, newElement; + + public MapSetEvent(Object source, String propertyName, Map map, K key, V oldElement, V newElement) { + super(source, propertyName, map, key); + this.oldElement = oldElement; + this.newElement = newElement; + } + + public V getOldElement() { + return oldElement; + } + + public V getNewElement() { + return newElement; + } + } + + public static class MapRemoveEvent extends MapEvent { + private static final long serialVersionUID = -2644879706878221895L; + + private V oldElement; + + public MapRemoveEvent(Object source, String propertyName, Map map, K key, V oldElement) { + super(source, propertyName, map, key); + this.oldElement = oldElement; + } + + public V getOldElement() { + return oldElement; + } + } +} diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/bound/PropertyChangeSetListener.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/bound/PropertyChangeSetListener.java new file mode 100644 index 00000000000..328962e29d2 --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/beans/properties/bound/PropertyChangeSetListener.java @@ -0,0 +1,96 @@ +/** + * PropertyChangeSetListener.java + * + * Created on 16.07.2010 + */ + +package org.mage.plugins.card.dl.beans.properties.bound; + + +import java.beans.PropertyChangeEvent; +import java.util.Set; + +import org.mage.plugins.card.dl.beans.PropertyChangeSupport; +import org.mage.plugins.card.dl.beans.collections.ListenableCollections.SetListener; + + +/** + * The class PropertyChangeSetListener. This listener always fires events with {@link Set} -> {@link Set} as the + * value parameters, as nonindexed collection properties. The events will be {@link SetEvent} instances. + * + * @version V0.0 16.07.2010 + * @author Clemens Koza + */ +public class PropertyChangeSetListener implements SetListener { + private static final long serialVersionUID = 625853864429729560L; + + private PropertyChangeSupport s; + private Set set; + private String propertyName; + + public PropertyChangeSetListener(PropertyChangeSupport s, Set set, String propertyName) { + this.s = s; + this.set = set; + this.propertyName = propertyName; + } + + public void add(E newValue) { + s.firePropertyChange(new SetAddEvent(s.getSourceBean(), propertyName, set, newValue)); + } + + public void remove(E oldValue) { + s.firePropertyChange(new SetRemoveEvent(s.getSourceBean(), propertyName, set, oldValue)); + } + + public static abstract class SetEvent extends PropertyChangeEvent { + private static final long serialVersionUID = -651568020675693544L; + + private Set set; + + public SetEvent(Object source, String propertyName, Set set) { + super(source, propertyName, null, null); + this.set = set; + } + + @Override + public Set getOldValue() { + //old and new value must not be equal + return null; + } + + @Override + public Set getNewValue() { + return set; + } + } + + public static class SetAddEvent extends SetEvent { + private static final long serialVersionUID = 9041766866796759871L; + + private E newElement; + + public SetAddEvent(Object source, String propertyName, Set set, E newElement) { + super(source, propertyName, set); + this.newElement = newElement; + } + + public E getNewElement() { + return newElement; + } + } + + public static class SetRemoveEvent extends SetEvent { + private static final long serialVersionUID = -1315342339926392385L; + + private E oldElement; + + public SetRemoveEvent(Object source, String propertyName, Set set, E oldElement) { + super(source, propertyName, set); + this.oldElement = oldElement; + } + + public E getOldElement() { + return oldElement; + } + } +} diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/lm/AbstractLaternaBean.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/lm/AbstractLaternaBean.java new file mode 100644 index 00000000000..b44019add22 --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/lm/AbstractLaternaBean.java @@ -0,0 +1,27 @@ +/** + * AbstractLaternaBean.java + * + * Created on 25.08.2010 + */ + +package org.mage.plugins.card.dl.lm; + + +import org.apache.log4j.Logger; +import org.mage.plugins.card.dl.beans.AbstractBoundBean; +import org.mage.plugins.card.dl.beans.EventListenerList; +import org.mage.plugins.card.dl.beans.properties.Properties; +import org.mage.plugins.card.dl.beans.properties.bound.BoundProperties; + + +/** + * The class AbstractLaternaBean. + * + * @version V0.0 25.08.2010 + * @author Clemens Koza + */ +public class AbstractLaternaBean extends AbstractBoundBean { + protected static final Logger log = Logger.getLogger(AbstractLaternaBean.class); + protected Properties properties = new BoundProperties(s); + protected EventListenerList listeners = new EventListenerList(); +} diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/sources/GathererSymbols.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/sources/GathererSymbols.java new file mode 100644 index 00000000000..4b2c988c47c --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/dl/sources/GathererSymbols.java @@ -0,0 +1,81 @@ +/** + * GathererSymbols.java + * + * Created on 25.08.2010 + */ + +package org.mage.plugins.card.dl.sources; + + +import static java.lang.String.format; +import static org.mage.plugins.card.dl.DownloadJob.fromURL; +import static org.mage.plugins.card.dl.DownloadJob.toFile; + +import java.io.File; +import java.util.Iterator; + +import org.mage.plugins.card.dl.DownloadJob; + +import com.google.common.collect.AbstractIterator; + + +/** + * The class GathererSymbols. + * + * @version V0.0 25.08.2010 + * @author Clemens Koza + */ +public class GathererSymbols implements Iterable { + //TODO chaos and planeswalker symbol + //chaos: http://gatherer.wizards.com/Images/Symbols/chaos.gif + + private static final File outDir = new File("plugins/images/symbols"); + private static final String urlFmt = "http://gatherer.wizards.com/handlers/image.ashx?size=%1$s&name=%2$s&type=symbol"; + + private static final String[] sizes = {"small", "medium", "large"}; + + private static final String[] symbols = {"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", + + "X", "S", "T", "Q"}; + private static final int minNumeric = 0, maxNumeric = 16; + + @Override + public Iterator iterator() { + return new AbstractIterator() { + private int sizeIndex, symIndex, numeric = minNumeric; + private File dir = new File(outDir, sizes[sizeIndex]); + + @Override + protected DownloadJob computeNext() { + String sym; + if(symIndex < symbols.length) { + sym = symbols[symIndex++]; + } else if(numeric <= maxNumeric) { + sym = "" + (numeric++); + } else { + sizeIndex++; + if(sizeIndex == sizes.length) return endOfData(); + + symIndex = 0; + numeric = 0; + dir = new File(outDir, sizes[sizeIndex]); + return computeNext(); + } + String symbol = sym.replaceAll("/", ""); + File dst = new File(dir, symbol + ".jpg"); + + if(symbol.equals("T")) symbol = "tap"; + else if(symbol.equals("Q")) symbol = "untap"; + else if(symbol.equals("S")) symbol = "snow"; + + String url = format(urlFmt, sizes[sizeIndex], symbol); + + return new DownloadJob(sym, fromURL(url), toFile(dst)); + } + }; + } +} diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/images/DownloadPictures.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/images/DownloadPictures.java index 8a448fe06ae..d4021df9207 100644 --- a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/images/DownloadPictures.java +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/images/DownloadPictures.java @@ -1,10 +1,14 @@ package org.mage.plugins.card.images; +import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.EventQueue; +import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; @@ -42,6 +46,10 @@ import mage.cards.Card; import org.apache.log4j.Logger; import org.mage.plugins.card.CardUrl; import org.mage.plugins.card.constants.Constants; +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.GathererSymbols; import org.mage.plugins.card.properties.SettingsManager; import org.mage.plugins.card.utils.CardImageUtils; @@ -60,6 +68,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab private JLabel jLabel1; private static boolean offlineMode = false; private JCheckBox checkBox; + private JButton downloadSymbols; public static final Proxy.Type[] types = Proxy.Type.values(); @@ -70,10 +79,10 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab public static void startDownload(JFrame frame, Set allCards) { ArrayList cards = getNeededCards(allCards); - if (cards == null || cards.size() == 0) { + /*if (cards == null || cards.size() == 0) { JOptionPane.showMessageDialog(null, "All card pictures have been downloaded."); return; - } + }*/ DownloadPictures download = new DownloadPictures(cards); JDialog dlg = download.getDlg(frame); @@ -147,7 +156,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab jComboBox1.setAlignmentX(Component.LEFT_ALIGNMENT); p0.add(jComboBox1); p0.add(Box.createVerticalStrut(5)); - + // Start final JButton b = new JButton("Start download"); b.addActionListener(new ActionListener() { diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/utils/BufferedImageBuilder.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/utils/BufferedImageBuilder.java new file mode 100644 index 00000000000..cc0890cdc56 --- /dev/null +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/utils/BufferedImageBuilder.java @@ -0,0 +1,59 @@ +package org.mage.plugins.card.utils; + +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.awt.image.ImageObserver; + +public class BufferedImageBuilder { + + private static final int DEFAULT_IMAGE_TYPE = BufferedImage.TYPE_INT_RGB; + + public BufferedImage bufferImage(Image image) { + return bufferImage(image, DEFAULT_IMAGE_TYPE); + } + + public BufferedImage bufferImage(Image image, int type) { + BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), type); + Graphics2D g = bufferedImage.createGraphics(); + g.drawImage(image, null, null); + //waitForImage(bufferedImage); + return bufferedImage; + } + + private void waitForImage(BufferedImage bufferedImage) { + final ImageLoadStatus imageLoadStatus = new ImageLoadStatus(); + bufferedImage.getHeight(new ImageObserver() { + public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) { + if (infoflags == ALLBITS) { + imageLoadStatus.heightDone = true; + return true; + } + return false; + } + }); + bufferedImage.getWidth(new ImageObserver() { + public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) { + if (infoflags == ALLBITS) { + imageLoadStatus.widthDone = true; + return true; + } + return false; + } + }); + while (!imageLoadStatus.widthDone && !imageLoadStatus.heightDone) { + try { + Thread.sleep(300); + } catch (InterruptedException e) { + + } + } + } + + class ImageLoadStatus { + + public boolean widthDone = false; + public boolean heightDone = false; + } + +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index a9869b1dbea..787c8ed7836 100644 --- a/pom.xml +++ b/pom.xml @@ -36,6 +36,11 @@ Java Image Scaling Repository Released svn:https://java-image-scaling.googlecode.com/svn/repo/released + + jetlang.googlecode.com + Jetlang Repository for Maven + http://jetlang.googlecode.com/svn/repo/ +