Add Net Decks support

This commit is contained in:
drdev
2015-01-25 05:10:32 +00:00
parent f3a30793c5
commit 30fbe55ac3
25 changed files with 756 additions and 251 deletions

4
.gitattributes vendored
View File

@@ -16050,6 +16050,8 @@ forge-gui/res/lists/TypeLists.txt svneol=native#text/plain
forge-gui/res/lists/booster-images.txt svneol=native#text/plain
forge-gui/res/lists/boosterbox-images.txt -text
forge-gui/res/lists/fatpack-images.txt svneol=native#text/plain
forge-gui/res/lists/net-decks-commander.txt -text
forge-gui/res/lists/net-decks.txt -text
forge-gui/res/lists/precon-images.txt svneol=native#text/plain
forge-gui/res/lists/quest-opponent-icons.txt svneol=native#text/plain
forge-gui/res/lists/quest-pet-shop-icons.txt svneol=native#text/plain
@@ -17331,6 +17333,7 @@ forge-gui/src/main/java/forge/deck/DeckGeneratorTheme.java -text
forge-gui/src/main/java/forge/deck/DeckProxy.java -text
forge-gui/src/main/java/forge/deck/DeckType.java -text
forge-gui/src/main/java/forge/deck/DeckgenUtil.java -text
forge-gui/src/main/java/forge/deck/NetDeckCategory.java -text
forge-gui/src/main/java/forge/deck/RandomDeckGenerator.java -text
forge-gui/src/main/java/forge/deck/io/DeckPreferences.java -text
forge-gui/src/main/java/forge/deck/io/OldDeckParser.java -text
@@ -17339,6 +17342,7 @@ forge-gui/src/main/java/forge/download/GuiDownloadPrices.java -text
forge-gui/src/main/java/forge/download/GuiDownloadQuestImages.java -text
forge-gui/src/main/java/forge/download/GuiDownloadService.java -text
forge-gui/src/main/java/forge/download/GuiDownloadSetPicturesLQ.java -text
forge-gui/src/main/java/forge/download/GuiDownloadZipService.java -text
forge-gui/src/main/java/forge/error/BugReporter.java -text
forge-gui/src/main/java/forge/error/ExceptionHandler.java svneol=native#text/plain
forge-gui/src/main/java/forge/error/package-info.java svneol=native#text/plain

View File

@@ -23,6 +23,8 @@ import forge.assets.FSkinProp;
import forge.assets.ISkinImage;
import forge.control.GuiTimer;
import forge.deck.CardPool;
import forge.download.GuiDownloadService;
import forge.download.GuiDownloader;
import forge.error.BugReportDialog;
import forge.game.GameEntity;
import forge.game.GameEntityView;
@@ -50,6 +52,7 @@ import forge.toolbox.FOptionPane;
import forge.toolbox.FSkin;
import forge.toolbox.FSkin.SkinImage;
import forge.util.BuildInfo;
import forge.util.Callback;
import forge.util.FCollectionView;
import forge.util.FileUtil;
import forge.util.gui.SGuiChoose;
@@ -258,6 +261,11 @@ public class GuiDesktop implements IGuiBase {
return fc.getSelectedFile();
}
@Override
public void download(GuiDownloadService service, Callback<Boolean> callback) {
new GuiDownloader(service, callback);
}
@Override
public void copyToClipboard(String text) {
StringSelection ss = new StringSelection(text);

View File

@@ -33,13 +33,16 @@ public class DecksComboBox extends FComboBoxWrapper<DeckType> {
return new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
MouseUtil.setCursor(Cursor.WAIT_CURSOR);
DeckType newDeckType = (DeckType)getSelectedItem();
if (newDeckType != selectedDeckType) {
notifyDeckTypeSelected(newDeckType);
selectedDeckType = newDeckType;
Object selectedItem = getSelectedItem();
if (selectedItem instanceof DeckType) {
MouseUtil.setCursor(Cursor.WAIT_CURSOR);
DeckType newDeckType = (DeckType)selectedItem;
if (newDeckType != selectedDeckType) {
selectedDeckType = newDeckType;
notifyDeckTypeSelected(newDeckType);
}
MouseUtil.resetCursor();
}
MouseUtil.resetCursor();
}
};
}
@@ -68,4 +71,10 @@ public class DecksComboBox extends FComboBoxWrapper<DeckType> {
selectedDeckType = valueOf;
setSelectedItem(selectedDeckType);
}
@Override
public void setText(String text0) {
selectedDeckType = null; //ensure selecting current deck type again raises event
super.setText(text0);
}
}

View File

