diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/SkinChooser.java b/src/hdskins/java/com/voxelmodpack/hdskins/SkinChooser.java index 6aa90cb9..d849d203 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/SkinChooser.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/SkinChooser.java @@ -1,8 +1,8 @@ package com.voxelmodpack.hdskins; import com.voxelmodpack.hdskins.skins.MoreHttpResponses; -import com.voxelmodpack.hdskins.upload.awt.ThreadOpenFile; -import com.voxelmodpack.hdskins.upload.awt.ThreadOpenFileFolder; +import com.voxelmodpack.hdskins.upload.awt.IFileDialog; +import com.voxelmodpack.hdskins.upload.awt.ThreadSaveFilePNG; import com.voxelmodpack.hdskins.upload.awt.ThreadOpenFilePNG; import net.minecraft.client.Minecraft; import org.apache.commons.io.FileUtils; @@ -39,7 +39,7 @@ public class SkinChooser { return number != 0 && (number & number - 1) == 0; } - private ThreadOpenFile openFileThread; + private IFileDialog openFileThread; private final SkinUploader uploader; @@ -60,29 +60,27 @@ public class SkinChooser { } public void openBrowsePNG(Minecraft mc, String title) { - openFileThread = new ThreadOpenFilePNG(mc, title, (fileDialog, dialogResult) -> { + openFileThread = new ThreadOpenFilePNG(mc, title, (file, dialogResult) -> { openFileThread = null; if (dialogResult == 0) { - selectFile(fileDialog.getSelectedFile()); + selectFile(file); } }); openFileThread.start(); } public void openSavePNG(Minecraft mc, String title) { - openFileThread = new ThreadOpenFileFolder(mc, title, (fileDialog, dialogResult) -> { + openFileThread = new ThreadSaveFilePNG(mc, title, mc.getSession().getUsername() + ".png", (file, dialogResult) -> { if (dialogResult == 0) { - File out = fileDialog.getSelectedFile(); try (MoreHttpResponses response = uploader.downloadSkin().get()) { if (response.ok()) { - FileUtils.copyInputStreamToFile(response.getInputStream(), out); + FileUtils.copyInputStreamToFile(response.getInputStream(), file); } } catch (IOException | InterruptedException | ExecutionException e) { e.printStackTrace(); } } openFileThread = null; - }); openFileThread.start(); } diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiSkins.java b/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiSkins.java index b9b89d0a..4275ee29 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiSkins.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiSkins.java @@ -129,7 +129,7 @@ public class GuiSkins extends GameGui implements ISkinUploadHandler { addButton(btnDownload = new Button(width / 2 - 24, height / 2 + 20, 48, 20, "hdskins.options.download", sender -> { if (uploader.canClear()) { - chooser.openSavePNG(mc, format("hdskins.open.title")); + chooser.openSavePNG(mc, format("hdskins.save.title")); } })).setEnabled(uploader.canClear()).setTooltip("hdskins.options.download.title"); diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/IFileCallback.java b/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/IFileCallback.java new file mode 100644 index 00000000..25075e79 --- /dev/null +++ b/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/IFileCallback.java @@ -0,0 +1,7 @@ +package com.voxelmodpack.hdskins.upload.awt; + +import java.io.File; + +public interface IFileCallback { + void onDialogClosed(File file, int dialogResults); +} diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/IFileDialog.java b/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/IFileDialog.java new file mode 100644 index 00000000..08bed605 --- /dev/null +++ b/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/IFileDialog.java @@ -0,0 +1,5 @@ +package com.voxelmodpack.hdskins.upload.awt; + +public interface IFileDialog extends Runnable { + void start(); +} diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/IOpenFileCallback.java b/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/IOpenFileCallback.java deleted file mode 100644 index 2f859b6f..00000000 --- a/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/IOpenFileCallback.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.voxelmodpack.hdskins.upload.awt; - -import javax.swing.JFileChooser; - -/** - * Interface for objects which can receive a callback from ThreadOpenFile - * - * @author Adam Mummery-Smith - */ -@FunctionalInterface -public interface IOpenFileCallback { - - /** - * Callback method called when the "open file" dialog is closed - */ - void onFileOpenDialogClosed(JFileChooser fileDialog, int dialogResult); - -} diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/ThreadOpenFile.java b/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/ThreadOpenFile.java index e7aa5105..d980515c 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/ThreadOpenFile.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/ThreadOpenFile.java @@ -15,16 +15,16 @@ import com.voxelmodpack.hdskins.LiteModHDSkins; * * @author Adam Mummery-Smith */ -public abstract class ThreadOpenFile extends Thread { +public abstract class ThreadOpenFile extends Thread implements IFileDialog { protected String dialogTitle; /** * Delegate to call back when the dialog box is closed */ - protected final IOpenFileCallback parentScreen; + protected final IFileCallback parentScreen; - protected ThreadOpenFile(Minecraft minecraft, String dialogTitle, IOpenFileCallback callback) throws IllegalStateException { + protected ThreadOpenFile(Minecraft minecraft, String dialogTitle, IFileCallback callback) throws IllegalStateException { if (minecraft.isFullScreen()) { throw new IllegalStateException("Cannot open an awt window whilst minecraft is in full screen mode!"); } @@ -44,20 +44,32 @@ public abstract class ThreadOpenFile extends Thread { } fileDialog.setFileFilter(getFileFilter()); - int dialogResult = fileDialog.showOpenDialog(InternalDialog.getAWTContext()); + int dialogResult = showDialog(fileDialog); File f = fileDialog.getSelectedFile(); if (f != null) { LiteModHDSkins.instance().lastChosenFile = f.getAbsolutePath(); LiteModHDSkins.instance().writeConfig(); + + if (!f.exists() && f.getName().indexOf('.') == -1) { + f = appendMissingExtension(f); + } } - parentScreen.onFileOpenDialogClosed(fileDialog, dialogResult); + parentScreen.onDialogClosed(f, dialogResult); + } + + protected int showDialog(JFileChooser chooser) { + return chooser.showOpenDialog(InternalDialog.getAWTContext()); } /** * Subclasses should override this to return a file filter */ protected abstract FileFilter getFileFilter(); + + protected File appendMissingExtension(File file) { + return file; + } } diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/ThreadOpenFileFolder.java b/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/ThreadOpenFileFolder.java deleted file mode 100644 index 09cdd43c..00000000 --- a/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/ThreadOpenFileFolder.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.voxelmodpack.hdskins.upload.awt; - -import net.minecraft.client.Minecraft; - -import javax.swing.filechooser.FileFilter; -import java.io.File; - -/** - * Opens an awt "Open File" dialog that only accepts directories. - */ -public class ThreadOpenFileFolder extends ThreadOpenFile { - - public ThreadOpenFileFolder(Minecraft minecraft, String dialogTitle, IOpenFileCallback callback) - throws IllegalStateException { - super(minecraft, dialogTitle, callback); - } - - @Override - protected FileFilter getFileFilter() { - return new FileFilter() { - @Override - public String getDescription() { - return "Directories"; - } - - @Override - public boolean accept(File f) { - return f.isDirectory(); - } - }; - } -} diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/ThreadOpenFilePNG.java b/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/ThreadOpenFilePNG.java index 2f15a7c1..ccda4df9 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/ThreadOpenFilePNG.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/ThreadOpenFilePNG.java @@ -12,8 +12,7 @@ import java.io.File; */ public class ThreadOpenFilePNG extends ThreadOpenFile { - public ThreadOpenFilePNG(Minecraft minecraft, String dialogTitle, IOpenFileCallback callback) - throws IllegalStateException { + public ThreadOpenFilePNG(Minecraft minecraft, String dialogTitle, IFileCallback callback) throws IllegalStateException { super(minecraft, dialogTitle, callback); } diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/ThreadSaveFile.java b/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/ThreadSaveFile.java new file mode 100644 index 00000000..3235016c --- /dev/null +++ b/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/ThreadSaveFile.java @@ -0,0 +1,47 @@ +package com.voxelmodpack.hdskins.upload.awt; + +import net.minecraft.client.Minecraft; + +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; + +import java.io.File; + +/** + * Opens an awt "Save File" dialog + */ +public abstract class ThreadSaveFile extends ThreadOpenFile { + + protected String filename; + + protected ThreadSaveFile(Minecraft minecraft, String dialogTitle, String initialFilename, IFileCallback callback) throws IllegalStateException { + super(minecraft, dialogTitle, callback); + this.filename = initialFilename; + } + + @Override + protected int showDialog(JFileChooser chooser) { + + + do { + chooser.setSelectedFile(new File(filename)); + + int result = chooser.showSaveDialog(InternalDialog.getAWTContext()); + + File f = chooser.getSelectedFile(); + if (result == 0 && f != null && f.exists()) { + + if (JOptionPane.showConfirmDialog(chooser, + "A file named \"" + f.getName() + "\" already exists. Do you want to replace it?", "Confirm", + JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.YES_OPTION) { + continue; + } + + f.delete(); + } + + + return result; + } while (true); + } +} diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/ThreadSaveFilePNG.java b/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/ThreadSaveFilePNG.java new file mode 100644 index 00000000..fbe12f3a --- /dev/null +++ b/src/hdskins/java/com/voxelmodpack/hdskins/upload/awt/ThreadSaveFilePNG.java @@ -0,0 +1,34 @@ +package com.voxelmodpack.hdskins.upload.awt; + +import net.minecraft.client.Minecraft; + +import javax.swing.filechooser.FileFilter; + +import java.io.File; + +public class ThreadSaveFilePNG extends ThreadSaveFile { + + public ThreadSaveFilePNG(Minecraft minecraft, String dialogTitle, String filename, IFileCallback callback) { + super(minecraft, dialogTitle, filename, callback); + } + + @Override + protected FileFilter getFileFilter() { + return new FileFilter() { + @Override + public String getDescription() { + return "PNG Files (*.png)"; + } + + @Override + public boolean accept(File f) { + return f.isDirectory() || f.getName().toLowerCase().endsWith(".png"); + } + }; + } + + @Override + protected File appendMissingExtension(File file) { + return new File(file.getParentFile(), file.getName() + ".png"); + } +} diff --git a/src/hdskins/resources/assets/hdskins/lang/en_us.lang b/src/hdskins/resources/assets/hdskins/lang/en_us.lang index af18dce8..c9fce345 100644 --- a/src/hdskins/resources/assets/hdskins/lang/en_us.lang +++ b/src/hdskins/resources/assets/hdskins/lang/en_us.lang @@ -13,6 +13,7 @@ hdskins.error.noserver=There was no valid skin server available hdskins.error.offline=- Server Offline - hdskins.open.title=Choose skin +hdskins.save.title=Choose save location hdskins.fetch=Fetching skin... hdskins.failed=Uploading skin failed hdskins.request=Sending request to server please wait... diff --git a/src/main/java/com/minelittlepony/hdskins/gui/GuiSkinsMineLP.java b/src/main/java/com/minelittlepony/hdskins/gui/GuiSkinsMineLP.java index 5244af0a..a43805fe 100644 --- a/src/main/java/com/minelittlepony/hdskins/gui/GuiSkinsMineLP.java +++ b/src/main/java/com/minelittlepony/hdskins/gui/GuiSkinsMineLP.java @@ -10,7 +10,6 @@ import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type; import com.voxelmodpack.hdskins.gui.EntityPlayerModel; import com.voxelmodpack.hdskins.gui.GuiSkins; import com.voxelmodpack.hdskins.skins.SkinServer; -import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.init.Items; import net.minecraft.init.SoundEvents; import net.minecraft.item.ItemStack;