@@ -7,6 +7,7 @@ import forge.deck.Deck;
import forge.deck.DeckProxy;
import forge.deck.DeckType;
import forge.deck.DeckgenUtil;
import forge.deck.NetDeckCategory;
import forge.deck.RandomDeckGenerator;
import forge.game.GameType;
import forge.game.player.RegisteredPlayer;
@@ -38,6 +39,8 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener {
private DecksComboBox decksComboBox;
private DeckType selectedDeckType;
private ItemManagerContainer lstDecksContainer;
private NetDeckCategory netDeckCategory;
private boolean refreshingDeckType;
private final DeckManager lstDecks = new DeckManager(GameType.Constructed);
private final FLabel btnViewDeck = new FLabel.ButtonBuilder().text("View Deck").fontSize(14).build();
@@ -219,6 +222,26 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener {
});
}
private void updateNetDecks() {
if (netDeckCategory != null) {
decksComboBox.setText(netDeckCategory.toString());
}
lstDecks.setAllowMultipleSelections(false);
lstDecks.setPool(DeckProxy.getNetDecks(netDeckCategory));
lstDecks.setup(ItemManagerConfig.NET_DECKS);
btnRandom.setText("Random Deck");
btnRandom.setCommand(new UiCommand() {
@Override
public void run() {
DeckgenUtil.randomSelect(lstDecks);
}
});
lstDecks.setSelectedIndex(0);
}
public Deck getDeck() {
DeckProxy proxy = lstDecks.getSelectedItem();
return proxy.getDeck();
@@ -269,14 +292,36 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener {
}
public void setIsAi(boolean isAiDeck) {
this.isAi = isAiDeck;
isAi = isAiDeck;
}
/* (non-Javadoc)
* @see forge.gui.deckchooser.IDecksComboBoxListener#deckTypeSelected(forge.gui.deckchooser.DecksComboBoxEvent)
*/
@Override
public void deckTypeSelected(DecksComboBoxEvent ev) {
public void deckTypeSelected(final DecksComboBoxEvent ev) {
if (ev.getDeckType() == DeckType.NET_DECK && !refreshingDeckType) {
FThreads.invokeInBackgroundThread(new Runnable() { //needed for loading net decks
@Override
public void run() {
final NetDeckCategory category = NetDeckCategory.selectAndLoad(lstDecks.getGameType());
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
if (category == null) {
decksComboBox.setDeckType(selectedDeckType); //restore old selection if user cancels
if (selectedDeckType == DeckType.NET_DECK && netDeckCategory != null) {
decksComboBox.setText(netDeckCategory.toString());
}
return;
}
netDeckCategory = category;
refreshDecksList(DeckType.NET_DECK, true, ev);
}
});
}
});
return;
}
refreshDecksList(ev.getDeckType(), false, ev);
}
@@ -285,7 +330,9 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener {
selectedDeckType = deckType;
if (ev == null) {
refreshingDeckType = true;
decksComboBox.refresh(deckType);
refreshingDeckType = false;
}
lstDecks.setCaption(deckType.toString());
@@ -308,6 +355,9 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener {
case RANDOM_DECK:
updateRandom();
break;
case NET_DECK:
updateNetDecks();
break;
}
}
@@ -322,8 +372,15 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener {
}
private String getState() {
String deckType = decksComboBox.getDeckType().name();
StringBuilder state = new StringBuilder(deckType);
StringBuilder state = new StringBuilder();
if (decksComboBox.getDeckType() == null || decksComboBox.getDeckType() == DeckType.NET_DECK) {
//handle special case of net decks
if (netDeckCategory == null) { return ""; }
state.append(NetDeckCategory.PREFIX + netDeckCategory.getName());
}
else {
state.append(decksComboBox.getDeckType().name());
}
state.append(";");
joinSelectedDecks(state, SELECTED_DECK_DELIMITER);
return state.toString();
@@ -345,25 +402,20 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener {
}
}
/** Returns a clean name from the state that can be used for labels. */
public final String getStateForLabel() {
String deckType = decksComboBox.getDeckType().toString();
StringBuilder state = new StringBuilder(deckType);
state.append(": ");
joinSelectedDecks(state, ", ");
return state.toString();
}
private void restoreSavedState() {
DeckType oldDeckType = selectedDeckType;
if (stateSetting == null) {
//if can't restore saved state, just refresh deck list
refreshDecksList(selectedDeckType, true, null);
refreshDecksList(oldDeckType, true, null);
return;
}
String savedState = prefs.getPref(stateSetting);
refreshDecksList(getDeckTypeFromSavedState(savedState), true, null);
lstDecks.setSelectedStrings(getSelectedDecksFromSavedState(savedState));
if (!lstDecks.setSelectedStrings(getSelectedDecksFromSavedState(savedState))) {
//if can't select old decks, just refresh deck list
refreshDecksList(oldDeckType, true, null);
}
}
private DeckType getDeckTypeFromSavedState(String savedState) {
@@ -372,7 +424,12 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener {
return selectedDeckType;
}
else {
return DeckType.valueOf(savedState.split(";")[0]);
String deckType = savedState.split(";")[0];
if (deckType.startsWith(NetDeckCategory.PREFIX)) {
netDeckCategory = NetDeckCategory.selectAndLoad(lstDecks.getGameType(), deckType.substring(NetDeckCategory.PREFIX.length()));
return DeckType.NET_DECK;
}
return DeckType.valueOf(deckType);
}
}
catch (IllegalArgumentException ex) {

View File

@@ -23,6 +23,7 @@ import forge.UiCommand;
import forge.assets.FSkinProp;
import forge.gui.SOverlayUtils;
import forge.toolbox.*;
import forge.util.Callback;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
@@ -47,6 +48,10 @@ public class GuiDownloader extends DefaultBoundedRangeModel {
// Kill overlay
SOverlayUtils.hideOverlay();
if (callback != null) {
callback.run(btnStart.getText() == "OK"); //determine result based on whether download finished
}
}
};
@@ -58,9 +63,14 @@ public class GuiDownloader extends DefaultBoundedRangeModel {
private final FRadioButton radProxyHTTP = new FRadioButton("HTTP Proxy");
private final GuiDownloadService service;
private final Callback<Boolean> callback;
public GuiDownloader(GuiDownloadService service0) {
this(service0, null);
}
public GuiDownloader(GuiDownloadService service0, Callback<Boolean> callback0) {
service = service0;
callback = callback0;
String radConstraints = "w 100%!, h 30px!, gap 2% 0 0 10px";
JXButtonPanel grpPanel = new JXButtonPanel();

View File

@@ -52,7 +52,19 @@ public class FComboBox<E> extends SkinnedComboBox<E> implements IComboBox<E> {
private Border getDefaultBorder() {
return UIManager.getBorder("ComboBox.border");
}
public String getText() {
Object selectedItem = getSelectedItem();
if (selectedItem == null) {
return "";
}
return selectedItem.toString();
}
public void setText(String text0) {
setSelectedItem(null);
dataModel.setSelectedItem(text0); //use this to get around inability to set selected item that's not in items
}
public TextAlignment getTextAlignment() {
return textAlignment;
}
@@ -60,7 +72,7 @@ public class FComboBox<E> extends SkinnedComboBox<E> implements IComboBox<E> {
public void setTextAlignment(TextAlignment align) {
textAlignment = align;
}
public SkinFont getSkinFont() {
return this.skinFont;
}

View File

@@ -32,138 +32,145 @@ public class FComboBoxWrapper<E> implements IComboBox<E> {
public FComboBoxWrapper() {
super();
this.comboBox = new FComboBox<E>();
comboBox = new FComboBox<E>();
allWrappers.add(this);
}
public FComboBoxWrapper(E[] items) {
super();
this.comboBox = new FComboBox<E>(items);
comboBox = new FComboBox<E>(items);
allWrappers.add(this);
}
public FComboBoxWrapper(Vector<E> items) {
super();
this.comboBox = new FComboBox<E>(items);
comboBox = new FComboBox<E>(items);
allWrappers.add(this);
}
public FComboBoxWrapper(ComboBoxModel<E> aModel) {
super();
this.comboBox = new FComboBox<E>(aModel);
comboBox = new FComboBox<E>(aModel);
allWrappers.add(this);
}
public void addItem(E item) {
this.comboBox.addItem(item);
comboBox.addItem(item);
}
public void removeItem(E item) {
this.comboBox.removeItem(item);
comboBox.removeItem(item);
}
public void removeAllItems() {
this.comboBox.removeAllItems();
comboBox.removeAllItems();
}
@SuppressWarnings("unchecked")
public E getSelectedItem() {
Object res = this.comboBox.getSelectedItem();
Object res = comboBox.getSelectedItem();
return res == null ? null : (E) res;
}
public void setSelectedItem(Object item) {
this.comboBox.setSelectedItem(item);
comboBox.setSelectedItem(item);
}
public int getSelectedIndex() {
return this.comboBox.getSelectedIndex();
return comboBox.getSelectedIndex();
}
public void setSelectedIndex(int index) {
this.comboBox.setSelectedIndex(index);
comboBox.setSelectedIndex(index);
}
public String getText() {
return comboBox.getText();
}
public void setText(String text0) {
comboBox.setText(text0);
}
public void setMaximumRowCount(int count) {
this.comboBox.setMaximumRowCount(count);
comboBox.setMaximumRowCount(count);
}
public int getItemCount() {
return this.comboBox.getItemCount();
return comboBox.getItemCount();
}
public E getItemAt(int index) {
return this.comboBox.getItemAt(index);
return comboBox.getItemAt(index);
}
public void addActionListener(ActionListener l) {
this.comboBox.addActionListener(l);
comboBox.addActionListener(l);
}
public void addItemListener(ItemListener l) {
this.comboBox.addItemListener(l);
comboBox.addItemListener(l);
}
public void addKeyListener(KeyListener l) {
this.comboBox.addKeyListener(l);
comboBox.addKeyListener(l);
}
public void setRenderer(ListCellRenderer<? super E> aRenderer) {
this.comboBox.setRenderer(aRenderer);
comboBox.setRenderer(aRenderer);
}
public void setModel(ComboBoxModel<E> aModel) {
this.comboBox.setModel(aModel);
comboBox.setModel(aModel);
}
public void setTextAlignment(TextAlignment align) {
this.comboBox.setTextAlignment(align);
comboBox.setTextAlignment(align);
}
public void setSkinFont(SkinFont skinFont) {
this.comboBox.setSkinFont(skinFont);
comboBox.setSkinFont(skinFont);
}
@Override
public boolean isVisible() {
return this.comboBox.isVisible();
return comboBox.isVisible();
}
@Override
public void setVisible(boolean aFlag) {
this.comboBox.setVisible(aFlag);
comboBox.setVisible(aFlag);
}
@Override
public boolean isEnabled() {
return this.comboBox.isEnabled();
return comboBox.isEnabled();
}
@Override
public void setEnabled(boolean aFlag) {
this.comboBox.setEnabled(aFlag);
comboBox.setEnabled(aFlag);
}
public int getAutoSizeWidth() {
return this.comboBox.getAutoSizeWidth();
return comboBox.getAutoSizeWidth();
}
public void addTo(Container container) {
this.addTo(container, null);
addTo(container, null);
}
public void addTo(Container container, Object constraints0) {
container.add(this.comboBox, constraints0);
this.constraints = constraints0;
container.add(comboBox, constraints0);
constraints = constraints0;
}
//disguise as component for sake of rare places that need to access component in wrapper
//use addTo instead if you want constraints remembered after refreshing skin
public JComponent getComponent() {
return this.comboBox;
return comboBox;
}
private void refreshSkin() {
this.comboBox = refreshComboBoxSkin(this.comboBox, this.constraints);
comboBox = refreshComboBoxSkin(comboBox, constraints);
}
//refresh combo box skin by replacing it with a copy of itself

View File

@@ -1,6 +1,5 @@
package forge.toolbox;
import forge.FThreads;
import forge.interfaces.IProgressBar;
import javax.swing.*;
@@ -9,9 +8,6 @@ import java.util.Date;
/**
* A simple progress bar component using the Forge skin.
*
* Can show
*
*/
@SuppressWarnings("serial")
public class FProgressBar extends JProgressBar implements IProgressBar {
@@ -23,20 +19,13 @@ public class FProgressBar extends JProgressBar implements IProgressBar {
private boolean percentMode = false;
/** */
public FProgressBar() {
super();
reset();
setStringPainted(true);
}
/**
* Sets description on bar. Must be called from EDT.
*
* @param s0 &emsp; A description to prepend before statistics.
*/
public void setDescription(final String s0) {
FThreads.assertExecutedByEdt(true);
desc = s0;
setString(s0);
}
@@ -79,9 +68,8 @@ public class FProgressBar extends JProgressBar implements IProgressBar {
setString(sb.toString());
}
/** Resets the various values required for this class. Must be called from EDT. */
/** Resets the various values required for this class. */
public void reset() {
FThreads.assertExecutedByEdt(true);
setIndeterminate(true);
setValue(0);
tempVal = 0;
@@ -91,17 +79,14 @@ public class FProgressBar extends JProgressBar implements IProgressBar {
setShowCount(true);
}
/** @param b0 &emsp; Boolean, show the ETA statistic or not */
public void setShowETA(boolean b0) {
showETA = b0;
}
/** @param b0 &emsp; Boolean, show the ETA statistic or not */
public void setShowCount(boolean b0) {
showCount = b0;
}
/** */
private void calculateETA(int v0) {
float tempMillis = new Date().getTime();
float timePerUnit = (tempMillis - startMillis) / v0;
@@ -111,9 +96,7 @@ public class FProgressBar extends JProgressBar implements IProgressBar {
public boolean isPercentMode() {
return percentMode;
}
public void setPercentMode(boolean value) {
percentMode = value;
}
}

View File

@@ -27,6 +27,7 @@ import forge.deck.CardPool;
import forge.deck.Deck;
import forge.deck.FDeckViewer;
import forge.deck.FSideboardDialog;
import forge.download.GuiDownloadService;
import forge.error.BugReportDialog;
import forge.game.GameEntity;
import forge.game.GameEntityView;
@@ -40,12 +41,14 @@ import forge.player.PlayerControllerHuman;
import forge.properties.ForgeConstants;
import forge.screens.match.MatchController;
import forge.screens.quest.QuestMenu;
import forge.screens.settings.GuiDownloader;
import forge.sound.AudioClip;
import forge.sound.AudioMusic;
import forge.sound.IAudioClip;
import forge.sound.IAudioMusic;
import forge.toolbox.FOptionPane;
import forge.toolbox.GuiChoose;
import forge.util.Callback;
import forge.util.FCollectionView;
import forge.util.FileUtil;
import forge.util.MessageUtil;
@@ -291,6 +294,11 @@ public class GuiMobile implements IGuiBase {
return defaultFile; //TODO: Show dialog
}
@Override
public void download(GuiDownloadService service, Callback<Boolean> callback) {
new GuiDownloader(service, callback);
}
@Override
public void copyToClipboard(String text) {
Forge.getClipboard().setContents(text);

View File

@@ -1,29 +1,19 @@
package forge.assets;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.apache.commons.lang3.StringUtils;
import com.badlogic.gdx.Application.ApplicationType;
import com.badlogic.gdx.Gdx;
import com.esotericsoftware.minlog.Log;
import forge.FThreads;
import forge.Forge;
import forge.download.GuiDownloadZipService;
import forge.properties.ForgeConstants;
import forge.screens.SplashScreen;
import forge.toolbox.FProgressBar;
import forge.util.FileUtil;
import forge.util.gui.SOptionPane;
@@ -52,9 +42,10 @@ public class AssetsDownloader {
message += " If so, you may want to connect to wifi first. The download is around 6.5MB.";
}
if (SOptionPane.showConfirmDialog(message, "New Version Available", "Update Now", "Update Later")) {
String apkFile = downloadFile("update", "forge-android-" + version + "-signed-aligned.apk",
"http://cardforge.org/android/releases/forge/forge-gui-android/" + version + "/",
Forge.getDeviceAdapter().getDownloadsDir(), splashScreen.getProgressBar());
String filename = "forge-android-" + version + "-signed-aligned.apk";
String apkFile = new GuiDownloadZipService("", "update",
"http://cardforge.org/android/releases/forge/forge-gui-android/" + version + "/" + filename,
Forge.getDeviceAdapter().getDownloadsDir(), null, splashScreen.getProgressBar()).download(filename);
if (apkFile != null) {
Forge.getDeviceAdapter().openFile(apkFile);
Forge.exit(true);
@@ -136,7 +127,9 @@ public class AssetsDownloader {
return;
}
downloadAssets(splashScreen.getProgressBar());
new GuiDownloadZipService("", "resource files",
"http://cardforge.org/android/releases/forge/forge-gui-android/" + Forge.CURRENT_VERSION + "/" + "assets.zip",
ForgeConstants.ASSETS_DIR, ForgeConstants.RES_DIR, splashScreen.getProgressBar()).downloadAndUnzip();
FSkinFont.deleteCachedFiles(); //delete cached font files in case any skin's .ttf file changed
@@ -153,103 +146,4 @@ public class AssetsDownloader {
//so they don't need to be re-downloaded until you upgrade again
FileUtil.writeFile(versionFile, Forge.CURRENT_VERSION);
}
private static String downloadFile(final String desc, final String filename, final String sourceFolder, final String destFolder, final FProgressBar progressBar) {
progressBar.reset();
progressBar.setPercentMode(true);
progressBar.setDescription("Downloading " + desc);
try {
URL url = new URL(sourceFolder + filename);
URLConnection conn = url.openConnection();
conn.connect();
long contentLength = conn.getContentLength();
progressBar.setMaximum(100);
// input stream to read file - with 8k buffer
InputStream input = new BufferedInputStream(url.openStream(), 8192);
// output stream to write file
String destFile = destFolder + filename;
OutputStream output = new FileOutputStream(destFile);
int count;
long total = 0;
byte data[] = new byte[1024];
while ((count = input.read(data)) != -1) {
total += count;
progressBar.setValue((int)(100 * total / contentLength));
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
return destFile;
}
catch (final Exception ex) {
Log.error("Downloading " + desc, "Error downloading " + desc, ex);
}
return null;
}
private static void downloadAssets(final FProgressBar progressBar) {
String assetsFile = downloadFile("resource files", "assets.zip",
"http://cardforge.org/android/releases/forge/forge-gui-android/" + Forge.CURRENT_VERSION + "/",
ForgeConstants.ASSETS_DIR, progressBar);
if (assetsFile == null) { return; }
//if assets.zip downloaded successfully, unzip into destination folder
try {
File resDir = new File(ForgeConstants.RES_DIR);
if (resDir.exists()) {
//attempt to delete previous res directory if to be rebuilt
progressBar.reset();
progressBar.setDescription("Deleting old resource files...");
FileUtil.deleteDirectory(resDir);
}
ZipFile zipFile = new ZipFile(assetsFile);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
progressBar.reset();
progressBar.setPercentMode(true);
progressBar.setDescription("Unzipping resource files");
progressBar.setMaximum(zipFile.size());
int count = 0;
while (entries.hasMoreElements()) {
ZipEntry entry = (ZipEntry)entries.nextElement();
String path = ForgeConstants.ASSETS_DIR + entry.getName();
if (entry.isDirectory()) {
new File(path).mkdir();
progressBar.setValue(++count);
continue;
}
copyInputStream(zipFile.getInputStream(entry), new BufferedOutputStream(new FileOutputStream(path)));
progressBar.setValue(++count);
}
zipFile.close();
new File(assetsFile).delete();
}
catch (Exception e) {
e.printStackTrace();
}
}
public static final void copyInputStream(InputStream in, OutputStream out) throws IOException{
byte[] buffer = new byte[1024];
int len;
while((len = in.read(buffer)) >= 0) {
out.write(buffer, 0, len);
}
in.close();
out.close();
}
}

View File

@@ -41,6 +41,8 @@ public class FDeckChooser extends FScreen {
private DeckType selectedDeckType;
private boolean needRefreshOnActivate;
private Callback<Deck> callback;
private NetDeckCategory netDeckCategory;
private boolean refreshingDeckType;
private final DeckManager lstDecks;
private final FButton btnNewDeck = new FButton("New Deck");
@@ -261,6 +263,12 @@ public class FDeckChooser extends FScreen {
cmbDeckTypes.addItem(DeckType.COLOR_DECK);
cmbDeckTypes.addItem(DeckType.THEME_DECK);
cmbDeckTypes.addItem(DeckType.RANDOM_DECK);
cmbDeckTypes.addItem(DeckType.NET_DECK);
break;
case Commander:
cmbDeckTypes.addItem(DeckType.CUSTOM_DECK);
cmbDeckTypes.addItem(DeckType.RANDOM_DECK);
cmbDeckTypes.addItem(DeckType.NET_DECK);
break;
default:
cmbDeckTypes.addItem(DeckType.CUSTOM_DECK);
@@ -271,7 +279,32 @@ public class FDeckChooser extends FScreen {
restoreSavedState();
cmbDeckTypes.setChangedHandler(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
public void handleEvent(final FEvent e) {
if (cmbDeckTypes.getSelectedItem() == DeckType.NET_DECK && !refreshingDeckType) {
FThreads.invokeInBackgroundThread(new Runnable() { //needed for loading net decks
@Override
public void run() {
final NetDeckCategory category = NetDeckCategory.selectAndLoad(lstDecks.getGameType());
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
if (category == null) {
cmbDeckTypes.setSelectedItem(selectedDeckType); //restore old selection if user cancels
if (selectedDeckType == DeckType.NET_DECK && netDeckCategory != null) {
cmbDeckTypes.setText(netDeckCategory.toString());
}
return;
}
netDeckCategory = category;
refreshDecksList(DeckType.NET_DECK, true, e);
}
});
}
});
return;
}
refreshDecksList(cmbDeckTypes.getSelectedItem(), false, e);
}
});
@@ -493,6 +526,32 @@ public class FDeckChooser extends FScreen {
});
}
private void updateNetDecks() {
if (netDeckCategory != null) {
cmbDeckTypes.setText(netDeckCategory.toString());
}
lstDecks.setSelectionSupport(1, 1);
lstDecks.setPool(DeckProxy.getNetDecks(netDeckCategory));
lstDecks.setup(ItemManagerConfig.NET_DECKS);
btnNewDeck.setText("New Deck");
btnNewDeck.setWidth(btnEditDeck.getWidth());
btnEditDeck.setVisible(true);
btnViewDeck.setVisible(true);
btnRandom.setText("Random Deck");
btnRandom.setWidth(btnNewDeck.getWidth());
btnRandom.setLeft(getWidth() - PADDING - btnRandom.getWidth());
btnRandom.setCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
DeckgenUtil.randomSelect(lstDecks);
accept();
}
});
}
public Deck getDeck() {
DeckProxy proxy = lstDecks.getSelectedItem();
if (proxy == null) { return null; }
@@ -530,7 +589,9 @@ public class FDeckChooser extends FScreen {
selectedDeckType = deckType;
if (e == null) {
refreshingDeckType = true;
cmbDeckTypes.setSelectedItem(deckType);
refreshingDeckType = false;
}
if (deckType == null) { return; }
@@ -553,6 +614,9 @@ public class FDeckChooser extends FScreen {
case RANDOM_DECK:
updateRandom();
break;
case NET_DECK:
updateNetDecks();
break;
}
if (e != null) { //set default list selection if from combo box change event
@@ -577,8 +641,15 @@ public class FDeckChooser extends FScreen {
}
private String getState() {
String deckType = cmbDeckTypes.getSelectedItem().name();
StringBuilder state = new StringBuilder(deckType);
StringBuilder state = new StringBuilder();
if (cmbDeckTypes.getSelectedItem() == null || cmbDeckTypes.getSelectedItem() == DeckType.NET_DECK) {
//handle special case of net decks
if (netDeckCategory == null) { return ""; }
state.append(NetDeckCategory.PREFIX + netDeckCategory.getName());
}
else {
state.append(cmbDeckTypes.getSelectedItem().name());
}
state.append(";");
joinSelectedDecks(state, SELECTED_DECK_DELIMITER);
return state.toString();
@@ -600,25 +671,20 @@ public class FDeckChooser extends FScreen {
}
}
/** Returns a clean name from the state that can be used for labels. */
public final String getStateForLabel() {
String deckType = cmbDeckTypes.getSelectedItem().toString();
StringBuilder state = new StringBuilder(deckType);
state.append(": ");
joinSelectedDecks(state, ", ");
return state.toString();
}
private void restoreSavedState() {
DeckType oldDeckType = selectedDeckType;
if (stateSetting == null) {
//if can't restore saved state, just refresh deck list
refreshDecksList(selectedDeckType, true, null);
refreshDecksList(oldDeckType, true, null);
return;
}
String savedState = prefs.getPref(stateSetting);
refreshDecksList(getDeckTypeFromSavedState(savedState), true, null);
lstDecks.setSelectedStrings(getSelectedDecksFromSavedState(savedState));
if (!lstDecks.setSelectedStrings(getSelectedDecksFromSavedState(savedState))) {
//if can't select old decks, just refresh deck list
refreshDecksList(oldDeckType, true, null);
}
}
private DeckType getDeckTypeFromSavedState(String savedState) {
@@ -627,7 +693,12 @@ public class FDeckChooser extends FScreen {
return selectedDeckType;
}
else {
return DeckType.valueOf(savedState.split(";")[0]);
String deckType = savedState.split(";")[0];
if (deckType.startsWith(NetDeckCategory.PREFIX)) {
netDeckCategory = NetDeckCategory.selectAndLoad(lstDecks.getGameType(), deckType.substring(NetDeckCategory.PREFIX.length()));
return DeckType.NET_DECK;
}
return DeckType.valueOf(deckType);
}
}
catch (IllegalArgumentException ex) {

View File

@@ -24,9 +24,11 @@ import com.badlogic.gdx.Gdx;
import forge.UiCommand;
import forge.assets.FSkinFont;
import forge.download.GuiDownloadService;
import forge.download.GuiDownloadZipService;
import forge.toolbox.*;
import forge.toolbox.FEvent.FEventHandler;
import forge.toolbox.FRadioButton.RadioButtonGroup;
import forge.util.Callback;
public class GuiDownloader extends FDialog {
public static final Proxy.Type[] TYPES = Proxy.Type.values();
@@ -44,16 +46,25 @@ public class GuiDownloader extends FDialog {
private final UiCommand cmdClose = new UiCommand() {
@Override
public void run() {
Gdx.graphics.setContinuousRendering(false);
service.setCancel(true);
hide();
if (callback != null) {
callback.run(btnStart.getText() == "OK"); //determine result based on whether download finished
}
}
};
private final GuiDownloadService service;
private final Callback<Boolean> callback;
public GuiDownloader(GuiDownloadService service0) {
this(service0, null);
}
public GuiDownloader(GuiDownloadService service0, Callback<Boolean> callback0) {
super(service0.getTitle());
service = service0;
callback = callback0;
txtAddress.setGhostText("Proxy Address");
txtPort.setGhostText("Proxy Port");
@@ -85,7 +96,9 @@ public class GuiDownloader extends FDialog {
service.initialize(txtAddress, txtPort, progressBar, btnStart, cmdClose, new Runnable() {
@Override
public void run() {
Gdx.graphics.setContinuousRendering(false);
if (!(service instanceof GuiDownloadZipService)) { //retain continuous rendering for zip service
Gdx.graphics.setContinuousRendering(false);
}
progressBar.setShowProgressTrail(false);
}
}, null);

View File

@@ -174,10 +174,15 @@ public class FComboBox<T> extends FTextField implements IComboBox<T> {
}
@Override
protected float getRightPadding() {
protected float getLeftPadding() {
if (getAlignment() == HAlignment.CENTER) {
return super.getRightPadding();
return getRightPadding(); //match right padding if center aligned
}
return super.getLeftPadding();
}
@Override
protected float getRightPadding() {
return getDivotWidth() + 2 * PADDING;
}

View File

@@ -7,7 +7,8 @@ public class FEvent {
CHANGE,
ACTIVATE,
SAVE,
DELETE
DELETE,
CLOSE
}
private FDisplayObject source;

View File

@@ -8,6 +8,12 @@ Forge Beta: 1-#-2015 ver 1.5.33
Release Notes
-------------
- Net Decks support -
On the Constructed screen, you can now select a new Net Decks category from the drop down
Contains all decks from gos's Forge Decks subforums, broken up by the column/event they were taken from
Won't cause startup to be slower since they are loaded on the fly
- Zoom to a XLHQ card picture -
Forge now supports showing XLHQ (extra large high quality) card pictures when zooming in on a card if these pictures are available. Forge will look for XLHQ card art in the "XLHQ" subfolder of the "pics/cards" folder in Forge cache. XLHQ pictures should have the ".xlhq.jpg" extension instead of the ".full.jpg" one (CCGHQ XLHQ releases comply with this naming scheme). For example, while the regular 10th edition Blaze will be looked up as "pics/cards/10E/Blaze.full.jpg", the XLHQ version will be looked up as "pics/cards/XLHQ/10E/Blaze.xlhq.jpg". If the XLHQ picture is not available Forge will show you the regular card picture in the zoomed view, as usual. Please note that XLHQ versions of cards are *only* showed in the zoom view, regular card pictures are still used (LQ/HQ, depending on what you're using) on the battlefield and elsewhere in the game because XLHQ art is significantly more taxing in memory consumption even when compared to standard high quality (HQ) releases (and in addition to that, XLHQ card borders are not cropped the way Forge expects them in order to show them properly on the battlefield anyway). XLHQ tokens are also supported, but the naming scheme for them is a little different - they are looked up in "pics/tokens/XLHQ" and have their ordinary names. For example, the 1/1 red Goblin token from the Magic 2015 set is normally looked up at "pics/tokens/r_1_1_goblin_m15.jpg", while its XLHQ version is looked up at "pics/tokens/XLHQ/r_1_1_goblin_m15.jpg".

View File

@@ -0,0 +1,10 @@
The Week That Was | http://www.slightlymagic.net/forum/download/file.php?id=19986
WotC Preconstructed | http://www.slightlymagic.net/forum/download/file.php?id=21293
Serious Fun | http://www.slightlymagic.net/forum/download/file.php?id=21279
ReConstructed | http://www.slightlymagic.net/forum/download/file.php?id=21275
Latest Developments | http://www.slightlymagic.net/forum/download/file.php?id=13259
From the Lab | http://www.slightlymagic.net/forum/download/file.php?id=21263
Feature Article | http://www.slightlymagic.net/forum/download/file.php?id=21259
Daily Deck List | http://www.slightlymagic.net/forum/download/file.php?id=18670
Command Tower | http://www.slightlymagic.net/forum/download/file.php?id=21255
Going Rogue | http://www.slightlymagic.net/forum/download/file.php?id=14064

View File

@@ -0,0 +1,28 @@
Top Decks | http://www.slightlymagic.net/forum/download/file.php?id=21296
World Championship | http://www.slightlymagic.net/forum/download/file.php?id=21289
The Week That Was | http://www.slightlymagic.net/forum/download/file.php?id=21285
Single Card Strategy | http://www.slightlymagic.net/forum/download/file.php?id=21282
WotC Preconstructed | http://www.slightlymagic.net/forum/download/file.php?id=21292
Serious Fun | http://www.slightlymagic.net/forum/download/file.php?id=21278
ReConstructed | http://www.slightlymagic.net/forum/download/file.php?id=21274
Pro Tour | http://www.slightlymagic.net/forum/download/file.php?id=21272
Perilous Research | http://www.slightlymagic.net/forum/download/file.php?id=21270
Into the AEther | http://www.slightlymagic.net/forum/download/file.php?id=18683
Level One | http://www.slightlymagic.net/forum/download/file.php?id=21268
Latest Developments | http://www.slightlymagic.net/forum/download/file.php?id=21266
From the Lab | http://www.slightlymagic.net/forum/download/file.php?id=21262
Feature Article | http://www.slightlymagic.net/forum/download/file.php?id=21260
Daily Deck List | http://www.slightlymagic.net/forum/download/file.php?id=21257
Building on a Budget | http://www.slightlymagic.net/forum/download/file.php?id=21253
Breaking Through | http://www.slightlymagic.net/forum/download/file.php?id=21251
Woo Brews | http://www.slightlymagic.net/forum/download/file.php?id=19091
Swimming with Sharks | http://www.slightlymagic.net/forum/download/file.php?id=17441
Learning Curve | http://www.slightlymagic.net/forum/download/file.php?id=16447
Squandered Resources | http://www.slightlymagic.net/forum/download/file.php?id=16074
Deconstructing Famous | http://www.slightlymagic.net/forum/download/file.php?id=14190
Going Rogue | http://www.slightlymagic.net/forum/download/file.php?id=13498
Uncommon Knowledge | http://www.slightlymagic.net/forum/download/file.php?id=13877
MagicTheGathering.Combos | http://www.slightlymagic.net/forum/download/file.php?id=9316
Players Championship 2012 | http://www.slightlymagic.net/forum/download/file.php?id=7324
Brewing on a Budget | http://www.slightlymagic.net/forum/download/file.php?id=6584
Grand Prix Lincoln 2012 | http://www.slightlymagic.net/forum/download/file.php?id=5318

View File

@@ -445,6 +445,14 @@ public class DeckProxy implements InventoryItem {
return decks;
}
public static List<DeckProxy> getNetDecks(NetDeckCategory category) {
ArrayList<DeckProxy> decks = new ArrayList<DeckProxy>();
if (category != null) {
addDecksRecursivelly("Constructed", GameType.Constructed, decks, "", category);
}
return decks;
}
public static final Predicate<DeckProxy> IS_WHITE = new Predicate<DeckProxy>() {
@Override
public boolean apply(final DeckProxy deck) {

View File

@@ -6,7 +6,8 @@ public enum DeckType {
QUEST_OPPONENT_DECK ("Quest Opponent Decks"),
COLOR_DECK ("Random Color Decks"),
THEME_DECK ("Random Theme Decks"),
RANDOM_DECK ("Random Decks");
RANDOM_DECK ("Random Decks"),
NET_DECK ("Net Decks");
private String value;
private DeckType(String value) {

View File

@@ -0,0 +1,127 @@
package forge.deck;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import forge.GuiBase;
import forge.deck.io.DeckSerializer;
import forge.deck.io.DeckStorage;
import forge.download.GuiDownloadZipService;
import forge.game.GameType;
import forge.properties.ForgeConstants;
import forge.util.FileUtil;
import forge.util.WaitCallback;
import forge.util.gui.SGuiChoose;
import forge.util.storage.StorageBase;
public class NetDeckCategory extends StorageBase<Deck> {
public static final String PREFIX = "NET_DECK_";
private static Map<String, NetDeckCategory> constructed, commander;
private static Map<String, NetDeckCategory> loadCategories(String filename) {
Map<String, NetDeckCategory> categories = new TreeMap<String, NetDeckCategory>();
if (FileUtil.doesFileExist(filename)) {
List<String> lines = FileUtil.readFile(filename);
for (String line : lines) {
int idx = line.indexOf('|');
if (idx != -1) {
String name = line.substring(0, idx).trim();
String url = line.substring(idx + 1).trim();
categories.put(name, new NetDeckCategory(name, url));
}
}
}
return categories;
}
public static NetDeckCategory selectAndLoad(GameType gameType) {
return selectAndLoad(gameType, null);
}
public static NetDeckCategory selectAndLoad(GameType gameType, String name) {
Map<String, NetDeckCategory> categories;
switch (gameType) {
case Constructed:
case Gauntlet:
if (constructed == null) {
constructed = loadCategories(ForgeConstants.NET_DECKS_LIST_FILE);
}
categories = constructed;
break;
case Commander:
if (commander == null) {
commander = loadCategories(ForgeConstants.NET_DECKS_COMMANDER_LIST_FILE);
}
categories = commander;
break;
default:
return null;
}
if (name != null) {
NetDeckCategory category = categories.get(name);
if (category != null && category.map.isEmpty()) {
//if name passed in, try to load decks from current cached files
File downloadDir = new File(category.getDownloadLocation());
if (downloadDir.exists()) {
for (File file : downloadDir.listFiles(DeckStorage.DCK_FILE_FILTER)) {
Deck deck = DeckSerializer.fromFile(file);
if (deck != null) {
category.map.put(deck.getName(), deck);
}
}
}
}
return category;
}
final NetDeckCategory c= SGuiChoose.oneOrNone("Select a Net Deck category", categories.values());
if (c == null) { return null; }
if (c.map.isEmpty()) { //only download decks once per session
WaitCallback<Boolean> callback = new WaitCallback<Boolean>() {
@Override
public void run() {
String downloadLoc = c.getDownloadLocation();
GuiBase.getInterface().download(new GuiDownloadZipService(c.getName(), "decks", c.getUrl(), downloadLoc, downloadLoc, null) {
@Override
protected void copyInputStream(InputStream in, String outPath) throws IOException {
super.copyInputStream(in, outPath);
Deck deck = DeckSerializer.fromFile(new File(outPath));
if (deck != null) {
c.map.put(deck.getName(), deck);
}
}
}, this);
}
};
if (!callback.invokeAndWait()) { return null; } //wait for download to finish
}
return c;
}
private final String url;
private NetDeckCategory(String name0, String downloadLocation0) {
super(name0, new HashMap<String, Deck>());
url = downloadLocation0;
}
public String getDownloadLocation() {
return ForgeConstants.DECK_NET_DIR + name + "/";
}
public String getUrl() {
return url;
}
@Override
public String toString() {
return "Net Decks - " + name;
}
}

View File

@@ -53,7 +53,7 @@ public abstract class GuiDownloadService implements Runnable {
//Components passed from GUI component displaying download
private ITextField txtAddress;
private ITextField txtPort;
private IProgressBar progressBar;
protected IProgressBar progressBar;
private IButton btnStart;
private UiCommand cmdClose;
private Runnable onUpdate;
@@ -73,7 +73,7 @@ public abstract class GuiDownloadService implements Runnable {
// Progress variables
private Map<String, String> files; // local path -> url
private boolean cancel;
protected boolean cancel;
private final long[] times = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
private int tptr = 0;
private int skipped = 0;
@@ -90,27 +90,50 @@ public abstract class GuiDownloadService implements Runnable {
cmdClose = cmdClose0;
onUpdate = onUpdate0;
// Free up the EDT by assembling card list on a background thread
FThreads.invokeInBackgroundThread(new Runnable() {
@Override
public void run() {
try {
files = getNeededFiles();
}
catch (Exception e) {
e.printStackTrace();
}
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
if (onReadyToStart != null) {
onReadyToStart.run();
}
readyToStart();
String startOverrideDesc = getStartOverrideDesc();
if (startOverrideDesc == null) {
// Free up the EDT by assembling card list on a background thread
FThreads.invokeInBackgroundThread(new Runnable() {
@Override
public void run() {
try {
files = getNeededFiles();
}
});
catch (Exception e) {
e.printStackTrace();
}
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
if (onReadyToStart != null) {
onReadyToStart.run();
}
readyToStart();
}
});
}
});
}
else {
//handle special case of zip service
if (onReadyToStart != null) {
onReadyToStart.run();
}
});
progressBar.setDescription("Click \"Start\" to download and extract " + startOverrideDesc);
btnStart.setCommand(cmdStartDownload);
btnStart.setEnabled(true);
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
btnStart.requestFocusInWindow();
}
});
}
}
protected String getStartOverrideDesc() {
return null;
}
private void readyToStart() {
@@ -198,10 +221,7 @@ public abstract class GuiDownloadService implements Runnable {
else {
sb.append(String.format("%d of %d items finished! Skipped " + skipped + " items. Please close!",
count, files.size()));
btnStart.setText("OK");
btnStart.setCommand(cmdClose);
btnStart.setEnabled(true);
btnStart.requestFocusInWindow();
finish();
}
progressBar.setValue(count);
@@ -211,25 +231,18 @@ public abstract class GuiDownloadService implements Runnable {
});
}
protected void finish() {
btnStart.setText("OK");
btnStart.setCommand(cmdClose);
btnStart.setEnabled(true);
btnStart.requestFocusInWindow();
}
@Override
public final void run() {
public void run() {
final Random r = MyRandom.getRandom();
Proxy p = null;
if (type == 0) {
p = Proxy.NO_PROXY;
}
else {
try {
p = new Proxy(TYPES[type], new InetSocketAddress(txtAddress.getText(), Integer.parseInt(txtPort.getText())));
}
catch (final Exception ex) {
BugReporter.reportException(ex,
"Proxy connection could not be established!\nProxy address: %s\nProxy port: %s",
txtAddress.getText(), txtPort.getText());
return;
}
}
Proxy p = getProxy();
int bufferLength;
int iCard = 0;
@@ -304,6 +317,23 @@ public abstract class GuiDownloadService implements Runnable {
}
}
protected Proxy getProxy() {
if (type == 0) {
return Proxy.NO_PROXY;
}
else {
try {
return new Proxy(TYPES[type], new InetSocketAddress(txtAddress.getText(), Integer.parseInt(txtPort.getText())));
}
catch (final Exception ex) {
BugReporter.reportException(ex,
"Proxy connection could not be established!\nProxy address: %s\nProxy port: %s",
txtAddress.getText(), txtPort.getText());
}
}
return null;
}
public abstract String getTitle();
protected abstract Map<String, String> getNeededFiles();

View File

@@ -0,0 +1,203 @@
package forge.download;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import com.esotericsoftware.minlog.Log;
import com.google.common.io.Files;
import forge.FThreads;
import forge.interfaces.IProgressBar;
import forge.util.FileUtil;
public class GuiDownloadZipService extends GuiDownloadService {
private final String name, desc, sourceUrl, destFolder, deleteFolder;
private int filesDownloaded;
public GuiDownloadZipService(String name0, String desc0, String sourceUrl0, String destFolder0, String deleteFolder0, IProgressBar progressBar0) {
name = name0;
desc = desc0;
sourceUrl = sourceUrl0;
destFolder = destFolder0;
deleteFolder = deleteFolder0;
progressBar = progressBar0;
}
@Override
public String getTitle() {
return "Download " + name;
}
@Override
protected String getStartOverrideDesc() {
return desc;
}
@Override
protected final Map<String, String> getNeededFiles() {
HashMap<String, String> files = new HashMap<String, String>();
files.put("_", "_");
return files; //not needed by zip service, so just return map of size 1
}
@Override
public final void run() {
downloadAndUnzip();
if (!cancel) {
FThreads.invokeInEdtNowOrLater(new Runnable() {
@Override
public void run() {
progressBar.setDescription(filesDownloaded + " " + desc + " downloaded");
finish();
}
});
}
}
public void downloadAndUnzip() {
filesDownloaded = 0;
String zipFilename = download("temp.zip");
if (zipFilename == null) { return; }
//if assets.zip downloaded successfully, unzip into destination folder
try {
if (deleteFolder != null) {
File deleteDir = new File(deleteFolder);
if (deleteDir.exists()) {
//attempt to delete previous res directory if to be rebuilt
progressBar.reset();
progressBar.setDescription("Deleting old " + desc + "...");
if (deleteFolder.equals(destFolder)) { //move zip file to prevent deleting it
String oldZipFilename = zipFilename;
zipFilename = deleteDir.getParentFile().getAbsolutePath() + File.separator + "temp.zip";
Files.move(new File(oldZipFilename), new File(zipFilename));
}
FileUtil.deleteDirectory(deleteDir);
}
}
ZipFile zipFile = new ZipFile(zipFilename, Charset.forName("CP866")); //ensure unzip doesn't fail due to non UTF-8 chars
Enumeration<? extends ZipEntry> entries = zipFile.entries();
progressBar.reset();
progressBar.setPercentMode(true);
progressBar.setDescription("Extracting " + desc);
progressBar.setMaximum(zipFile.size());
FileUtil.ensureDirectoryExists(destFolder);
int count = 0;
while (entries.hasMoreElements()) {
if (cancel) { break; }
ZipEntry entry = (ZipEntry)entries.nextElement();
String path = destFolder + entry.getName();
if (entry.isDirectory()) {
new File(path).mkdir();
progressBar.setValue(++count);
continue;
}
copyInputStream(zipFile.getInputStream(entry), path);
progressBar.setValue(++count);
filesDownloaded++;
}
zipFile.close();
new File(zipFilename).delete();
}
catch (Exception e) {
e.printStackTrace();
}
}
public String download(String filename) {
progressBar.reset();
progressBar.setPercentMode(true);
progressBar.setDescription("Downloading " + desc);
try {
URL url = new URL(sourceUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection(getProxy());
if (url.getPath().endsWith(".php")) {
//ensure file can be downloaded if returned from PHP script
conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 4.01; Windows NT)");
}
conn.connect();
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
return null;
}
long contentLength = conn.getContentLengthLong();
if (contentLength == 0) {
return null;
}
progressBar.setMaximum(100);
// input stream to read file - with 8k buffer
InputStream input = new BufferedInputStream(conn.getInputStream(), 8192);
FileUtil.ensureDirectoryExists(destFolder);
// output stream to write file
String destFile = destFolder + filename;
OutputStream output = new FileOutputStream(destFile);
int count;
long total = 0;
byte data[] = new byte[1024];
while ((count = input.read(data)) != -1) {
if (cancel) { break; }
total += count;
progressBar.setValue((int)(100 * total / contentLength));
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
if (cancel) {
new File(destFile).delete();
return null;
}
return destFile;
}
catch (final Exception ex) {
Log.error("Downloading " + desc, "Error downloading " + desc, ex);
}
return null;
}
protected void copyInputStream(InputStream in, String outPath) throws IOException{
byte[] buffer = new byte[1024];
int len;
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(outPath));
while((len = in.read(buffer)) >= 0) {
out.write(buffer, 0, len);
}
in.close();
out.close();
}
}

View File

@@ -10,6 +10,7 @@ import forge.LobbyPlayer;
import forge.assets.FSkinProp;
import forge.assets.ISkinImage;
import forge.deck.CardPool;
import forge.download.GuiDownloadService;
import forge.game.GameEntity;
import forge.game.GameEntityView;
import forge.game.card.CardView;
@@ -19,6 +20,7 @@ import forge.item.PaperCard;
import forge.player.PlayerControllerHuman;
import forge.sound.IAudioClip;
import forge.sound.IAudioMusic;
import forge.util.Callback;
import forge.util.FCollectionView;
public interface IGuiBase {
@@ -45,6 +47,7 @@ public interface IGuiBase {
GameEntityView chooseSingleEntityForEffect(String title, FCollectionView<? extends GameEntity> optionList, DelayedReveal delayedReveal, boolean isOptional, PlayerControllerHuman controller);
String showFileDialog(String title, String defaultDir);
File getSaveFile(File defaultFile);
void download(GuiDownloadService service, Callback<Boolean> callback);
void showCardList(final String title, final String message, final List<PaperCard> list);
boolean showBoxedProduct(final String title, final String message, final List<PaperCard> list);
void setCard(CardView card);

View File

@@ -88,6 +88,8 @@ public enum ItemManagerConfig {
null, null, 3, 0),
QUEST_EVENT_DECKS(SColumnUtil.getDecksDefaultColumns(false, false), false, false, false,
null, null, 3, 0),
NET_DECKS(SColumnUtil.getDecksDefaultColumns(false, false), false, false, false,
null, null, 3, 0),
SIDEBOARD(SColumnUtil.getDeckEditorDefaultColumns(), false, false, true,
GroupDef.DEFAULT, ColumnDef.CMC, 3, 0);

View File

@@ -40,6 +40,8 @@ public final class ForgeConstants {
public static final String IMAGE_LIST_QUEST_BOOSTERBOXES_FILE = LISTS_DIR + "boosterbox-images.txt";
public static final String IMAGE_LIST_QUEST_PRECONS_FILE = LISTS_DIR + "precon-images.txt";
public static final String IMAGE_LIST_QUEST_TOURNAMENTPACKS_FILE = LISTS_DIR + "tournamentpack-images.txt";
public static final String NET_DECKS_LIST_FILE = LISTS_DIR + "net-decks.txt";
public static final String NET_DECKS_COMMANDER_LIST_FILE = LISTS_DIR + "net-decks-commander.txt";
public static final String CHANGES_FILE = ASSETS_DIR + "CHANGES.txt";
public static final String LICENSE_FILE = ASSETS_DIR + "LICENSE.txt";
@@ -114,6 +116,7 @@ public final class ForgeConstants {
public static final String DECK_SCHEME_DIR = DECK_BASE_DIR + "scheme/";
public static final String DECK_PLANE_DIR = DECK_BASE_DIR + "planar/";
public static final String DECK_COMMANDER_DIR = DECK_BASE_DIR + "commander/";
public static final String DECK_NET_DIR = DECK_BASE_DIR + "net/";
public static final String QUEST_SAVE_DIR = USER_QUEST_DIR + "saves/";
public static final String CONQUEST_SAVE_DIR = USER_CONQUEST_DIR + "saves/";
public static final String MAIN_PREFS_FILE = USER_PREFS_DIR + "forge.preferences";
@@ -159,6 +162,8 @@ public final class ForgeConstants {
DECK_SEALED_DIR,
DECK_SCHEME_DIR,
DECK_PLANE_DIR,
DECK_COMMANDER_DIR,
DECK_NET_DIR,
QUEST_SAVE_DIR,
CACHE_TOKEN_PICS_DIR,
CACHE_ICON_PICS_DIR,