diff --git a/.classpath b/.classpath index 525e316..595b356 100644 --- a/.classpath +++ b/.classpath @@ -3,5 +3,6 @@ + diff --git a/.gitignore b/.gitignore index b3c432c..7a46396 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ /Resizer*.exe /antbin /launch4j.log +target +.idea/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..fea9e65 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +9patch-resizer \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..217af47 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,23 @@ + + + + + + diff --git a/.idea/copyright/Redwarp.xml b/.idea/copyright/Redwarp.xml new file mode 100644 index 0000000..fb25d3e --- /dev/null +++ b/.idea/copyright/Redwarp.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..a63a6f4 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..cb01329 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/.idea/libraries/gson_2_2_4.xml b/.idea/libraries/gson_2_2_4.xml new file mode 100644 index 0000000..33a40e6 --- /dev/null +++ b/.idea/libraries/gson_2_2_4.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..c4ab1ee --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,211 @@ + + + + + + + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..3636d50 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Resizer.eml b/Resizer.eml new file mode 100644 index 0000000..71d5e2b --- /dev/null +++ b/Resizer.eml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Resizer.iml b/Resizer.iml new file mode 100644 index 0000000..46adf0f --- /dev/null +++ b/Resizer.iml @@ -0,0 +1,3 @@ + + + diff --git a/build.xml b/build.xml index d2205ee..8a4464b 100644 --- a/build.xml +++ b/build.xml @@ -9,6 +9,7 @@ + @@ -71,6 +72,8 @@ + + diff --git a/proguard.txt b/proguard.txt index 862fed9..3b42123 100644 --- a/proguard.txt +++ b/proguard.txt @@ -10,4 +10,21 @@ -keep public class net.redwarp.tool.resizer.Main { public static void main(java.lang.String[]); -} \ No newline at end of file +} + +##---------------Begin: proguard configuration for Gson ---------- +# Gson uses generic type information stored in a class file when working with fields. Proguard +# removes such information by default, so configure it to keep all of it. +-keepattributes Signature + +# For using GSON @Expose annotation +-keepattributes *Annotation* + +# Gson specific classes +-keep class sun.misc.Unsafe { *; } +#-keep class com.google.gson.stream.** { *; } + +# Application classes that will be serialized/deserialized over Gson +-keep class net.redwarp.tool.resizer.worker.ScreenDensity { *; } + +##---------------End: proguard configuration for Gson ---------- \ No newline at end of file diff --git a/res/locale/Strings.properties b/res/locale/Strings.properties index 111c9d1..47d3ff5 100644 --- a/res/locale/Strings.properties +++ b/res/locale/Strings.properties @@ -1,6 +1,6 @@ #Created by JInto - www.guh-software.de #Sat Jun 09 15:23:03 CEST 2012 -about_text=Resizer is a simple resizer tool for Android.\r\nIt takes a PNG image as input, and automatically renerates folders with 4 densities \: ldpi, mdpi, hdpi and xhdpi.\r\nWhat's more \: Resizer work on 9 patches as well \! Because, let's face it, it's a pain to have to do it by hand.\r\nAll icons were found on http\://www.clker.com/\r\n\r\n(c) Copyright Redwarp 2012. All rights reserved. +about_text=Resizer is a simple resizer tool for Android.\r\nIt takes a PNG image as input, and automatically renerates folders with 4 densities \: ldpi, mdpi, hdpi and xhdpi.\r\nWhat's more \: Resizer work on 9 patches as well \! Because, let's face it, it's a pain to have to do it by hand.\r\nAll icons were found on http\://www.clker.com/\r\n\r\n(c) Copyright Redwarp 2013. All rights reserved. app_name=9Patch Resizer column_name=Image name column_status=Status @@ -16,3 +16,5 @@ status_finished=Finished \! status_in_progress=In progress... status_pending=Pending... xhdpi=Drop xhdpi image here (PNG format, nine patch included) +input_density="Input density:" +output_density="Output density:" \ No newline at end of file diff --git a/res/locale/Strings_fr.properties b/res/locale/Strings_fr.properties index d1979d5..c1bd8fc 100644 --- a/res/locale/Strings_fr.properties +++ b/res/locale/Strings_fr.properties @@ -1,6 +1,6 @@ #Created by JInto - www.guh-software.de #Sat Jun 09 15:23:03 CEST 2012 -about_text=Resizer est un outil de redimensionnement pour Android.\r\nIl g\u00E9n\u00E8re automatiquement 4 dossiers de densit\u00E9 \: ldpi, mdpi, hdpi and xhdpi.\r\nMais le plus \: Resizer fonctionne sur les 9 patches \! Il faut l'avouer, c'est p\u00EAte b**ne de le faire \u00E0 la main.\r\nLes icons proviennent de http\://www.clker.com/\r\n\r\n(c) Copyright Redwarp 2012. Tous droits r\u00E9serv\u00E9s. +about_text=Resizer est un outil de redimensionnement pour Android.\r\nIl g\u00E9n\u00E8re automatiquement 4 dossiers de densit\u00E9 \: ldpi, mdpi, hdpi and xhdpi.\r\nMais le plus \: Resizer fonctionne sur les 9 patches \! Il faut l'avouer, c'est p\u00EAte b**ne de le faire \u00E0 la main.\r\nLes icons proviennent de http\://www.clker.com/\r\n\r\n(c) Copyright Redwarp 2013. Tous droits r\u00E9serv\u00E9s. app_name=9Patch Resizer column_name=Nom de l'image column_status=Status @@ -16,3 +16,5 @@ status_finished=Termin\u00E9 \! status_in_progress=En cours... status_pending=En attente... xhdpi=D\u00E9posez des images au format PNG (9 patch inclus) +input_density="Densit\u00E9 d'entr\u00E9e :" +output_density="Densit\u00E9s de sortie :" diff --git a/res/misc/densities.json b/res/misc/densities.json new file mode 100644 index 0000000..dd5ec3e --- /dev/null +++ b/res/misc/densities.json @@ -0,0 +1,35 @@ +{ + "densities": [ + { + "name": "xxhdpi", + "scale": 3, + "active": false + }, + { + "name": "xhdpi", + "scale": 2, + "active": true + }, + { + "name": "hdpi", + "scale": 1.5, + "active": true + }, + { + "name": "tvdpi", + "scale": 1.33, + "active": false + }, + { + "name": "mdpi", + "scale": 1, + "active": true + }, + { + "name": "ldpi", + "scale": 0.75, + "active": true + } + ], + "source": "xhdpi" +} diff --git a/res/misc/preferences.properties b/res/misc/preferences.properties index 6f308a5..9aa50dc 100644 --- a/res/misc/preferences.properties +++ b/res/misc/preferences.properties @@ -1,3 +1,3 @@ #Created by JInto - www.guh-software.de #Sun Oct 21 22:30:52 CEST 2012 -version=1.2 +version=1.3 \ No newline at end of file diff --git a/src/net/iharder/dnd/FileDrop.java b/src/net/iharder/dnd/FileDrop.java index d4c0f76..1be52c0 100644 --- a/src/net/iharder/dnd/FileDrop.java +++ b/src/net/iharder/dnd/FileDrop.java @@ -1,12 +1,8 @@ package net.iharder.dnd; -import java.awt.Component; +import java.awt.*; import java.awt.datatransfer.DataFlavor; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.PrintStream; -import java.io.Reader; +import java.io.*; /** * This class makes it easy to drag and drop files from the operating system to @@ -22,7 +18,7 @@ * JPanel myPanel = new JPanel(); * new FileDrop( myPanel, new FileDrop.Listener() * { public void filesDropped( java.io.File[] files ) - * { + * { * // handle file drop * ... * } // end filesDropped @@ -38,7 +34,7 @@ * null value will result in no extra debugging information being * output. *

- * + *

*

* I'm releasing this code into the Public Domain. Enjoy. *

@@ -51,932 +47,898 @@ *

* 2012-05-10 Redwarp -- Parameterized (me gusta) *

- * + * * @author Robert Harder * @author rharder@users.sf.net * @version 1.0.1 */ public class FileDrop { - private transient javax.swing.border.Border normalBorder; - private transient java.awt.dnd.DropTargetListener dropListener; - - /** Discover if the running JVM is modern enough to have drag and drop. */ - private static Boolean supportsDnD; - - // Default border color - private static java.awt.Color defaultBorderColor = new java.awt.Color(0f, - 0f, 1f, 0.25f); - - /** - * Constructs a {@link FileDrop} with a default light-blue border and, if - * c is a {@link java.awt.Container}, recursively sets all - * elements contained within as drop targets, though only the top level - * container will change borders. - * - * @param c - * Component on which files will be dropped. - * @param listener - * Listens for filesDropped. - * @since 1.0 - */ - public FileDrop(final T c, final Listener listener) { - this(null, // Logging stream - c, // Drop target - javax.swing.BorderFactory.createMatteBorder(2, 2, 2, 2, - defaultBorderColor), // Drag border - true, // Recursive - listener); - } // end constructor - - /** - * Constructor with a default border and the option to recursively set drop - * targets. If your component is a java.awt.Container, then each of - * its children components will also listen for drops, though only the - * parent will change borders. - * - * @param c - * Component on which files will be dropped. - * @param recursive - * Recursively set children as drop targets. - * @param listener - * Listens for filesDropped. - * @since 1.0 - */ - public FileDrop(final T c, final boolean recursive, - final Listener listener) { - this(null, // Logging stream - c, // Drop target - javax.swing.BorderFactory.createMatteBorder(2, 2, 2, 2, - defaultBorderColor), // Drag border - recursive, // Recursive - listener); - } // end constructor - - /** - * Constructor with a default border and debugging optionally turned on. - * With Debugging turned on, more status messages will be displayed to - * out. A common way to use this constructor is with - * System.out or System.err. A null value for the - * parameter out will result in no debugging output. - * - * @param out - * PrintStream to record debugging info or null for no debugging. - * @param out - * @param c - * Component on which files will be dropped. - * @param listener - * Listens for filesDropped. - * @since 1.0 - */ - public FileDrop(final java.io.PrintStream out, final T c, - final Listener listener) { - this(out, // Logging stream - c, // Drop target - javax.swing.BorderFactory.createMatteBorder(2, 2, 2, 2, - defaultBorderColor), false, // Recursive - listener); - } // end constructor - - /** - * Constructor with a default border, debugging optionally turned on and the - * option to recursively set drop targets. If your component is a - * java.awt.Container, then each of its children components will - * also listen for drops, though only the parent will change borders. With - * Debugging turned on, more status messages will be displayed to - * out. A common way to use this constructor is with - * System.out or System.err. A null value for the - * parameter out will result in no debugging output. - * - * @param out - * PrintStream to record debugging info or null for no debugging. - * @param out - * @param c - * Component on which files will be dropped. - * @param recursive - * Recursively set children as drop targets. - * @param listener - * Listens for filesDropped. - * @since 1.0 - */ - public FileDrop(final java.io.PrintStream out, final T c, - final boolean recursive, final Listener listener) { - this(out, // Logging stream - c, // Drop target - javax.swing.BorderFactory.createMatteBorder(2, 2, 2, 2, - defaultBorderColor), // Drag border - recursive, // Recursive - listener); - } // end constructor - - /** - * Constructor with a specified border - * - * @param c - * Component on which files will be dropped. - * @param dragBorder - * Border to use on JComponent when dragging occurs. - * @param listener - * Listens for filesDropped. - * @since 1.0 - */ - public FileDrop(final T c, final javax.swing.border.Border dragBorder, - final Listener listener) { - this(null, // Logging stream - c, // Drop target - dragBorder, // Drag border - false, // Recursive - listener); - } // end constructor - - /** - * Constructor with a specified border and the option to recursively set - * drop targets. If your component is a java.awt.Container, then - * each of its children components will also listen for drops, though only - * the parent will change borders. - * - * @param c - * Component on which files will be dropped. - * @param dragBorder - * Border to use on JComponent when dragging occurs. - * @param recursive - * Recursively set children as drop targets. - * @param listener - * Listens for filesDropped. - * @since 1.0 - */ - public FileDrop(final T c, final javax.swing.border.Border dragBorder, - final boolean recursive, final Listener listener) { - this(null, c, dragBorder, recursive, listener); - } // end constructor - - /** - * Constructor with a specified border and debugging optionally turned on. - * With Debugging turned on, more status messages will be displayed to - * out. A common way to use this constructor is with - * System.out or System.err. A null value for the - * parameter out will result in no debugging output. - * - * @param out - * PrintStream to record debugging info or null for no debugging. - * @param c - * Component on which files will be dropped. - * @param dragBorder - * Border to use on JComponent when dragging occurs. - * @param listener - * Listens for filesDropped. - * @since 1.0 - */ - public FileDrop(final java.io.PrintStream out, final T c, - final javax.swing.border.Border dragBorder, - final Listener listener) { - this(out, // Logging stream - c, // Drop target - dragBorder, // Drag border - false, // Recursive - listener); - } // end constructor - - /** - * Full constructor with a specified border and debugging optionally turned - * on. With Debugging turned on, more status messages will be displayed to - * out. A common way to use this constructor is with - * System.out or System.err. A null value for the - * parameter out will result in no debugging output. - * - * @param out - * PrintStream to record debugging info or null for no debugging. - * @param c - * Component on which files will be dropped. - * @param dragBorder - * Border to use on JComponent when dragging occurs. - * @param recursive - * Recursively set children as drop targets. - * @param listener - * Listens for filesDropped. - * @since 1.0 - */ - public FileDrop(final java.io.PrintStream out, final T c, - final javax.swing.border.Border dragBorder, - final boolean recursive, final Listener listener) { - - if (supportsDnD()) { // Make a drop listener - this.dropListener = new java.awt.dnd.DropTargetListener() { - @Override - public void dragEnter(java.awt.dnd.DropTargetDragEvent evt) { - log(out, "FileDrop: dragEnter event."); - - // Is this an acceptable drag event? - if (FileDrop.this.isDragOk(out, evt)) { - // If it's a Swing component, set its border - if (c instanceof javax.swing.JComponent) { - javax.swing.JComponent jc = (javax.swing.JComponent) c; - FileDrop.this.normalBorder = jc.getBorder(); - log(out, "FileDrop: normal border saved."); - jc.setBorder(dragBorder); - - log(out, "FileDrop: drag border set."); - } // end if: JComponent - - if (listener != null) { - listener.dragEnter(c); - } - - // Acknowledge that it's okay to enter - // evt.acceptDrag( - // java.awt.dnd.DnDConstants.ACTION_COPY_OR_MOVE ); - evt.acceptDrag(java.awt.dnd.DnDConstants.ACTION_COPY); - log(out, "FileDrop: event accepted."); - } // end if: drag ok - else { // Reject the drag event - evt.rejectDrag(); - log(out, "FileDrop: event rejected."); - } // end else: drag not ok - } // end dragEnter - - @Override - public void dragOver(java.awt.dnd.DropTargetDragEvent evt) { - // This is called continually as long as - // the mouse is over the drag target. - } // end dragOver - - @Override - public void drop(java.awt.dnd.DropTargetDropEvent evt) { - log(out, "FileDrop: drop event."); - try { // Get whatever was dropped - java.awt.datatransfer.Transferable tr = evt - .getTransferable(); - - // Is it a file list? - if (tr.isDataFlavorSupported(java.awt.datatransfer.DataFlavor.javaFileListFlavor)) { - // Say we'll take it. - // evt.acceptDrop ( - // java.awt.dnd.DnDConstants.ACTION_COPY_OR_MOVE ); - evt.acceptDrop(java.awt.dnd.DnDConstants.ACTION_COPY); - log(out, "FileDrop: file list accepted."); - - // Get a useful list - @SuppressWarnings("unchecked") - java.util.List fileList = (java.util.List) tr - .getTransferData(java.awt.datatransfer.DataFlavor.javaFileListFlavor); - - // Convert list to array - java.io.File[] filesTemp = new java.io.File[fileList - .size()]; - fileList.toArray(filesTemp); - final java.io.File[] files = filesTemp; - - // Alert listener to drop. - if (listener != null) { - listener.filesDropped(c, files); - } - // Mark that drop is completed. - evt.getDropTargetContext().dropComplete(true); - log(out, "FileDrop: drop complete."); - } // end if: file list - else // this section will check for a reader flavor. - { - // Thanks, Nathan! - // BEGIN 2007-09-12 Nathan Blomquist -- Linux - // (KDE/Gnome) support added. - DataFlavor[] flavors = tr.getTransferDataFlavors(); - boolean handled = false; - for (int zz = 0; zz < flavors.length; zz++) { - if (flavors[zz].isRepresentationClassReader()) { - // Say we'll take it. - // evt.acceptDrop ( - // java.awt.dnd.DnDConstants.ACTION_COPY_OR_MOVE - // ); - evt.acceptDrop(java.awt.dnd.DnDConstants.ACTION_COPY); - log(out, "FileDrop: reader accepted."); - - Reader reader = flavors[zz] - .getReaderForText(tr); - - BufferedReader br = new BufferedReader( - reader); - - if (listener != null) { - listener.filesDropped(c, - createFileArray(br, out)); - } - - // Mark that drop is completed. - evt.getDropTargetContext().dropComplete( - true); - log(out, "FileDrop: drop complete."); - handled = true; - break; - } - } - if (!handled) { - log(out, - "FileDrop: not a file list or reader - abort."); - evt.rejectDrop(); - } - // END 2007-09-12 Nathan Blomquist -- Linux - // (KDE/Gnome) support added. - } // end else: not a file list - } // end try - catch (java.io.IOException io) { - log(out, "FileDrop: IOException - abort:"); - io.printStackTrace(out); - evt.rejectDrop(); - } // end catch IOException - catch (java.awt.datatransfer.UnsupportedFlavorException ufe) { - log(out, - "FileDrop: UnsupportedFlavorException - abort:"); - ufe.printStackTrace(out); - evt.rejectDrop(); - } // end catch: UnsupportedFlavorException - finally { - // If it's a Swing component, reset its border - if (c instanceof javax.swing.JComponent) { - javax.swing.JComponent jc = (javax.swing.JComponent) c; - jc.setBorder(FileDrop.this.normalBorder); - - log(out, "FileDrop: normal border restored."); - } // end if: JComponent - if (listener != null) { - listener.dragExit(c); - } - } // end finally - } // end drop - - @Override - public void dragExit(java.awt.dnd.DropTargetEvent evt) { - log(out, "FileDrop: dragExit event."); - // If it's a Swing component, reset its border - if (c instanceof javax.swing.JComponent) { - javax.swing.JComponent jc = (javax.swing.JComponent) c; - jc.setBorder(FileDrop.this.normalBorder); - - log(out, "FileDrop: normal border restored."); - } // end if: JComponent - if (listener != null) { - listener.dragExit(c); - } - } // end dragExit - - @Override - public void dropActionChanged( - java.awt.dnd.DropTargetDragEvent evt) { - log(out, "FileDrop: dropActionChanged event."); - // Is this an acceptable drag event? - if (FileDrop.this.isDragOk(out, evt)) { // evt.acceptDrag( - // java.awt.dnd.DnDConstants.ACTION_COPY_OR_MOVE - // ); - evt.acceptDrag(java.awt.dnd.DnDConstants.ACTION_COPY); - log(out, "FileDrop: event accepted."); - } // end if: drag ok - else { - evt.rejectDrag(); - log(out, "FileDrop: event rejected."); - } // end else: drag not ok - } // end dropActionChanged - }; // end DropTargetListener - - // Make the component (and possibly children) drop targets - this.makeDropTarget(out, c, recursive); - } // end if: supports dnd - else { - log(out, "FileDrop: Drag and drop is not supported with this JVM"); - } // end else: does not support DnD - } // end constructor - - private static boolean supportsDnD() { // Static Boolean - if (supportsDnD == null) { - boolean support = false; - try { - Class.forName("java.awt.dnd.DnDConstants"); - support = true; - } // end try - catch (Exception e) { - support = false; - } // end catch - supportsDnD = new Boolean(support); - } // end if: first time through - return supportsDnD.booleanValue(); - } // end supportsDnD - - // BEGIN 2007-09-12 Nathan Blomquist -- Linux (KDE/Gnome) support added. - private static String ZERO_CHAR_STRING = "" + (char) 0; - - private static File[] createFileArray(BufferedReader bReader, - PrintStream out) { - try { - java.util.List list = new java.util.ArrayList(); - java.lang.String line = null; - while ((line = bReader.readLine()) != null) { - try { - // kde seems to append a 0 char to the end of the reader - if (ZERO_CHAR_STRING.equals(line)) { - continue; - } - - java.io.File file = new java.io.File(new java.net.URI(line)); - list.add(file); - } catch (Exception ex) { - log(out, "Error with " + line + ": " + ex.getMessage()); - } - } - - return list.toArray(new File[list.size()]); - } catch (IOException ex) { - log(out, "FileDrop: IOException"); - } - return new File[0]; - } - - // END 2007-09-12 Nathan Blomquist -- Linux (KDE/Gnome) support added. - - private void makeDropTarget(final java.io.PrintStream out, - final java.awt.Component c, boolean recursive) { - // Make drop target - final java.awt.dnd.DropTarget dt = new java.awt.dnd.DropTarget(); - try { - dt.addDropTargetListener(this.dropListener); - } // end try - catch (java.util.TooManyListenersException e) { - e.printStackTrace(); - log(out, - "FileDrop: Drop will not work due to previous error. Do you have another listener attached?"); - } // end catch - - // Listen for hierarchy changes and remove the drop target when the - // parent gets cleared out. - c.addHierarchyListener(new java.awt.event.HierarchyListener() { - @Override - public void hierarchyChanged(java.awt.event.HierarchyEvent evt) { - log(out, "FileDrop: Hierarchy changed."); - java.awt.Component parent = c.getParent(); - if (parent == null) { - c.setDropTarget(null); - log(out, "FileDrop: Drop target cleared from component."); - } // end if: null parent - else { - new java.awt.dnd.DropTarget(c, FileDrop.this.dropListener); - log(out, "FileDrop: Drop target added to component."); - } // end else: parent not null - } // end hierarchyChanged - }); // end hierarchy listener - if (c.getParent() != null) { - new java.awt.dnd.DropTarget(c, this.dropListener); - } - - if (recursive && (c instanceof java.awt.Container)) { - // Get the container - java.awt.Container cont = (java.awt.Container) c; - - // Get it's components - java.awt.Component[] comps = cont.getComponents(); - - // Set it's components as listeners also - for (int i = 0; i < comps.length; i++) { - this.makeDropTarget(out, comps[i], recursive); - } - } // end if: recursively set components as listener - } // end dropListener - - /** Determine if the dragged data is a file list. */ - private boolean isDragOk(final java.io.PrintStream out, - final java.awt.dnd.DropTargetDragEvent evt) { - boolean ok = false; - - // Get data flavors being dragged - java.awt.datatransfer.DataFlavor[] flavors = evt - .getCurrentDataFlavors(); - - // See if any of the flavors are a file list - int i = 0; - while (!ok && i < flavors.length) { - // BEGIN 2007-09-12 Nathan Blomquist -- Linux (KDE/Gnome) support - // added. - // Is the flavor a file list? - final DataFlavor curFlavor = flavors[i]; - if (curFlavor - .equals(java.awt.datatransfer.DataFlavor.javaFileListFlavor) - || curFlavor.isRepresentationClassReader()) { - ok = true; - } - // END 2007-09-12 Nathan Blomquist -- Linux (KDE/Gnome) support - // added. - i++; - } // end while: through flavors - - // If logging is enabled, show data flavors - if (out != null) { - if (flavors.length == 0) { - log(out, "FileDrop: no data flavors."); - } - for (i = 0; i < flavors.length; i++) { - log(out, flavors[i].toString()); - } - } // end if: logging enabled - - return ok; - } // end isDragOk - - /** Outputs message to out if it's not null. */ - private static void log(java.io.PrintStream out, String message) { // Log - // message - // if - // requested - if (out != null) { - out.println(message); - } - } // end log - - /** - * Removes the drag-and-drop hooks from the component and optionally from - * the all children. You should call this if you add and remove components - * after you've set up the drag-and-drop. This will recursively unregister - * all components contained within c if c is a - * {@link java.awt.Container}. - * - * @param c - * The component to unregister as a drop target - * @since 1.0 - */ - public static boolean remove(java.awt.Component c) { - return remove(null, c, true); - } // end remove - - /** - * Removes the drag-and-drop hooks from the component and optionally from - * the all children. You should call this if you add and remove components - * after you've set up the drag-and-drop. - * - * @param out - * Optional {@link java.io.PrintStream} for logging drag and drop - * messages - * @param c - * The component to unregister - * @param recursive - * Recursively unregister components within a container - * @since 1.0 - */ - public static boolean remove(java.io.PrintStream out, java.awt.Component c, - boolean recursive) { // Make sure we support dnd. - if (supportsDnD()) { - log(out, "FileDrop: Removing drag-and-drop hooks."); - c.setDropTarget(null); - if (recursive && (c instanceof java.awt.Container)) { - java.awt.Component[] comps = ((java.awt.Container) c) - .getComponents(); - for (int i = 0; i < comps.length; i++) { - remove(out, comps[i], recursive); - } - return true; - } // end if: recursive - else { - return false; - } - } // end if: supports DnD - else { - return false; - } - } // end remove + private transient javax.swing.border.Border normalBorder; + private transient java.awt.dnd.DropTargetListener dropListener; + + /** + * Discover if the running JVM is modern enough to have drag and drop. + */ + private static Boolean supportsDnD; + + // Default border color + private static java.awt.Color defaultBorderColor = new java.awt.Color(0f, + 0f, 1f, 0.25f); + + /** + * Constructs a {@link FileDrop} with a default light-blue border and, if + * c is a {@link java.awt.Container}, recursively sets all + * elements contained within as drop targets, though only the top level + * container will change borders. + * + * @param c Component on which files will be dropped. + * @param listener Listens for filesDropped. + * @since 1.0 + */ + public FileDrop(final T c, final Listener listener) { + this(null, // Logging stream + c, // Drop target + javax.swing.BorderFactory.createMatteBorder(2, 2, 2, 2, + defaultBorderColor), // Drag border + true, // Recursive + listener); + } // end constructor + + /** + * Constructor with a default border and the option to recursively set drop + * targets. If your component is a java.awt.Container, then each of + * its children components will also listen for drops, though only the + * parent will change borders. + * + * @param c Component on which files will be dropped. + * @param recursive Recursively set children as drop targets. + * @param listener Listens for filesDropped. + * @since 1.0 + */ + public FileDrop(final T c, final boolean recursive, + final Listener listener) { + this(null, // Logging stream + c, // Drop target + javax.swing.BorderFactory.createMatteBorder(2, 2, 2, 2, + defaultBorderColor), // Drag border + recursive, // Recursive + listener); + } // end constructor + + /** + * Constructor with a default border and debugging optionally turned on. + * With Debugging turned on, more status messages will be displayed to + * out. A common way to use this constructor is with + * System.out or System.err. A null value for the + * parameter out will result in no debugging output. + * + * @param out PrintStream to record debugging info or null for no debugging. + * @param out + * @param c Component on which files will be dropped. + * @param listener Listens for filesDropped. + * @since 1.0 + */ + public FileDrop(final java.io.PrintStream out, final T c, + final Listener listener) { + this(out, // Logging stream + c, // Drop target + javax.swing.BorderFactory.createMatteBorder(2, 2, 2, 2, + defaultBorderColor), false, // Recursive + listener); + } // end constructor + + /** + * Constructor with a default border, debugging optionally turned on and the + * option to recursively set drop targets. If your component is a + * java.awt.Container, then each of its children components will + * also listen for drops, though only the parent will change borders. With + * Debugging turned on, more status messages will be displayed to + * out. A common way to use this constructor is with + * System.out or System.err. A null value for the + * parameter out will result in no debugging output. + * + * @param out PrintStream to record debugging info or null for no debugging. + * @param out + * @param c Component on which files will be dropped. + * @param recursive Recursively set children as drop targets. + * @param listener Listens for filesDropped. + * @since 1.0 + */ + public FileDrop(final java.io.PrintStream out, final T c, + final boolean recursive, final Listener listener) { + this(out, // Logging stream + c, // Drop target + javax.swing.BorderFactory.createMatteBorder(2, 2, 2, 2, + defaultBorderColor), // Drag border + recursive, // Recursive + listener); + } // end constructor + + /** + * Constructor with a specified border + * + * @param c Component on which files will be dropped. + * @param dragBorder Border to use on JComponent when dragging occurs. + * @param listener Listens for filesDropped. + * @since 1.0 + */ + public FileDrop(final T c, final javax.swing.border.Border dragBorder, + final Listener listener) { + this(null, // Logging stream + c, // Drop target + dragBorder, // Drag border + false, // Recursive + listener); + } // end constructor + + /** + * Constructor with a specified border and the option to recursively set + * drop targets. If your component is a java.awt.Container, then + * each of its children components will also listen for drops, though only + * the parent will change borders. + * + * @param c Component on which files will be dropped. + * @param dragBorder Border to use on JComponent when dragging occurs. + * @param recursive Recursively set children as drop targets. + * @param listener Listens for filesDropped. + * @since 1.0 + */ + public FileDrop(final T c, final javax.swing.border.Border dragBorder, + final boolean recursive, final Listener listener) { + this(null, c, dragBorder, recursive, listener); + } // end constructor + + /** + * Constructor with a specified border and debugging optionally turned on. + * With Debugging turned on, more status messages will be displayed to + * out. A common way to use this constructor is with + * System.out or System.err. A null value for the + * parameter out will result in no debugging output. + * + * @param out PrintStream to record debugging info or null for no debugging. + * @param c Component on which files will be dropped. + * @param dragBorder Border to use on JComponent when dragging occurs. + * @param listener Listens for filesDropped. + * @since 1.0 + */ + public FileDrop(final java.io.PrintStream out, final T c, + final javax.swing.border.Border dragBorder, + final Listener listener) { + this(out, // Logging stream + c, // Drop target + dragBorder, // Drag border + false, // Recursive + listener); + } // end constructor + + /** + * Full constructor with a specified border and debugging optionally turned + * on. With Debugging turned on, more status messages will be displayed to + * out. A common way to use this constructor is with + * System.out or System.err. A null value for the + * parameter out will result in no debugging output. + * + * @param out PrintStream to record debugging info or null for no debugging. + * @param c Component on which files will be dropped. + * @param dragBorder Border to use on JComponent when dragging occurs. + * @param recursive Recursively set children as drop targets. + * @param listener Listens for filesDropped. + * @since 1.0 + */ + public FileDrop(final java.io.PrintStream out, final T c, + final javax.swing.border.Border dragBorder, + final boolean recursive, final Listener listener) { + + if (supportsDnD()) { // Make a drop listener + this.dropListener = new java.awt.dnd.DropTargetListener() { + @Override + public void dragEnter(java.awt.dnd.DropTargetDragEvent evt) { + log(out, "FileDrop: dragEnter event."); + + // Is this an acceptable drag event? + if (FileDrop.this.isDragOk(out, evt)) { + // If it's a Swing component, set its border + if (c instanceof javax.swing.JComponent) { + javax.swing.JComponent jc = (javax.swing.JComponent) c; + FileDrop.this.normalBorder = jc.getBorder(); + log(out, "FileDrop: normal border saved."); + jc.setBorder(dragBorder); + + log(out, "FileDrop: drag border set."); + } // end if: JComponent + + if (listener != null) { + listener.dragEnter(c); + } + + // Acknowledge that it's okay to enter + // evt.acceptDrag( + // java.awt.dnd.DnDConstants.ACTION_COPY_OR_MOVE ); + evt.acceptDrag(java.awt.dnd.DnDConstants.ACTION_COPY); + log(out, "FileDrop: event accepted."); + } // end if: drag ok + else { // Reject the drag event + evt.rejectDrag(); + log(out, "FileDrop: event rejected."); + } // end else: drag not ok + } // end dragEnter + + @Override + public void dragOver(java.awt.dnd.DropTargetDragEvent evt) { + // This is called continually as long as + // the mouse is over the drag target. + } // end dragOver + + @Override + public void drop(java.awt.dnd.DropTargetDropEvent evt) { + log(out, "FileDrop: drop event."); + try { // Get whatever was dropped + java.awt.datatransfer.Transferable tr = evt + .getTransferable(); + + // Is it a file list? + if (tr.isDataFlavorSupported(java.awt.datatransfer.DataFlavor.javaFileListFlavor)) { + // Say we'll take it. + // evt.acceptDrop ( + // java.awt.dnd.DnDConstants.ACTION_COPY_OR_MOVE ); + evt.acceptDrop(java.awt.dnd.DnDConstants.ACTION_COPY); + log(out, "FileDrop: file list accepted."); + + // Get a useful list + @SuppressWarnings("unchecked") + java.util.List fileList = (java.util.List) tr + .getTransferData(java.awt.datatransfer.DataFlavor.javaFileListFlavor); + + // Convert list to array + java.io.File[] filesTemp = new java.io.File[fileList + .size()]; + fileList.toArray(filesTemp); + final java.io.File[] files = filesTemp; + + // Alert listener to drop. + if (listener != null) { + listener.filesDropped(c, files); + } + // Mark that drop is completed. + evt.getDropTargetContext().dropComplete(true); + log(out, "FileDrop: drop complete."); + } // end if: file list + else // this section will check for a reader flavor. + { + // Thanks, Nathan! + // BEGIN 2007-09-12 Nathan Blomquist -- Linux + // (KDE/Gnome) support added. + DataFlavor[] flavors = tr.getTransferDataFlavors(); + boolean handled = false; + for (int zz = 0; zz < flavors.length; zz++) { + if (flavors[zz].isRepresentationClassReader()) { + // Say we'll take it. + // evt.acceptDrop ( + // java.awt.dnd.DnDConstants.ACTION_COPY_OR_MOVE + // ); + evt.acceptDrop(java.awt.dnd.DnDConstants.ACTION_COPY); + log(out, "FileDrop: reader accepted."); + + Reader reader = flavors[zz] + .getReaderForText(tr); + + BufferedReader br = new BufferedReader( + reader); + + if (listener != null) { + listener.filesDropped(c, + createFileArray(br, out)); + } + + // Mark that drop is completed. + evt.getDropTargetContext().dropComplete( + true); + log(out, "FileDrop: drop complete."); + handled = true; + break; + } + } + if (!handled) { + log(out, + "FileDrop: not a file list or reader - abort."); + evt.rejectDrop(); + } + // END 2007-09-12 Nathan Blomquist -- Linux + // (KDE/Gnome) support added. + } // end else: not a file list + } // end try + catch (java.io.IOException io) { + log(out, "FileDrop: IOException - abort:"); + io.printStackTrace(out); + evt.rejectDrop(); + } // end catch IOException + catch (java.awt.datatransfer.UnsupportedFlavorException ufe) { + log(out, + "FileDrop: UnsupportedFlavorException - abort:"); + ufe.printStackTrace(out); + evt.rejectDrop(); + } // end catch: UnsupportedFlavorException + finally { + // If it's a Swing component, reset its border + if (c instanceof javax.swing.JComponent) { + javax.swing.JComponent jc = (javax.swing.JComponent) c; + jc.setBorder(FileDrop.this.normalBorder); + + log(out, "FileDrop: normal border restored."); + } // end if: JComponent + if (listener != null) { + listener.dragExit(c); + } + } // end finally + } // end drop + + @Override + public void dragExit(java.awt.dnd.DropTargetEvent evt) { + log(out, "FileDrop: dragExit event."); + // If it's a Swing component, reset its border + if (c instanceof javax.swing.JComponent) { + javax.swing.JComponent jc = (javax.swing.JComponent) c; + jc.setBorder(FileDrop.this.normalBorder); + + log(out, "FileDrop: normal border restored."); + } // end if: JComponent + if (listener != null) { + listener.dragExit(c); + } + } // end dragExit + + @Override + public void dropActionChanged( + java.awt.dnd.DropTargetDragEvent evt) { + log(out, "FileDrop: dropActionChanged event."); + // Is this an acceptable drag event? + if (FileDrop.this.isDragOk(out, evt)) { // evt.acceptDrag( + // java.awt.dnd.DnDConstants.ACTION_COPY_OR_MOVE + // ); + evt.acceptDrag(java.awt.dnd.DnDConstants.ACTION_COPY); + log(out, "FileDrop: event accepted."); + } // end if: drag ok + else { + evt.rejectDrag(); + log(out, "FileDrop: event rejected."); + } // end else: drag not ok + } // end dropActionChanged + }; // end DropTargetListener + + // Make the component (and possibly children) drop targets + this.makeDropTarget(out, c, recursive); + } // end if: supports dnd + else { + log(out, "FileDrop: Drag and drop is not supported with this JVM"); + } // end else: does not support DnD + } // end constructor + + private static boolean supportsDnD() { // Static Boolean + if (supportsDnD == null) { + boolean support = false; + try { + Class.forName("java.awt.dnd.DnDConstants"); + support = true; + } // end try + catch (Exception e) { + support = false; + } // end catch + supportsDnD = new Boolean(support); + } // end if: first time through + return supportsDnD.booleanValue(); + } // end supportsDnD + + // BEGIN 2007-09-12 Nathan Blomquist -- Linux (KDE/Gnome) support added. + private static String ZERO_CHAR_STRING = "" + (char) 0; + + private static File[] createFileArray(BufferedReader bReader, + PrintStream out) { + try { + java.util.List list = new java.util.ArrayList(); + java.lang.String line = null; + while ((line = bReader.readLine()) != null) { + try { + // kde seems to append a 0 char to the end of the reader + if (ZERO_CHAR_STRING.equals(line)) { + continue; + } + + java.io.File file = new java.io.File(new java.net.URI(line)); + list.add(file); + } catch (Exception ex) { + log(out, "Error with " + line + ": " + ex.getMessage()); + } + } + + return list.toArray(new File[list.size()]); + } catch (IOException ex) { + log(out, "FileDrop: IOException"); + } + return new File[0]; + } + + // END 2007-09-12 Nathan Blomquist -- Linux (KDE/Gnome) support added. + + private void makeDropTarget(final java.io.PrintStream out, + final java.awt.Component c, boolean recursive) { + // Make drop target + final java.awt.dnd.DropTarget dt = new java.awt.dnd.DropTarget(); + try { + dt.addDropTargetListener(this.dropListener); + } // end try + catch (java.util.TooManyListenersException e) { + e.printStackTrace(); + log(out, + "FileDrop: Drop will not work due to previous error. Do you have another listener attached?"); + } // end catch + + // Listen for hierarchy changes and remove the drop target when the + // parent gets cleared out. + c.addHierarchyListener(new java.awt.event.HierarchyListener() { + @Override + public void hierarchyChanged(java.awt.event.HierarchyEvent evt) { + log(out, "FileDrop: Hierarchy changed."); + java.awt.Component parent = c.getParent(); + if (parent == null) { + c.setDropTarget(null); + log(out, "FileDrop: Drop target cleared from component."); + } // end if: null parent + else { + new java.awt.dnd.DropTarget(c, FileDrop.this.dropListener); + log(out, "FileDrop: Drop target added to component."); + } // end else: parent not null + } // end hierarchyChanged + }); // end hierarchy listener + if (c.getParent() != null) { + new java.awt.dnd.DropTarget(c, this.dropListener); + } + + if (recursive && (c instanceof java.awt.Container)) { + // Get the container + java.awt.Container cont = (java.awt.Container) c; + + // Get it's components + java.awt.Component[] comps = cont.getComponents(); + + // Set it's components as listeners also + for (int i = 0; i < comps.length; i++) { + this.makeDropTarget(out, comps[i], recursive); + } + } // end if: recursively set components as listener + } // end dropListener + + /** + * Determine if the dragged data is a file list. + */ + private boolean isDragOk(final java.io.PrintStream out, + final java.awt.dnd.DropTargetDragEvent evt) { + boolean ok = false; + + // Get data flavors being dragged + java.awt.datatransfer.DataFlavor[] flavors = evt + .getCurrentDataFlavors(); + + // See if any of the flavors are a file list + int i = 0; + while (!ok && i < flavors.length) { + // BEGIN 2007-09-12 Nathan Blomquist -- Linux (KDE/Gnome) support + // added. + // Is the flavor a file list? + final DataFlavor curFlavor = flavors[i]; + if (curFlavor + .equals(java.awt.datatransfer.DataFlavor.javaFileListFlavor) + || curFlavor.isRepresentationClassReader()) { + ok = true; + } + // END 2007-09-12 Nathan Blomquist -- Linux (KDE/Gnome) support + // added. + i++; + } // end while: through flavors + + // If logging is enabled, show data flavors + if (out != null) { + if (flavors.length == 0) { + log(out, "FileDrop: no data flavors."); + } + for (i = 0; i < flavors.length; i++) { + log(out, flavors[i].toString()); + } + } // end if: logging enabled + + return ok; + } // end isDragOk + + /** + * Outputs message to out if it's not null. + */ + private static void log(java.io.PrintStream out, String message) { // Log + // message + // if + // requested + if (out != null) { + out.println(message); + } + } // end log + + /** + * Removes the drag-and-drop hooks from the component and optionally from + * the all children. You should call this if you add and remove components + * after you've set up the drag-and-drop. This will recursively unregister + * all components contained within c if c is a + * {@link java.awt.Container}. + * + * @param c The component to unregister as a drop target + * @since 1.0 + */ + public static boolean remove(java.awt.Component c) { + return remove(null, c, true); + } // end remove + + /** + * Removes the drag-and-drop hooks from the component and optionally from + * the all children. You should call this if you add and remove components + * after you've set up the drag-and-drop. + * + * @param out Optional {@link java.io.PrintStream} for logging drag and drop + * messages + * @param c The component to unregister + * @param recursive Recursively unregister components within a container + * @since 1.0 + */ + public static boolean remove(java.io.PrintStream out, java.awt.Component c, + boolean recursive) { // Make sure we support dnd. + if (supportsDnD()) { + log(out, "FileDrop: Removing drag-and-drop hooks."); + c.setDropTarget(null); + if (recursive && (c instanceof java.awt.Container)) { + java.awt.Component[] comps = ((java.awt.Container) c) + .getComponents(); + for (int i = 0; i < comps.length; i++) { + remove(out, comps[i], recursive); + } + return true; + } // end if: recursive + else { + return false; + } + } // end if: supports DnD + else { + return false; + } + } // end remove /* ******** I N N E R I N T E R F A C E L I S T E N E R ******** */ - /** - * Implement this inner interface to listen for when files are dropped. For - * example your class declaration may begin like this:
-	 *      public class MyClass implements FileDrop.Listener
-	 *      ...
-	 *      public void filesDropped( java.io.File[] files )
-	 *      {
-	 *          ...
-	 *      }   // end filesDropped
-	 *      ...
-	 * 
- * - * @since 1.1 - */ - public static interface Listener { - - /** - * This method is called when files have been successfully dropped. - * - * @param files - * An array of Files that were dropped. - * @since 1.0 - */ - public abstract void filesDropped(T source, java.io.File[] files); - - public abstract void dragEnter(T source); - - public abstract void dragExit(T source); - - } // end inner-interface Listener + /** + * Implement this inner interface to listen for when files are dropped. For + * example your class declaration may begin like this:
+     *      public class MyClass implements FileDrop.Listener
+     *      ...
+     *      public void filesDropped( java.io.File[] files )
+     *      {
+     *          ...
+     *      }   // end filesDropped
+     *      ...
+     * 
+ * + * @since 1.1 + */ + public static interface Listener { + + /** + * This method is called when files have been successfully dropped. + * + * @param files An array of Files that were dropped. + * @since 1.0 + */ + public abstract void filesDropped(T source, java.io.File[] files); + + public abstract void dragEnter(T source); + + public abstract void dragExit(T source); + + } // end inner-interface Listener /* ******** I N N E R C L A S S ******** */ - /** - * This is the event that is passed to the - * {@link FileDropListener#filesDropped filesDropped(...)} method in your - * {@link FileDropListener} when files are dropped onto a registered drop - * target. - * - *

- * I'm releasing this code into the Public Domain. Enjoy. - *

- * - * @author Robert Harder - * @author rob@iharder.net - * @version 1.2 - */ - public static class Event extends java.util.EventObject { - - private static final long serialVersionUID = 6145536635297645995L; - - private java.io.File[] files; - - /** - * Constructs an {@link Event} with the array of files that were dropped - * and the {@link FileDrop} that initiated the event. - * - * @param files - * The array of files that were dropped - * @source The event source - * @since 1.1 - */ - public Event(java.io.File[] files, Object source) { - super(source); - this.files = files; - } // end constructor - - /** - * Returns an array of files that were dropped on a registered drop - * target. - * - * @return array of files that were dropped - * @since 1.1 - */ - public java.io.File[] getFiles() { - return this.files; - } // end getFiles - - } // end inner class Event + /** + * This is the event that is passed to the + * {@link FileDropListener#filesDropped filesDropped(...)} method in your + * {@link FileDropListener} when files are dropped onto a registered drop + * target. + *

+ *

+ * I'm releasing this code into the Public Domain. Enjoy. + *

+ * + * @author Robert Harder + * @author rob@iharder.net + * @version 1.2 + */ + public static class Event extends java.util.EventObject { + + private static final long serialVersionUID = 6145536635297645995L; + + private java.io.File[] files; + + /** + * Constructs an {@link Event} with the array of files that were dropped + * and the {@link FileDrop} that initiated the event. + * + * @param files The array of files that were dropped + * @source The event source + * @since 1.1 + */ + public Event(java.io.File[] files, Object source) { + super(source); + this.files = files; + } // end constructor + + /** + * Returns an array of files that were dropped on a registered drop + * target. + * + * @return array of files that were dropped + * @since 1.1 + */ + public java.io.File[] getFiles() { + return this.files; + } // end getFiles + + } // end inner class Event /* ******** I N N E R C L A S S ******** */ - /** - * At last an easy way to encapsulate your custom objects for dragging and - * dropping in your Java programs! When you need to create a - * {@link java.awt.datatransfer.Transferable} object, use this class to wrap - * your object. For example: - * - *
-	 * 
-	 *      ...
-	 *      MyCoolClass myObj = new MyCoolClass();
-	 *      Transferable xfer = new TransferableObject( myObj );
-	 *      ...
-	 * 
-	 * 
- * - * Or if you need to know when the data was actually dropped, like when - * you're moving data out of a list, say, you can use the - * {@link TransferableObject.Fetcher} inner class to return your object Just - * in Time. For example: - * - *
-	 * 
-	 *      ...
-	 *      final MyCoolClass myObj = new MyCoolClass();
-	 * 
-	 *      TransferableObject.Fetcher fetcher = new TransferableObject.Fetcher()
-	 *      {   public Object getObject(){ return myObj; }
-	 *      }; // end fetcher
-	 * 
-	 *      Transferable xfer = new TransferableObject( fetcher );
-	 *      ...
-	 * 
-	 * 
- * - * The {@link java.awt.datatransfer.DataFlavor} associated with - * {@link TransferableObject} has the representation class - * net.iharder.dnd.TransferableObject.class and MIME type - * application/x-net.iharder.dnd.TransferableObject. This data - * flavor is accessible via the static {@link #DATA_FLAVOR} property. - * - * - *

- * I'm releasing this code into the Public Domain. Enjoy. - *

- * - * @author Robert Harder - * @author rob@iharder.net - * @version 1.2 - */ - public static class TransferableObject implements - java.awt.datatransfer.Transferable { - /** - * The MIME type for {@link #DATA_FLAVOR} is - * application/x-net.iharder.dnd.TransferableObject. - * - * @since 1.1 - */ - public final static String MIME_TYPE = "application/x-net.iharder.dnd.TransferableObject"; - - /** - * The default {@link java.awt.datatransfer.DataFlavor} for - * {@link TransferableObject} has the representation class - * net.iharder.dnd.TransferableObject.class and the MIME type - * application/x-net.iharder.dnd.TransferableObject. - * - * @since 1.1 - */ - public final static java.awt.datatransfer.DataFlavor DATA_FLAVOR = new java.awt.datatransfer.DataFlavor( - FileDrop.TransferableObject.class, MIME_TYPE); - - private Fetcher fetcher; - private Object data; - - private java.awt.datatransfer.DataFlavor customFlavor; - - /** - * Creates a new {@link TransferableObject} that wraps data. - * Along with the {@link #DATA_FLAVOR} associated with this class, this - * creates a custom data flavor with a representation class determined - * from data.getClass() and the MIME type - * application/x-net.iharder.dnd.TransferableObject. - * - * @param data - * The data to transfer - * @since 1.1 - */ - public TransferableObject(Object data) { - this.data = data; - this.customFlavor = new java.awt.datatransfer.DataFlavor( - data.getClass(), MIME_TYPE); - } // end constructor - - /** - * Creates a new {@link TransferableObject} that will return the object - * that is returned by fetcher. No custom data flavor is set - * other than the default {@link #DATA_FLAVOR}. - * - * @see Fetcher - * @param fetcher - * The {@link Fetcher} that will return the data object - * @since 1.1 - */ - public TransferableObject(Fetcher fetcher) { - this.fetcher = fetcher; - } // end constructor - - /** - * Creates a new {@link TransferableObject} that will return the object - * that is returned by fetcher. Along with the - * {@link #DATA_FLAVOR} associated with this class, this creates a - * custom data flavor with a representation class dataClass - * and the MIME type - * application/x-net.iharder.dnd.TransferableObject. - * - * @see Fetcher - * @param dataClass - * The {@link java.lang.Class} to use in the custom data - * flavor - * @param fetcher - * The {@link Fetcher} that will return the data object - * @since 1.1 - */ - @SuppressWarnings("rawtypes") - public TransferableObject(Class dataClass, Fetcher fetcher) { - this.fetcher = fetcher; - this.customFlavor = new java.awt.datatransfer.DataFlavor(dataClass, - MIME_TYPE); - } // end constructor - - /** - * Returns the custom {@link java.awt.datatransfer.DataFlavor} - * associated with the encapsulated object or null if the - * {@link Fetcher} constructor was used without passing a - * {@link java.lang.Class}. - * - * @return The custom data flavor for the encapsulated object - * @since 1.1 - */ - public java.awt.datatransfer.DataFlavor getCustomDataFlavor() { - return this.customFlavor; - } // end getCustomDataFlavor + /** + * At last an easy way to encapsulate your custom objects for dragging and + * dropping in your Java programs! When you need to create a + * {@link java.awt.datatransfer.Transferable} object, use this class to wrap + * your object. For example: + *

+ *

+     * 
+     *      ...
+     *      MyCoolClass myObj = new MyCoolClass();
+     *      Transferable xfer = new TransferableObject( myObj );
+     *      ...
+     * 
+     * 
+ *

+ * Or if you need to know when the data was actually dropped, like when + * you're moving data out of a list, say, you can use the + * {@link TransferableObject.Fetcher} inner class to return your object Just + * in Time. For example: + *

+ *

+     * 
+     *      ...
+     *      final MyCoolClass myObj = new MyCoolClass();
+     *
+     *      TransferableObject.Fetcher fetcher = new TransferableObject.Fetcher()
+     *      {   public Object getObject(){ return myObj; }
+     *      }; // end fetcher
+     *
+     *      Transferable xfer = new TransferableObject( fetcher );
+     *      ...
+     * 
+     * 
+ *

+ * The {@link java.awt.datatransfer.DataFlavor} associated with + * {@link TransferableObject} has the representation class + * net.iharder.dnd.TransferableObject.class and MIME type + * application/x-net.iharder.dnd.TransferableObject. This data + * flavor is accessible via the static {@link #DATA_FLAVOR} property. + *

+ *

+ *

+ * I'm releasing this code into the Public Domain. Enjoy. + *

+ * + * @author Robert Harder + * @author rob@iharder.net + * @version 1.2 + */ + public static class TransferableObject implements + java.awt.datatransfer.Transferable { + /** + * The MIME type for {@link #DATA_FLAVOR} is + * application/x-net.iharder.dnd.TransferableObject. + * + * @since 1.1 + */ + public final static String MIME_TYPE = "application/x-net.iharder.dnd.TransferableObject"; + + /** + * The default {@link java.awt.datatransfer.DataFlavor} for + * {@link TransferableObject} has the representation class + * net.iharder.dnd.TransferableObject.class and the MIME type + * application/x-net.iharder.dnd.TransferableObject. + * + * @since 1.1 + */ + public final static java.awt.datatransfer.DataFlavor DATA_FLAVOR = new java.awt.datatransfer.DataFlavor( + FileDrop.TransferableObject.class, MIME_TYPE); + + private Fetcher fetcher; + private Object data; + + private java.awt.datatransfer.DataFlavor customFlavor; + + /** + * Creates a new {@link TransferableObject} that wraps data. + * Along with the {@link #DATA_FLAVOR} associated with this class, this + * creates a custom data flavor with a representation class determined + * from data.getClass() and the MIME type + * application/x-net.iharder.dnd.TransferableObject. + * + * @param data The data to transfer + * @since 1.1 + */ + public TransferableObject(Object data) { + this.data = data; + this.customFlavor = new java.awt.datatransfer.DataFlavor( + data.getClass(), MIME_TYPE); + } // end constructor + + /** + * Creates a new {@link TransferableObject} that will return the object + * that is returned by fetcher. No custom data flavor is set + * other than the default {@link #DATA_FLAVOR}. + * + * @param fetcher The {@link Fetcher} that will return the data object + * @see Fetcher + * @since 1.1 + */ + public TransferableObject(Fetcher fetcher) { + this.fetcher = fetcher; + } // end constructor + + /** + * Creates a new {@link TransferableObject} that will return the object + * that is returned by fetcher. Along with the + * {@link #DATA_FLAVOR} associated with this class, this creates a + * custom data flavor with a representation class dataClass + * and the MIME type + * application/x-net.iharder.dnd.TransferableObject. + * + * @param dataClass The {@link java.lang.Class} to use in the custom data + * flavor + * @param fetcher The {@link Fetcher} that will return the data object + * @see Fetcher + * @since 1.1 + */ + @SuppressWarnings("rawtypes") + public TransferableObject(Class dataClass, Fetcher fetcher) { + this.fetcher = fetcher; + this.customFlavor = new java.awt.datatransfer.DataFlavor(dataClass, + MIME_TYPE); + } // end constructor + + /** + * Returns the custom {@link java.awt.datatransfer.DataFlavor} + * associated with the encapsulated object or null if the + * {@link Fetcher} constructor was used without passing a + * {@link java.lang.Class}. + * + * @return The custom data flavor for the encapsulated object + * @since 1.1 + */ + public java.awt.datatransfer.DataFlavor getCustomDataFlavor() { + return this.customFlavor; + } // end getCustomDataFlavor /* ******** T R A N S F E R A B L E M E T H O D S ******** */ - /** - * Returns a two- or three-element array containing first the custom - * data flavor, if one was created in the constructors, second the - * default {@link #DATA_FLAVOR} associated with - * {@link TransferableObject}, and third the - * {@link java.awt.datatransfer.DataFlavor.stringFlavor}. - * - * @return An array of supported data flavors - * @since 1.1 - */ - @Override - public java.awt.datatransfer.DataFlavor[] getTransferDataFlavors() { - if (this.customFlavor != null) { - return new java.awt.datatransfer.DataFlavor[] { - this.customFlavor, DATA_FLAVOR, - java.awt.datatransfer.DataFlavor.stringFlavor }; // end - // flavors - // array - } else { - return new java.awt.datatransfer.DataFlavor[] { DATA_FLAVOR, - java.awt.datatransfer.DataFlavor.stringFlavor }; // end - // flavors - // array - } - } // end getTransferDataFlavors - - /** - * Returns the data encapsulated in this {@link TransferableObject}. If - * the {@link Fetcher} constructor was used, then this is when the - * {@link Fetcher#getObject getObject()} method will be called. If the - * requested data flavor is not supported, then the - * {@link Fetcher#getObject getObject()} method will not be called. - * - * @param flavor - * The data flavor for the data to return - * @return The dropped data - * @since 1.1 - */ - @Override - public Object getTransferData(java.awt.datatransfer.DataFlavor flavor) - throws java.awt.datatransfer.UnsupportedFlavorException, - java.io.IOException { - // Native object - if (flavor.equals(DATA_FLAVOR)) { - return this.fetcher == null ? this.data : this.fetcher - .getObject(); - } - - // String - if (flavor.equals(java.awt.datatransfer.DataFlavor.stringFlavor)) { - return this.fetcher == null ? this.data.toString() - : this.fetcher.getObject().toString(); - } - - // We can't do anything else - throw new java.awt.datatransfer.UnsupportedFlavorException(flavor); - } // end getTransferData - - /** - * Returns true if flavor is one of the supported - * flavors. Flavors are supported using the equals(...) - * method. - * - * @param flavor - * The data flavor to check - * @return Whether or not the flavor is supported - * @since 1.1 - */ - @Override - public boolean isDataFlavorSupported( - java.awt.datatransfer.DataFlavor flavor) { - // Native object - if (flavor.equals(DATA_FLAVOR)) { - return true; - } - - // String - if (flavor.equals(java.awt.datatransfer.DataFlavor.stringFlavor)) { - return true; - } - - // We can't do anything else - return false; - } // end isDataFlavorSupported + /** + * Returns a two- or three-element array containing first the custom + * data flavor, if one was created in the constructors, second the + * default {@link #DATA_FLAVOR} associated with + * {@link TransferableObject}, and third the + * {@link java.awt.datatransfer.DataFlavor.stringFlavor}. + * + * @return An array of supported data flavors + * @since 1.1 + */ + @Override + public java.awt.datatransfer.DataFlavor[] getTransferDataFlavors() { + if (this.customFlavor != null) { + return new java.awt.datatransfer.DataFlavor[]{ + this.customFlavor, DATA_FLAVOR, + java.awt.datatransfer.DataFlavor.stringFlavor}; // end + // flavors + // array + } else { + return new java.awt.datatransfer.DataFlavor[]{DATA_FLAVOR, + java.awt.datatransfer.DataFlavor.stringFlavor}; // end + // flavors + // array + } + } // end getTransferDataFlavors + + /** + * Returns the data encapsulated in this {@link TransferableObject}. If + * the {@link Fetcher} constructor was used, then this is when the + * {@link Fetcher#getObject getObject()} method will be called. If the + * requested data flavor is not supported, then the + * {@link Fetcher#getObject getObject()} method will not be called. + * + * @param flavor The data flavor for the data to return + * @return The dropped data + * @since 1.1 + */ + @Override + public Object getTransferData(java.awt.datatransfer.DataFlavor flavor) + throws java.awt.datatransfer.UnsupportedFlavorException, + java.io.IOException { + // Native object + if (flavor.equals(DATA_FLAVOR)) { + return this.fetcher == null ? this.data : this.fetcher + .getObject(); + } + + // String + if (flavor.equals(java.awt.datatransfer.DataFlavor.stringFlavor)) { + return this.fetcher == null ? this.data.toString() + : this.fetcher.getObject().toString(); + } + + // We can't do anything else + throw new java.awt.datatransfer.UnsupportedFlavorException(flavor); + } // end getTransferData + + /** + * Returns true if flavor is one of the supported + * flavors. Flavors are supported using the equals(...) + * method. + * + * @param flavor The data flavor to check + * @return Whether or not the flavor is supported + * @since 1.1 + */ + @Override + public boolean isDataFlavorSupported( + java.awt.datatransfer.DataFlavor flavor) { + // Native object + if (flavor.equals(DATA_FLAVOR)) { + return true; + } + + // String + if (flavor.equals(java.awt.datatransfer.DataFlavor.stringFlavor)) { + return true; + } + + // We can't do anything else + return false; + } // end isDataFlavorSupported /* ******** I N N E R I N T E R F A C E F E T C H E R ******** */ - /** - * Instead of passing your data directly to the - * {@link TransferableObject} constructor, you may want to know exactly - * when your data was received in case you need to remove it from its - * source (or do anyting else to it). When the {@link #getTransferData - * getTransferData(...)} method is called on the - * {@link TransferableObject}, the {@link Fetcher}'s {@link #getObject - * getObject()} method will be called. - * - * @author Robert Harder - * @copyright 2001 - * @version 1.1 - * @since 1.1 - */ - public static interface Fetcher { - /** - * Return the object being encapsulated in the - * {@link TransferableObject}. - * - * @return The dropped object - * @since 1.1 - */ - public abstract Object getObject(); - } // end inner interface Fetcher - - } // end class TransferableObject + /** + * Instead of passing your data directly to the + * {@link TransferableObject} constructor, you may want to know exactly + * when your data was received in case you need to remove it from its + * source (or do anyting else to it). When the {@link #getTransferData + * getTransferData(...)} method is called on the + * {@link TransferableObject}, the {@link Fetcher}'s {@link #getObject + * getObject()} method will be called. + * + * @author Robert Harder + * @version 1.1 + * @copyright 2001 + * @since 1.1 + */ + public static interface Fetcher { + /** + * Return the object being encapsulated in the + * {@link TransferableObject}. + * + * @return The dropped object + * @since 1.1 + */ + public abstract Object getObject(); + } // end inner interface Fetcher + + } // end class TransferableObject } // end class FileDrop diff --git a/src/net/redwarp/tool/resizer/FileTools.java b/src/net/redwarp/tool/resizer/FileTools.java index a7b1738..c613dfb 100644 --- a/src/net/redwarp/tool/resizer/FileTools.java +++ b/src/net/redwarp/tool/resizer/FileTools.java @@ -1,6 +1,4 @@ /* - * Copyright 2012 redwarp - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,36 +10,32 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * Copyright 2013 Redwarp */ package net.redwarp.tool.resizer; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; +import java.io.*; public class FileTools { - public static void copyfile(File input, File output) { - try { - InputStream in = new FileInputStream(input); - OutputStream out = new FileOutputStream(output); + public static void copyfile(File input, File output) { + try { + InputStream in = new FileInputStream(input); + OutputStream out = new FileOutputStream(output); - byte[] buf = new byte[1024]; - int len; - while ((len = in.read(buf)) > 0) { - out.write(buf, 0, len); - } - in.close(); - out.close(); - } catch (FileNotFoundException ex) { - System.out - .println(ex.getMessage() + " in the specified directory."); - System.exit(0); - } catch (IOException e) { - System.out.println(e.getMessage()); - } - } + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + in.close(); + out.close(); + } catch (FileNotFoundException ex) { + System.out + .println(ex.getMessage() + " in the specified directory."); + System.exit(0); + } catch (IOException e) { + System.out.println(e.getMessage()); + } + } } \ No newline at end of file diff --git a/src/net/redwarp/tool/resizer/Main.java b/src/net/redwarp/tool/resizer/Main.java index b8af067..9d947c4 100644 --- a/src/net/redwarp/tool/resizer/Main.java +++ b/src/net/redwarp/tool/resizer/Main.java @@ -1,6 +1,4 @@ /* - * Copyright 2012 redwarp - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,34 +10,35 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * Copyright 2013 Redwarp */ package net.redwarp.tool.resizer; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; - import net.redwarp.tool.resizer.misc.Localization; import net.redwarp.tool.resizer.views.MainWindow; +import javax.swing.*; + public class Main { - public static void main(String[] args) { - // Apple only stuff - System.setProperty("apple.laf.useScreenMenuBar", "true"); - System.setProperty("com.apple.mrj.application.apple.menu.about.name", - Localization.get("app_name")); + public static void main(String[] args) { + // Apple only stuff + System.setProperty("apple.laf.useScreenMenuBar", "true"); + System.setProperty("com.apple.mrj.application.apple.menu.about.name", + Localization.get("app_name")); - try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (UnsupportedLookAndFeelException e) { - e.printStackTrace(); - } + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (UnsupportedLookAndFeelException e) { + e.printStackTrace(); + } - new MainWindow().setVisible(true); - } + new MainWindow().setVisible(true); + } } diff --git a/src/net/redwarp/tool/resizer/misc/Localization.java b/src/net/redwarp/tool/resizer/misc/Localization.java index 82a3a29..cdd6f23 100644 --- a/src/net/redwarp/tool/resizer/misc/Localization.java +++ b/src/net/redwarp/tool/resizer/misc/Localization.java @@ -1,6 +1,4 @@ /* - * Copyright 2012 redwarp - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,6 +10,8 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * Copyright 2013 Redwarp */ package net.redwarp.tool.resizer.misc; @@ -20,21 +20,21 @@ import java.util.ResourceBundle; public class Localization { - private static ResourceBundle bundle = ResourceBundle.getBundle( - "locale.Strings", Locale.getDefault(), new MyResourceControl()); + private static ResourceBundle bundle = ResourceBundle.getBundle( + "locale.Strings", Locale.getDefault(), new MyResourceControl()); - public static String get(String key) { - try { - return bundle.getString(key); - } catch (MissingResourceException e) { - return new String(key); - } - } + public static String get(String key) { + try { + return bundle.getString(key); + } catch (MissingResourceException e) { + return new String(key); + } + } - private static class MyResourceControl extends ResourceBundle.Control { - @Override - public Locale getFallbackLocale(String baseName, Locale locale) { - return null; - } - } + private static class MyResourceControl extends ResourceBundle.Control { + @Override + public Locale getFallbackLocale(String baseName, Locale locale) { + return null; + } + } } diff --git a/src/net/redwarp/tool/resizer/misc/Preferences.java b/src/net/redwarp/tool/resizer/misc/Preferences.java index d4483e3..269e035 100644 --- a/src/net/redwarp/tool/resizer/misc/Preferences.java +++ b/src/net/redwarp/tool/resizer/misc/Preferences.java @@ -1,6 +1,4 @@ /* - * Copyright 2012 redwarp - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,6 +10,8 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * Copyright 2013 Redwarp */ package net.redwarp.tool.resizer.misc; @@ -19,10 +19,10 @@ import java.util.ResourceBundle; public class Preferences { - private static ResourceBundle bundle = ResourceBundle.getBundle( - "misc.preferences", Locale.FRANCE); + private static ResourceBundle bundle = ResourceBundle.getBundle( + "misc.preferences", Locale.FRANCE); - public static String getVersion() { - return bundle.getString("version"); - } + public static String getVersion() { + return bundle.getString("version"); + } } diff --git a/src/net/redwarp/tool/resizer/table/Operation.java b/src/net/redwarp/tool/resizer/table/Operation.java index a5c13a3..e94298d 100644 --- a/src/net/redwarp/tool/resizer/table/Operation.java +++ b/src/net/redwarp/tool/resizer/table/Operation.java @@ -1,6 +1,4 @@ /* - * Copyright 2012 redwarp - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,40 +10,42 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * Copyright 2013 Redwarp */ package net.redwarp.tool.resizer.table; import java.io.File; public class Operation { - private volatile OperationStatus status; - private File file; - private String message = null; - - public Operation(File f) { - this.file = f; - this.status = OperationStatus.PENDING; - } - - public OperationStatus getStatus() { - return this.status; - } - - public File getFile() { - return this.file; - } - - public void setStatus(OperationStatus status) { - this.status = status; - this.message = null; - } - - public void setStatus(OperationStatus status, String message) { - this.status = status; - this.message = message; - } - - public String getMessage() { - return this.message; - } + private volatile OperationStatus status; + private File file; + private String message = null; + + public Operation(File f) { + this.file = f; + this.status = OperationStatus.PENDING; + } + + public OperationStatus getStatus() { + return this.status; + } + + public File getFile() { + return this.file; + } + + public void setStatus(OperationStatus status) { + this.status = status; + this.message = null; + } + + public void setStatus(OperationStatus status, String message) { + this.status = status; + this.message = message; + } + + public String getMessage() { + return this.message; + } } diff --git a/src/net/redwarp/tool/resizer/table/OperationStatus.java b/src/net/redwarp/tool/resizer/table/OperationStatus.java index 2324be6..0ecc790 100644 --- a/src/net/redwarp/tool/resizer/table/OperationStatus.java +++ b/src/net/redwarp/tool/resizer/table/OperationStatus.java @@ -1,6 +1,4 @@ /* - * Copyright 2012 redwarp - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,9 +10,11 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * Copyright 2013 Redwarp */ package net.redwarp.tool.resizer.table; public enum OperationStatus { - PENDING, IN_PROGRESS, FINISH, ERROR + PENDING, IN_PROGRESS, FINISH, ERROR } diff --git a/src/net/redwarp/tool/resizer/table/ResultModel.java b/src/net/redwarp/tool/resizer/table/ResultModel.java index 91d372c..b99a836 100644 --- a/src/net/redwarp/tool/resizer/table/ResultModel.java +++ b/src/net/redwarp/tool/resizer/table/ResultModel.java @@ -1,6 +1,4 @@ /* - * Copyright 2012 redwarp - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,79 +10,80 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * Copyright 2013 Redwarp */ package net.redwarp.tool.resizer.table; +import net.redwarp.tool.resizer.misc.Localization; + +import javax.swing.table.AbstractTableModel; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import javax.swing.table.AbstractTableModel; - -import net.redwarp.tool.resizer.misc.Localization; - public class ResultModel extends AbstractTableModel { - private static final long serialVersionUID = -6799282358729483044L; - private List operationList; - private String[] columns = new String[] { Localization.get("column_name"), - Localization.get("column_status") }; + private static final long serialVersionUID = -6799282358729483044L; + private List operationList; + private String[] columns = new String[]{Localization.get("column_name"), + Localization.get("column_status")}; - public ResultModel() { - this.operationList = new ArrayList(); - } + public ResultModel() { + this.operationList = new ArrayList(); + } - @Override - public synchronized int getRowCount() { - return this.operationList.size(); - } + @Override + public synchronized int getRowCount() { + return this.operationList.size(); + } - @Override - public int getColumnCount() { - return 2; - } + @Override + public int getColumnCount() { + return 2; + } - @Override - public synchronized Object getValueAt(int rowIndex, int columnIndex) { - switch (columnIndex) { - case 0: - return this.operationList.get(rowIndex).getFile().getName(); - case 1: - return this.operationList.get(rowIndex); - default: - return ""; - } - } + @Override + public synchronized Object getValueAt(int rowIndex, int columnIndex) { + switch (columnIndex) { + case 0: + return this.operationList.get(rowIndex).getFile().getName(); + case 1: + return this.operationList.get(rowIndex); + default: + return ""; + } + } - public synchronized void addOperation(Operation operation) { - this.operationList.add(operation); - int rowIndex = this.operationList.size() - 1; - this.fireTableRowsInserted(rowIndex, rowIndex); - } + public synchronized void addOperation(Operation operation) { + this.operationList.add(operation); + int rowIndex = this.operationList.size() - 1; + this.fireTableRowsInserted(rowIndex, rowIndex); + } - @Override - public String getColumnName(int column) { - return this.columns[column]; - } + @Override + public String getColumnName(int column) { + return this.columns[column]; + } - public synchronized void notifyChange(Operation operation) { - int row = this.operationList.indexOf(operation); - if (row != -1) { - this.fireTableCellUpdated(row, 1); - this.fireTableCellUpdated(row, 2); - } - } + public synchronized void notifyChange(Operation operation) { + int row = this.operationList.indexOf(operation); + if (row != -1) { + this.fireTableCellUpdated(row, 1); + this.fireTableCellUpdated(row, 2); + } + } - public synchronized void clear() { - Iterator itor = this.operationList.iterator(); - while (itor.hasNext()) { - Operation op = itor.next(); - OperationStatus status = op.getStatus(); - if (status == OperationStatus.FINISH - || status == OperationStatus.ERROR) { - itor.remove(); - } - } - this.fireTableDataChanged(); - } + public synchronized void clear() { + Iterator itor = this.operationList.iterator(); + while (itor.hasNext()) { + Operation op = itor.next(); + OperationStatus status = op.getStatus(); + if (status == OperationStatus.FINISH + || status == OperationStatus.ERROR) { + itor.remove(); + } + } + this.fireTableDataChanged(); + } } diff --git a/src/net/redwarp/tool/resizer/table/ResultTable.java b/src/net/redwarp/tool/resizer/table/ResultTable.java index fa30780..89a742a 100644 --- a/src/net/redwarp/tool/resizer/table/ResultTable.java +++ b/src/net/redwarp/tool/resizer/table/ResultTable.java @@ -1,6 +1,4 @@ /* - * Copyright 2012 redwarp - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,38 +10,39 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * Copyright 2013 Redwarp */ package net.redwarp.tool.resizer.table; -import java.awt.Dimension; - -import javax.swing.JTable; +import javax.swing.*; +import java.awt.*; public class ResultTable extends JTable { - private static final long serialVersionUID = -8240707430938246389L; - private ResultModel model; - - public ResultTable() { - this.model = new ResultModel(); - this.setModel(this.model); - this.getColumnModel().getColumn(1) - .setCellRenderer(new StatusCellRenderer()); - this.setIntercellSpacing(new Dimension(5, 0)); - this.setRowHeight(20); - - this.setRowSelectionAllowed(false); - this.setFillsViewportHeight(true); - } - - public void addOperation(Operation operation) { - this.model.addOperation(operation); - } - - public void notifyChange(Operation operation) { - this.model.notifyChange(operation); - } - - public void clear() { - this.model.clear(); - } + private static final long serialVersionUID = -8240707430938246389L; + private ResultModel model; + + public ResultTable() { + this.model = new ResultModel(); + this.setModel(this.model); + this.getColumnModel().getColumn(1) + .setCellRenderer(new StatusCellRenderer()); + this.setIntercellSpacing(new Dimension(5, 0)); + this.setRowHeight(20); + + this.setRowSelectionAllowed(false); + this.setFillsViewportHeight(true); + } + + public void addOperation(Operation operation) { + this.model.addOperation(operation); + } + + public void notifyChange(Operation operation) { + this.model.notifyChange(operation); + } + + public void clear() { + this.model.clear(); + } } diff --git a/src/net/redwarp/tool/resizer/table/StatusCellRenderer.java b/src/net/redwarp/tool/resizer/table/StatusCellRenderer.java index c707115..46c88d7 100644 --- a/src/net/redwarp/tool/resizer/table/StatusCellRenderer.java +++ b/src/net/redwarp/tool/resizer/table/StatusCellRenderer.java @@ -1,6 +1,4 @@ /* - * Copyright 2012 redwarp - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,64 +10,63 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * Copyright 2013 Redwarp */ package net.redwarp.tool.resizer.table; -import java.awt.Component; +import net.redwarp.tool.resizer.misc.Localization; -import javax.swing.ImageIcon; -import javax.swing.JLabel; -import javax.swing.JTable; +import javax.swing.*; import javax.swing.table.DefaultTableCellRenderer; - -import net.redwarp.tool.resizer.misc.Localization; +import java.awt.*; public class StatusCellRenderer extends DefaultTableCellRenderer { - private static final long serialVersionUID = 518341333665088552L; - private ImageIcon iconSuccess = new ImageIcon( - StatusCellRenderer.class.getResource("/img/valid.png")); - private ImageIcon iconError = new ImageIcon( - StatusCellRenderer.class.getResource("/img/error.png")); + private static final long serialVersionUID = 518341333665088552L; + private ImageIcon iconSuccess = new ImageIcon( + StatusCellRenderer.class.getResource("/img/valid.png")); + private ImageIcon iconError = new ImageIcon( + StatusCellRenderer.class.getResource("/img/error.png")); - public StatusCellRenderer() { - this.setHorizontalAlignment(LEADING); - this.setVerticalAlignment(CENTER); - } + public StatusCellRenderer() { + this.setHorizontalAlignment(LEADING); + this.setVerticalAlignment(CENTER); + } - @Override - public Component getTableCellRendererComponent(JTable table, Object value, - boolean isSelected, boolean hasFocus, int row, int column) { + @Override + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { - JLabel label = (JLabel) super.getTableCellRendererComponent(table, - value, isSelected, hasFocus, row, column); - label.setIcon(null); - label.setText(null); + JLabel label = (JLabel) super.getTableCellRendererComponent(table, + value, isSelected, hasFocus, row, column); + label.setIcon(null); + label.setText(null); - if (value instanceof Operation) { - Operation operation = (Operation) value; - OperationStatus status = operation.getStatus(); - if (status == OperationStatus.FINISH) { - label.setIcon(this.iconSuccess); - } else if (status == OperationStatus.ERROR) { - label.setIcon(this.iconError); - } - if (operation.getMessage() != null) { - label.setText(operation.getMessage()); - } else { - if (status == OperationStatus.PENDING) { - label.setText(Localization.get("status_pending")); - } else if (status == OperationStatus.FINISH) { - label.setText(Localization.get("status_finished")); - } else if (status == OperationStatus.ERROR) { - label.setText(Localization.get("status_error")); - } else if (status == OperationStatus.IN_PROGRESS) { - label.setText(Localization.get("status_in_progress")); - } - } - } + if (value instanceof Operation) { + Operation operation = (Operation) value; + OperationStatus status = operation.getStatus(); + if (status == OperationStatus.FINISH) { + label.setIcon(this.iconSuccess); + } else if (status == OperationStatus.ERROR) { + label.setIcon(this.iconError); + } + if (operation.getMessage() != null) { + label.setText(operation.getMessage()); + } else { + if (status == OperationStatus.PENDING) { + label.setText(Localization.get("status_pending")); + } else if (status == OperationStatus.FINISH) { + label.setText(Localization.get("status_finished")); + } else if (status == OperationStatus.ERROR) { + label.setText(Localization.get("status_error")); + } else if (status == OperationStatus.IN_PROGRESS) { + label.setText(Localization.get("status_in_progress")); + } + } + } - return label; - } + return label; + } } diff --git a/src/net/redwarp/tool/resizer/views/AboutDialog.java b/src/net/redwarp/tool/resizer/views/AboutDialog.java index be6f04e..64d939d 100644 --- a/src/net/redwarp/tool/resizer/views/AboutDialog.java +++ b/src/net/redwarp/tool/resizer/views/AboutDialog.java @@ -1,6 +1,4 @@ /* - * Copyright 2012 redwarp - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,56 +10,48 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * Copyright 2013 Redwarp */ package net.redwarp.tool.resizer.views; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Font; - -import javax.swing.ImageIcon; -import javax.swing.JDialog; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JTextArea; -import javax.swing.SwingConstants; -import javax.swing.UIManager; -import javax.swing.border.EmptyBorder; - import net.redwarp.tool.resizer.misc.Localization; import net.redwarp.tool.resizer.misc.Preferences; -public class AboutDialog extends JDialog { - private static final long serialVersionUID = 7783865044667012251L; - - public AboutDialog(JFrame parent) { - this.setResizable(false); - this.setSize(new Dimension(400, 250)); - this.getContentPane().setLayout(new BorderLayout(0, 0)); - - JLabel lblResizer = new JLabel(Localization.get("app_name") + " " - + Preferences.getVersion()); - lblResizer.setBorder(new EmptyBorder(10, 10, 10, 10)); - lblResizer.setVerticalTextPosition(SwingConstants.BOTTOM); - lblResizer.setIconTextGap(10); - lblResizer.setFont(lblResizer.getFont().deriveFont( - lblResizer.getFont().getStyle() | Font.BOLD, 16f)); - lblResizer.setIcon(new ImageIcon(AboutDialog.class - .getResource("/img/icon_64.png"))); - this.getContentPane().add(lblResizer, BorderLayout.NORTH); - - JTextArea txtrResizerIsA = new JTextArea(); - txtrResizerIsA.setEditable(false); - txtrResizerIsA.setWrapStyleWord(true); - txtrResizerIsA.setBorder(new EmptyBorder(0, 10, 10, 10)); - txtrResizerIsA.setFont(UIManager.getFont("Label.font")); - txtrResizerIsA.setLineWrap(true); - txtrResizerIsA.setText(Localization.get("about_text")); - txtrResizerIsA.setBackground(new Color(0, 0, 0, 0)); - this.getContentPane().add(txtrResizerIsA, BorderLayout.CENTER); +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; - this.setLocationRelativeTo(parent); - } +public class AboutDialog extends JDialog { + private static final long serialVersionUID = 7783865044667012251L; + + public AboutDialog(JFrame parent) { + this.setResizable(false); + this.setSize(new Dimension(400, 250)); + this.getContentPane().setLayout(new BorderLayout(0, 0)); + + JLabel lblResizer = new JLabel(Localization.get("app_name") + " " + + Preferences.getVersion()); + lblResizer.setBorder(new EmptyBorder(10, 10, 10, 10)); + lblResizer.setVerticalTextPosition(SwingConstants.BOTTOM); + lblResizer.setIconTextGap(10); + lblResizer.setFont(lblResizer.getFont().deriveFont( + lblResizer.getFont().getStyle() | Font.BOLD, 16f)); + lblResizer.setIcon(new ImageIcon(AboutDialog.class + .getResource("/img/icon_64.png"))); + this.getContentPane().add(lblResizer, BorderLayout.NORTH); + + JTextArea txtrResizerIsA = new JTextArea(); + txtrResizerIsA.setEditable(false); + txtrResizerIsA.setWrapStyleWord(true); + txtrResizerIsA.setBorder(new EmptyBorder(0, 10, 10, 10)); + txtrResizerIsA.setFont(UIManager.getFont("Label.font")); + txtrResizerIsA.setLineWrap(true); + txtrResizerIsA.setText(Localization.get("about_text")); + txtrResizerIsA.setBackground(new Color(0, 0, 0, 0)); + this.getContentPane().add(txtrResizerIsA, BorderLayout.CENTER); + + this.setLocationRelativeTo(parent); + } } diff --git a/src/net/redwarp/tool/resizer/views/MainWindow.java b/src/net/redwarp/tool/resizer/views/MainWindow.java index 67341e1..ff91b68 100644 --- a/src/net/redwarp/tool/resizer/views/MainWindow.java +++ b/src/net/redwarp/tool/resizer/views/MainWindow.java @@ -1,6 +1,4 @@ /* - * Copyright 2012 redwarp - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,36 +10,11 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * Copyright 2013 Redwarp */ -package net.redwarp.tool.resizer.views; - -import java.awt.BorderLayout; -import java.awt.CardLayout; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.Image; -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JMenu; -import javax.swing.JMenuBar; -import javax.swing.JMenuItem; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTextArea; -import javax.swing.ScrollPaneConstants; -import javax.swing.SwingConstants; -import javax.swing.border.EmptyBorder; +package net.redwarp.tool.resizer.views; import net.iharder.dnd.FileDrop; import net.redwarp.tool.resizer.misc.Localization; @@ -50,200 +23,251 @@ import net.redwarp.tool.resizer.worker.ImageScaler; import net.redwarp.tool.resizer.worker.ScreenDensity; +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Vector; + @SuppressWarnings("serial") public class MainWindow extends JFrame { - private JPanel inputPanel; - private JPanel outputPanel; - - private ImageIcon blueArrow, redArrow; - private ImageIcon blueArrowSmall, redArrowSmall; - private JButton xhdpiButton; - private JScrollPane scrollPane; - private JTextArea textArea; - private ResultTable resultTable; - private JLabel instructionLabel; - private JMenuBar menuBar; - private JMenu mnHelp; - private JMenu mnEdit; - private JMenuItem mntmClear; - private JMenuItem mntmAbout; - private final Action action = new SwingAction(); - - public MainWindow() { - this.setSize(new Dimension(450, 350)); - this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - this.setTitle(Localization.get("app_name")); - - List icons = new ArrayList(); - icons.add(Toolkit.getDefaultToolkit().getImage( - MainWindow.class.getResource("/img/icon_512.png"))); - icons.add(Toolkit.getDefaultToolkit().getImage( - MainWindow.class.getResource("/img/icon_256.png"))); - icons.add(Toolkit.getDefaultToolkit().getImage( - MainWindow.class.getResource("/img/icon_128.png"))); - icons.add(Toolkit.getDefaultToolkit().getImage( - MainWindow.class.getResource("/img/icon_64.png"))); - icons.add(Toolkit.getDefaultToolkit().getImage( - MainWindow.class.getResource("/img/icon_32.png"))); - icons.add(Toolkit.getDefaultToolkit().getImage( - MainWindow.class.getResource("/img/icon_16.png"))); - this.setIconImages(icons); - - this.blueArrow = new ImageIcon( - MainWindow.class.getResource("/img/blue_big.png")); - this.redArrow = new ImageIcon( - MainWindow.class.getResource("/img/red_big.png")); - this.blueArrowSmall = new ImageIcon( - MainWindow.class.getResource("/img/blue_small.png")); - this.redArrowSmall = new ImageIcon( - MainWindow.class.getResource("/img/red_small.png")); - this.getContentPane().setLayout(new CardLayout(0, 0)); - - this.inputPanel = new JPanel(); - this.inputPanel.setPreferredSize(new Dimension(10, 140)); - this.getContentPane().add(this.inputPanel, "input"); - - this.xhdpiButton = new JButton(Localization.get("xhdpi")); - this.xhdpiButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent arg0) { - } - }); - this.inputPanel.setLayout(new BorderLayout(0, 0)); - this.xhdpiButton.setBorderPainted(false); - this.xhdpiButton.setFocusPainted(false); - this.xhdpiButton.setVerticalTextPosition(SwingConstants.BOTTOM); - this.xhdpiButton.setHorizontalTextPosition(SwingConstants.CENTER); - this.xhdpiButton.setIcon(this.blueArrow); - this.xhdpiButton.setSelectedIcon(this.redArrow); - // this.xhdpiButton.setPressedIcon(this.redArrow); - this.xhdpiButton.setBorder(null); - this.xhdpiButton.setContentAreaFilled(false); - this.inputPanel.add(this.xhdpiButton); - - this.outputPanel = new JPanel(); - this.getContentPane().add(this.outputPanel, "output"); - this.outputPanel.setLayout(new BorderLayout(0, 0)); - - this.textArea = new JTextArea(); - this.textArea.setLineWrap(true); - this.textArea.setEditable(false); - - this.resultTable = new ResultTable(); - this.scrollPane = new JScrollPane(this.resultTable); - this.scrollPane - .setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - this.scrollPane - .setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); - this.outputPanel.add(this.scrollPane, BorderLayout.CENTER); - - FileDrop.Listener dropListener = new FileDrop.Listener() { - - @Override - public void filesDropped(Container source, File[] files) { - for (File input : files) { - String name = input.getName().toLowerCase(); - if (name.endsWith(".png") || name.endsWith(".jpg")) { - MainWindow.this.mntmClear.setEnabled(true); - CardLayout layout = (CardLayout) MainWindow.this - .getContentPane().getLayout(); - layout.show(MainWindow.this.getContentPane(), "output"); - int density = ScreenDensity.XHDPI; - Operation operation = new Operation(input); - MainWindow.this.resultTable.addOperation(operation); - - ImageScaler scaler = new ImageScaler(operation, - ScreenDensity.getDensity(density)) { - @Override - protected void process( - java.util.List chunks) { - for (Operation operation : chunks) { - MainWindow.this.resultTable - .notifyChange(operation); - } - }; - }; - scaler.post(); - } - } - } - - @Override - public void dragEnter(Container source) { - MainWindow.this.xhdpiButton.setSelected(true); - MainWindow.this.instructionLabel - .setIcon(MainWindow.this.redArrowSmall); - } - - @Override - public void dragExit(Container source) { - MainWindow.this.xhdpiButton.setSelected(false); - MainWindow.this.instructionLabel - .setIcon(MainWindow.this.blueArrowSmall); - } - }; - new FileDrop(this.getContentPane(), null, dropListener); - new FileDrop(this.outputPanel, null, dropListener); - - this.instructionLabel = new JLabel(Localization.get("xhdpi")); - this.instructionLabel.setIcon(this.blueArrowSmall); - this.instructionLabel.setBorder(new EmptyBorder(4, 4, 4, 4)); - this.outputPanel.add(this.instructionLabel, BorderLayout.SOUTH); - - new FileDrop(this.textArea, null, dropListener); - - this.setMenuBar(); - } - - private void setMenuBar() { - this.menuBar = new JMenuBar(); - this.setJMenuBar(this.menuBar); - - this.mnEdit = new JMenu(Localization.get("menu_edit")); - this.menuBar.add(this.mnEdit); - - this.mntmClear = new JMenuItem(Localization.get("menu_item_clear")); - this.mntmClear.setAction(this.action); - this.mntmClear.setEnabled(false); - this.mnEdit.add(this.mntmClear); - - this.mnHelp = new JMenu(Localization.get("menu_help")); - this.menuBar.add(this.mnHelp); - - this.mntmAbout = new JMenuItem(); - this.mntmAbout.setAction(new AboutAction()); - this.mnHelp.add(this.mntmAbout); - } - - private class AboutAction extends AbstractAction { - public AboutAction() { - this.putValue(NAME, Localization.get("menu_item_about")); - } - - @Override - public void actionPerformed(ActionEvent e) { - new AboutDialog(MainWindow.this).setVisible(true); - } - } - - private class SwingAction extends AbstractAction { - public SwingAction() { - this.putValue(NAME, Localization.get("menu_item_clear")); - this.putValue(SHORT_DESCRIPTION, - Localization.get("menu_item_clear_desc")); - } - - @Override - public void actionPerformed(ActionEvent e) { - MainWindow.this.resultTable.clear(); - if (MainWindow.this.resultTable.getModel().getRowCount() == 0) { - MainWindow.this.mntmClear.setEnabled(false); - - CardLayout layout = (CardLayout) MainWindow.this - .getContentPane().getLayout(); - layout.show(MainWindow.this.getContentPane(), "input"); - } - } - } + private JPanel inputPanel; + private JPanel outputPanel; + + private ImageIcon blueArrow, redArrow; + private ImageIcon blueArrowSmall, redArrowSmall; + private JButton xhdpiButton; + private JScrollPane scrollPane; + private JTextArea textArea; + private ResultTable resultTable; + private JLabel instructionLabel; + private JMenuBar menuBar; + private JMenu mnHelp; + private JMenu mnEdit; + private JMenuItem mntmClear; + private JMenuItem mntmAbout; + private final Action action = new SwingAction(); + + public MainWindow() { + this.setSize(new Dimension(450, 350)); + this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + this.setTitle(Localization.get("app_name")); + + List icons = new ArrayList(); + icons.add(Toolkit.getDefaultToolkit().getImage( + MainWindow.class.getResource("/img/icon_512.png"))); + icons.add(Toolkit.getDefaultToolkit().getImage( + MainWindow.class.getResource("/img/icon_256.png"))); + icons.add(Toolkit.getDefaultToolkit().getImage( + MainWindow.class.getResource("/img/icon_128.png"))); + icons.add(Toolkit.getDefaultToolkit().getImage( + MainWindow.class.getResource("/img/icon_64.png"))); + icons.add(Toolkit.getDefaultToolkit().getImage( + MainWindow.class.getResource("/img/icon_32.png"))); + icons.add(Toolkit.getDefaultToolkit().getImage( + MainWindow.class.getResource("/img/icon_16.png"))); + this.setIconImages(icons); + + this.blueArrow = new ImageIcon( + MainWindow.class.getResource("/img/blue_big.png")); + this.redArrow = new ImageIcon( + MainWindow.class.getResource("/img/red_big.png")); + this.blueArrowSmall = new ImageIcon( + MainWindow.class.getResource("/img/blue_small.png")); + this.redArrowSmall = new ImageIcon( + MainWindow.class.getResource("/img/red_small.png")); + this.getContentPane().setLayout(new CardLayout(0, 0)); + + this.inputPanel = new JPanel(); + this.inputPanel.setPreferredSize(new Dimension(10, 140)); + this.getContentPane().add(this.inputPanel, "input"); + + this.xhdpiButton = new JButton(Localization.get("xhdpi")); + this.xhdpiButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + } + }); + this.inputPanel.setLayout(new BorderLayout(0, 0)); + this.xhdpiButton.setBorderPainted(false); + this.xhdpiButton.setFocusPainted(false); + this.xhdpiButton.setVerticalTextPosition(SwingConstants.BOTTOM); + this.xhdpiButton.setHorizontalTextPosition(SwingConstants.CENTER); + this.xhdpiButton.setIcon(this.blueArrow); + this.xhdpiButton.setSelectedIcon(this.redArrow); + this.xhdpiButton.setBorder(null); + this.xhdpiButton.setContentAreaFilled(false); + this.inputPanel.add(this.xhdpiButton, BorderLayout.CENTER); + + JPanel optionPanel = new JPanel(); + optionPanel.setLayout(new BoxLayout(optionPanel, BoxLayout.PAGE_AXIS)); + optionPanel.add(Box.createVerticalGlue()); + + JLabel inputLabel = new JLabel(Localization.get("input_density")); + inputLabel.setAlignmentX(Component.LEFT_ALIGNMENT); + optionPanel.add(inputLabel); + JComboBox inputDensityChoice = new JComboBox(new Vector(ScreenDensity.getSupportedScreenDensity())); + inputDensityChoice.setSelectedItem(ScreenDensity.getDefaultInputDensity()); + inputDensityChoice.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + JComboBox box = (JComboBox) actionEvent.getSource(); + ScreenDensity selectedDensity = (ScreenDensity) box.getSelectedItem(); + ScreenDensity.setDefaultInputDensity(selectedDensity); + } + }); + inputDensityChoice.setAlignmentX(Component.LEFT_ALIGNMENT); + inputDensityChoice.setAlignmentY(Component.BOTTOM_ALIGNMENT); + inputDensityChoice.setPreferredSize(new Dimension(1, 10)); + + optionPanel.add(inputDensityChoice); + optionPanel.add(Box.createVerticalGlue()); + + JLabel outputLabel = new JLabel(Localization.get("output_density")); + optionPanel.add(outputLabel); + for (final ScreenDensity density : ScreenDensity.getSupportedScreenDensity()) { + final JCheckBox box = new JCheckBox(density.getName()); + box.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + density.setActive(box.isSelected()); + } + }); + box.setSelected(density.isActive()); + box.setAlignmentX(Component.LEFT_ALIGNMENT); + optionPanel.add(box); + } + optionPanel.add(Box.createVerticalGlue()); + optionPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder("Options"), BorderFactory.createEmptyBorder(10, 10, 10, 10))); + + this.inputPanel.add(optionPanel, BorderLayout.LINE_START); + + this.outputPanel = new JPanel(); + this.getContentPane().add(this.outputPanel, "output"); + this.outputPanel.setLayout(new BorderLayout(0, 0)); + + this.textArea = new JTextArea(); + this.textArea.setLineWrap(true); + this.textArea.setEditable(false); + + this.resultTable = new ResultTable(); + this.scrollPane = new JScrollPane(this.resultTable); + this.scrollPane + .setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + this.scrollPane + .setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); + this.outputPanel.add(this.scrollPane, BorderLayout.CENTER); + + FileDrop.Listener dropListener = new FileDrop.Listener() { + + @Override + public void filesDropped(Container source, File[] files) { + for (File input : files) { + String name = input.getName().toLowerCase(); + if (name.endsWith(".png") || name.endsWith(".jpg")) { + MainWindow.this.mntmClear.setEnabled(true); + CardLayout layout = (CardLayout) MainWindow.this + .getContentPane().getLayout(); + layout.show(MainWindow.this.getContentPane(), "output"); + Operation operation = new Operation(input); + MainWindow.this.resultTable.addOperation(operation); + + ImageScaler scaler = new ImageScaler(operation, + ScreenDensity.getDefaultInputDensity()) { + @Override + protected void process( + java.util.List chunks) { + for (Operation operation : chunks) { + MainWindow.this.resultTable + .notifyChange(operation); + } + } + }; + scaler.post(); + } + } + } + + @Override + public void dragEnter(Container source) { + MainWindow.this.xhdpiButton.setSelected(true); + MainWindow.this.instructionLabel + .setIcon(MainWindow.this.redArrowSmall); + } + + @Override + public void dragExit(Container source) { + MainWindow.this.xhdpiButton.setSelected(false); + MainWindow.this.instructionLabel + .setIcon(MainWindow.this.blueArrowSmall); + } + }; + new FileDrop(this.getContentPane(), null, dropListener); + new FileDrop(this.outputPanel, null, dropListener); + + this.instructionLabel = new JLabel(Localization.get("xhdpi")); + this.instructionLabel.setIcon(this.blueArrowSmall); + this.instructionLabel.setBorder(new EmptyBorder(4, 4, 4, 4)); + this.outputPanel.add(this.instructionLabel, BorderLayout.SOUTH); + + new FileDrop(this.textArea, null, dropListener); + + this.setMenuBar(); + } + + private void setMenuBar() { + this.menuBar = new JMenuBar(); + this.setJMenuBar(this.menuBar); + + this.mnEdit = new JMenu(Localization.get("menu_edit")); + this.menuBar.add(this.mnEdit); + + this.mntmClear = new JMenuItem(Localization.get("menu_item_clear")); + this.mntmClear.setAction(this.action); + this.mntmClear.setEnabled(false); + this.mnEdit.add(this.mntmClear); + + this.mnHelp = new JMenu(Localization.get("menu_help")); + this.menuBar.add(this.mnHelp); + + this.mntmAbout = new JMenuItem(); + this.mntmAbout.setAction(new AboutAction()); + this.mnHelp.add(this.mntmAbout); + } + + private class AboutAction extends AbstractAction { + public AboutAction() { + this.putValue(NAME, Localization.get("menu_item_about")); + } + + @Override + public void actionPerformed(ActionEvent e) { + new AboutDialog(MainWindow.this).setVisible(true); + } + } + + private class SwingAction extends AbstractAction { + public SwingAction() { + this.putValue(NAME, Localization.get("menu_item_clear")); + this.putValue(SHORT_DESCRIPTION, + Localization.get("menu_item_clear_desc")); + } + + @Override + public void actionPerformed(ActionEvent e) { + MainWindow.this.resultTable.clear(); + if (MainWindow.this.resultTable.getModel().getRowCount() == 0) { + MainWindow.this.mntmClear.setEnabled(false); + + CardLayout layout = (CardLayout) MainWindow.this + .getContentPane().getLayout(); + layout.show(MainWindow.this.getContentPane(), "input"); + } + } + } } diff --git a/src/net/redwarp/tool/resizer/worker/ImageScaler.java b/src/net/redwarp/tool/resizer/worker/ImageScaler.java index c6e16ea..3df68e0 100644 --- a/src/net/redwarp/tool/resizer/worker/ImageScaler.java +++ b/src/net/redwarp/tool/resizer/worker/ImageScaler.java @@ -1,6 +1,4 @@ /* - * Copyright 2012 redwarp - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,12 +10,18 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * Copyright 2013 Redwarp */ package net.redwarp.tool.resizer.worker; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.RenderingHints; +import net.redwarp.tool.resizer.misc.Localization; +import net.redwarp.tool.resizer.table.Operation; +import net.redwarp.tool.resizer.table.OperationStatus; + +import javax.imageio.ImageIO; +import javax.swing.*; +import java.awt.*; import java.awt.RenderingHints.Key; import java.awt.image.BufferedImage; import java.io.File; @@ -28,326 +32,322 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import javax.imageio.ImageIO; -import javax.swing.SwingWorker; - -import net.redwarp.tool.resizer.misc.Localization; -import net.redwarp.tool.resizer.table.Operation; -import net.redwarp.tool.resizer.table.OperationStatus; - public class ImageScaler extends SwingWorker { - private File inputFile; - private Operation operation; - private ScreenDensity inputDensity; - private static ExecutorService executor = Executors - .newFixedThreadPool(Runtime.getRuntime().availableProcessors()); - private static Object fileLock = new Object(); - private static Object folderLock = new Object(); - - public ImageScaler(final Operation operation, - final ScreenDensity inputDensity) { - this.operation = operation; - this.inputFile = operation.getFile(); - this.inputDensity = inputDensity; - } - - @Override - protected Void doInBackground() throws Exception { - try { - BufferedImage inputImage; - synchronized (fileLock) { - inputImage = ImageIO.read(this.inputFile); - } - if (inputImage == null) { - this.operation.setStatus(OperationStatus.ERROR, - Localization.get("error_wrong_png")); - this.publish(this.operation); - return null; - } - - this.operation.setStatus(OperationStatus.IN_PROGRESS); - this.publish(this.operation); - - List densityList = ScreenDensity - .getSupportedScreenDensity(); - - File parent = this.inputFile.getParentFile(); - for (ScreenDensity density : densityList) { - File outputFolder; - - synchronized (folderLock) { - outputFolder = new File(parent, "drawable-" - + density.getName()); - if (!outputFolder.exists()) { - outputFolder.mkdir(); - } - } - - String name; - int extensionPos = this.inputFile.getName().lastIndexOf('.'); - if (extensionPos != -1) { - name = this.inputFile.getName().substring(0, extensionPos) - + ".png"; - } else { - name = this.inputFile.getName(); - } - - File outputFile = new File(outputFolder, name); - if (outputFile.exists()) { - outputFile.delete(); - } - - // if (density.equals(this.inputDensity)) { - // FileTools.copyfile(this.inputFile, outputFile); - // } else { - - BufferedImage outputImage; - if (this.inputFile.getName().endsWith(".9.png")) { - BufferedImage trimedImage = this.trim9PBorder(inputImage); - - float ratio = density.getDensity() - / this.inputDensity.getDensity(); - trimedImage = this.rescaleImage(trimedImage, - (int) (ratio * trimedImage.getWidth()), - (int) (ratio * trimedImage.getHeight())); - - BufferedImage borderImage; - - int w = trimedImage.getWidth(); - int h = trimedImage.getHeight(); - - try { - borderImage = this.generateBordersImage(inputImage, w, - h); - } catch (Wrong9PatchException e) { - this.operation.setStatus(OperationStatus.ERROR, - Localization.get("error_wrong_9p")); - this.publish(this.operation); - return null; - } - - int[] rgbArray = new int[w * h]; - trimedImage.getRGB(0, 0, w, h, rgbArray, 0, w); - borderImage.setRGB(1, 1, w, h, rgbArray, 0, w); - rgbArray = null; - - outputImage = borderImage; - } else { - - float ratio = density.getDensity() - / this.inputDensity.getDensity(); - outputImage = this.rescaleImage(inputImage, - (int) (ratio * inputImage.getWidth()), - (int) (ratio * inputImage.getHeight())); - } - - try { - - synchronized (fileLock) { - ImageIO.write(outputImage, "png", outputFile); - } - - } catch (IOException e) { - this.operation.setStatus(OperationStatus.ERROR); - this.publish(this.operation); - return null; - } - } - // } - this.operation.setStatus(OperationStatus.FINISH); - this.publish(this.operation); - } catch (IOException e) { - this.operation.setStatus(OperationStatus.ERROR); - this.publish(this.operation); - } - - return null; - } - - public void post() { - executor.submit(this); - } - - private BufferedImage rescaleImage(BufferedImage image, int targetWidth, - int targetHeight) { - if (targetWidth == 0) { - targetWidth = 1; - } - if (targetHeight == 0) { - targetHeight = 1; - } - if (targetWidth * 2 < image.getWidth() - 1) { - BufferedImage tempImage = this.rescaleImage(image, - image.getWidth() / 2, image.getHeight() / 2); - return this.rescaleImage(tempImage, targetWidth, targetHeight); - } else { - BufferedImage outputImage = new BufferedImage(targetWidth, - targetHeight, BufferedImage.TYPE_INT_ARGB); - Graphics2D graphics = outputImage.createGraphics(); - Map hints = new HashMap(); - hints.put(RenderingHints.KEY_DITHERING, - RenderingHints.VALUE_DITHER_ENABLE); - hints.put(RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_BILINEAR); - hints.put(RenderingHints.KEY_RENDERING, - RenderingHints.VALUE_RENDER_QUALITY); - hints.put(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - hints.put(RenderingHints.KEY_ALPHA_INTERPOLATION, - RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); - graphics.setRenderingHints(hints); - - graphics.drawImage(image, 0, 0, outputImage.getWidth(), - outputImage.getHeight(), null); - graphics.dispose(); - - return outputImage; - } - } - - private BufferedImage trim9PBorder(BufferedImage inputImage) { - BufferedImage trimedImage = new BufferedImage( - inputImage.getWidth() - 2, inputImage.getHeight() - 2, - BufferedImage.TYPE_INT_ARGB); - Graphics2D g = trimedImage.createGraphics(); - g.drawImage(inputImage, 0, 0, trimedImage.getWidth(), - trimedImage.getHeight(), 1, 1, inputImage.getWidth() - 1, - inputImage.getHeight() - 1, null); - g.dispose(); - return trimedImage; - } - - private void enforceBorderColors(BufferedImage inputImage) { - Graphics2D g = inputImage.createGraphics(); - g.setBackground(new Color(0, 0, 0, 0)); - g.clearRect(1, 1, inputImage.getWidth() - 2, inputImage.getHeight() - 2); - g.dispose(); - int w = inputImage.getWidth(); - int h = inputImage.getHeight(); - int[] rgb = new int[w * h]; - - inputImage.getRGB(0, 0, w, h, rgb, 0, w); - - for (int i = 0; i < rgb.length; i++) { - if ((0xff000000 & rgb[i]) != 0) { - rgb[i] = 0xff000000; - } - } - inputImage.setRGB(0, 0, w, h, rgb, 0, w); - inputImage.setRGB(0, 0, 0x0); - inputImage.setRGB(0, h - 1, 0x0); - inputImage.setRGB(w - 1, h - 1, 0x0); - inputImage.setRGB(w - 1, 0, 0x0); - } - - private BufferedImage generateBordersImage(BufferedImage source, - int trimedWidth, int trimedHeight) throws Wrong9PatchException { - BufferedImage finalBorder = new BufferedImage(trimedWidth + 2, - trimedHeight + 2, BufferedImage.TYPE_INT_ARGB); - int cutW = source.getWidth() - 2; - int cutH = source.getHeight() - 2; - { - // left border - BufferedImage leftBorder = new BufferedImage(1, cutH, - BufferedImage.TYPE_INT_ARGB); - leftBorder.setRGB(0, 0, 1, cutH, - source.getRGB(0, 1, 1, cutH, null, 0, 1), 0, 1); - this.verifyBorderImage(leftBorder); - leftBorder = this.resizeBorder(leftBorder, 1, trimedHeight); - finalBorder.setRGB(0, 1, 1, trimedHeight, - leftBorder.getRGB(0, 0, 1, trimedHeight, null, 0, 1), 0, 1); - } - { - // right border - BufferedImage rightBorder = new BufferedImage(1, cutH, - BufferedImage.TYPE_INT_ARGB); - rightBorder.setRGB(0, 0, 1, cutH, - source.getRGB(cutW + 1, 1, 1, cutH, null, 0, 1), 0, 1); - this.verifyBorderImage(rightBorder); - rightBorder = this.resizeBorder(rightBorder, 1, trimedHeight); - finalBorder - .setRGB(trimedWidth + 1, 1, 1, trimedHeight, rightBorder - .getRGB(0, 0, 1, trimedHeight, null, 0, 1), 0, 1); - } - { - // top border - BufferedImage topBorder = new BufferedImage(cutW, 1, - BufferedImage.TYPE_INT_ARGB); - topBorder.setRGB(0, 0, cutW, 1, - source.getRGB(1, 0, cutW, 1, null, 0, cutW), 0, cutW); - this.verifyBorderImage(topBorder); - topBorder = this.resizeBorder(topBorder, trimedWidth, 1); - finalBorder.setRGB(1, 0, trimedWidth, 1, topBorder.getRGB(0, 0, - trimedWidth, 1, null, 0, trimedWidth), 0, trimedWidth); - } - { - // bottom border - BufferedImage bottomBorder = new BufferedImage(cutW, 1, - BufferedImage.TYPE_INT_ARGB); - bottomBorder - .setRGB(0, 0, cutW, 1, - source.getRGB(1, cutH + 1, cutW, 1, null, 0, cutW), - 0, cutW); - this.verifyBorderImage(bottomBorder); - bottomBorder = this.resizeBorder(bottomBorder, trimedWidth, 1); - finalBorder.setRGB(1, trimedHeight + 1, trimedWidth, 1, - bottomBorder.getRGB(0, 0, trimedWidth, 1, null, 0, - trimedWidth), 0, trimedWidth); - } - - return finalBorder; - } - - private BufferedImage resizeBorder(final BufferedImage border, - int targetWidth, int targetHeight) { - if (targetWidth > border.getWidth() - || targetHeight > border.getHeight()) { - BufferedImage endImage = this.rescaleImage(border, targetWidth, - targetHeight); - this.enforceBorderColors(endImage); - return endImage; - } - - int w = border.getWidth(); - int h = border.getHeight(); - int[] data = border.getRGB(0, 0, w, h, null, 0, w); - int[] newData = new int[targetWidth * targetHeight]; - - float widthRatio = (float) Math.max(targetWidth - 1, 1) - / (float) Math.max(w - 1, 1); - float heightRatio = (float) Math.max(targetHeight - 1, 1) - / (float) Math.max(h - 1, 1); - - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - if ((0xff000000 & data[y * w + x]) != 0) { - int newX = Math.min(Math.round(x * widthRatio), - targetWidth - 1); - int newY = Math.min(Math.round(y * heightRatio), - targetHeight - 1); - - newData[newY * targetWidth + newX] = data[y * w + x]; - } - } - } - - BufferedImage img = new BufferedImage(targetWidth, targetHeight, - BufferedImage.TYPE_INT_ARGB); - img.setRGB(0, 0, targetWidth, targetHeight, newData, 0, targetWidth); - - return img; - } - - private void verifyBorderImage(BufferedImage border) - throws Wrong9PatchException { - int[] rgb = border.getRGB(0, 0, border.getWidth(), border.getHeight(), - null, 0, border.getWidth()); - for (int i = 0; i < rgb.length; i++) { - if ((0xff000000 & rgb[i]) != 0) { - if (rgb[i] != 0xff000000 && rgb[i] != 0xffff0000) { - throw new Wrong9PatchException(); - } - } - } - } + private File inputFile; + private Operation operation; + private ScreenDensity inputDensity; + private static ExecutorService executor = Executors + .newFixedThreadPool(Runtime.getRuntime().availableProcessors()); + private static Object fileLock = new Object(); + private static Object folderLock = new Object(); + + public ImageScaler(final Operation operation, + final ScreenDensity inputDensity) { + this.operation = operation; + this.inputFile = operation.getFile(); + this.inputDensity = inputDensity; + } + + @Override + protected Void doInBackground() throws Exception { + try { + BufferedImage inputImage; + synchronized (fileLock) { + inputImage = ImageIO.read(this.inputFile); + } + if (inputImage == null) { + this.operation.setStatus(OperationStatus.ERROR, + Localization.get("error_wrong_png")); + this.publish(this.operation); + return null; + } + + this.operation.setStatus(OperationStatus.IN_PROGRESS); + this.publish(this.operation); + + List densityList = ScreenDensity + .getSupportedScreenDensity(); + + File parent = this.inputFile.getParentFile(); + for (ScreenDensity density : densityList) { + if (density.isActive() == false) { + continue; + } + File outputFolder; + + synchronized (folderLock) { + outputFolder = new File(parent, "drawable-" + + density.getName()); + if (!outputFolder.exists()) { + outputFolder.mkdir(); + } + } + + String name; + int extensionPos = this.inputFile.getName().lastIndexOf('.'); + if (extensionPos != -1) { + name = this.inputFile.getName().substring(0, extensionPos) + + ".png"; + } else { + name = this.inputFile.getName(); + } + + File outputFile = new File(outputFolder, name); + if (outputFile.exists()) { + outputFile.delete(); + } + + // if (density.equals(this.inputDensity)) { + // FileTools.copyfile(this.inputFile, outputFile); + // } else { + + BufferedImage outputImage; + if (this.inputFile.getName().endsWith(".9.png")) { + BufferedImage trimedImage = this.trim9PBorder(inputImage); + + float ratio = density.getScale() + / this.inputDensity.getScale(); + trimedImage = this.rescaleImage(trimedImage, + (int) (ratio * trimedImage.getWidth()), + (int) (ratio * trimedImage.getHeight())); + + BufferedImage borderImage; + + int w = trimedImage.getWidth(); + int h = trimedImage.getHeight(); + + try { + borderImage = this.generateBordersImage(inputImage, w, + h); + } catch (Wrong9PatchException e) { + this.operation.setStatus(OperationStatus.ERROR, + Localization.get("error_wrong_9p")); + this.publish(this.operation); + return null; + } + + int[] rgbArray = new int[w * h]; + trimedImage.getRGB(0, 0, w, h, rgbArray, 0, w); + borderImage.setRGB(1, 1, w, h, rgbArray, 0, w); + rgbArray = null; + + outputImage = borderImage; + } else { + + float ratio = density.getScale() + / this.inputDensity.getScale(); + outputImage = this.rescaleImage(inputImage, + (int) (ratio * inputImage.getWidth()), + (int) (ratio * inputImage.getHeight())); + } + + try { + + synchronized (fileLock) { + ImageIO.write(outputImage, "png", outputFile); + } + + } catch (IOException e) { + this.operation.setStatus(OperationStatus.ERROR); + this.publish(this.operation); + return null; + } + } + // } + this.operation.setStatus(OperationStatus.FINISH); + this.publish(this.operation); + } catch (IOException e) { + this.operation.setStatus(OperationStatus.ERROR); + this.publish(this.operation); + } + + return null; + } + + public void post() { + executor.submit(this); + } + + private BufferedImage rescaleImage(BufferedImage image, int targetWidth, + int targetHeight) { + if (targetWidth == 0) { + targetWidth = 1; + } + if (targetHeight == 0) { + targetHeight = 1; + } + if (targetWidth * 2 < image.getWidth() - 1) { + BufferedImage tempImage = this.rescaleImage(image, + image.getWidth() / 2, image.getHeight() / 2); + return this.rescaleImage(tempImage, targetWidth, targetHeight); + } else { + BufferedImage outputImage = new BufferedImage(targetWidth, + targetHeight, BufferedImage.TYPE_INT_ARGB); + Graphics2D graphics = outputImage.createGraphics(); + Map hints = new HashMap(); + hints.put(RenderingHints.KEY_DITHERING, + RenderingHints.VALUE_DITHER_ENABLE); + hints.put(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + hints.put(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_QUALITY); + hints.put(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + hints.put(RenderingHints.KEY_ALPHA_INTERPOLATION, + RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); + graphics.setRenderingHints(hints); + + graphics.drawImage(image, 0, 0, outputImage.getWidth(), + outputImage.getHeight(), null); + graphics.dispose(); + + return outputImage; + } + } + + private BufferedImage trim9PBorder(BufferedImage inputImage) { + BufferedImage trimedImage = new BufferedImage( + inputImage.getWidth() - 2, inputImage.getHeight() - 2, + BufferedImage.TYPE_INT_ARGB); + Graphics2D g = trimedImage.createGraphics(); + g.drawImage(inputImage, 0, 0, trimedImage.getWidth(), + trimedImage.getHeight(), 1, 1, inputImage.getWidth() - 1, + inputImage.getHeight() - 1, null); + g.dispose(); + return trimedImage; + } + + private void enforceBorderColors(BufferedImage inputImage) { + Graphics2D g = inputImage.createGraphics(); + g.setBackground(new Color(0, 0, 0, 0)); + g.clearRect(1, 1, inputImage.getWidth() - 2, inputImage.getHeight() - 2); + g.dispose(); + int w = inputImage.getWidth(); + int h = inputImage.getHeight(); + int[] rgb = new int[w * h]; + + inputImage.getRGB(0, 0, w, h, rgb, 0, w); + + for (int i = 0; i < rgb.length; i++) { + if ((0xff000000 & rgb[i]) != 0) { + rgb[i] = 0xff000000; + } + } + inputImage.setRGB(0, 0, w, h, rgb, 0, w); + inputImage.setRGB(0, 0, 0x0); + inputImage.setRGB(0, h - 1, 0x0); + inputImage.setRGB(w - 1, h - 1, 0x0); + inputImage.setRGB(w - 1, 0, 0x0); + } + + private BufferedImage generateBordersImage(BufferedImage source, + int trimedWidth, int trimedHeight) throws Wrong9PatchException { + BufferedImage finalBorder = new BufferedImage(trimedWidth + 2, + trimedHeight + 2, BufferedImage.TYPE_INT_ARGB); + int cutW = source.getWidth() - 2; + int cutH = source.getHeight() - 2; + { + // left border + BufferedImage leftBorder = new BufferedImage(1, cutH, + BufferedImage.TYPE_INT_ARGB); + leftBorder.setRGB(0, 0, 1, cutH, + source.getRGB(0, 1, 1, cutH, null, 0, 1), 0, 1); + this.verifyBorderImage(leftBorder); + leftBorder = this.resizeBorder(leftBorder, 1, trimedHeight); + finalBorder.setRGB(0, 1, 1, trimedHeight, + leftBorder.getRGB(0, 0, 1, trimedHeight, null, 0, 1), 0, 1); + } + { + // right border + BufferedImage rightBorder = new BufferedImage(1, cutH, + BufferedImage.TYPE_INT_ARGB); + rightBorder.setRGB(0, 0, 1, cutH, + source.getRGB(cutW + 1, 1, 1, cutH, null, 0, 1), 0, 1); + this.verifyBorderImage(rightBorder); + rightBorder = this.resizeBorder(rightBorder, 1, trimedHeight); + finalBorder + .setRGB(trimedWidth + 1, 1, 1, trimedHeight, rightBorder + .getRGB(0, 0, 1, trimedHeight, null, 0, 1), 0, 1); + } + { + // top border + BufferedImage topBorder = new BufferedImage(cutW, 1, + BufferedImage.TYPE_INT_ARGB); + topBorder.setRGB(0, 0, cutW, 1, + source.getRGB(1, 0, cutW, 1, null, 0, cutW), 0, cutW); + this.verifyBorderImage(topBorder); + topBorder = this.resizeBorder(topBorder, trimedWidth, 1); + finalBorder.setRGB(1, 0, trimedWidth, 1, topBorder.getRGB(0, 0, + trimedWidth, 1, null, 0, trimedWidth), 0, trimedWidth); + } + { + // bottom border + BufferedImage bottomBorder = new BufferedImage(cutW, 1, + BufferedImage.TYPE_INT_ARGB); + bottomBorder + .setRGB(0, 0, cutW, 1, + source.getRGB(1, cutH + 1, cutW, 1, null, 0, cutW), + 0, cutW); + this.verifyBorderImage(bottomBorder); + bottomBorder = this.resizeBorder(bottomBorder, trimedWidth, 1); + finalBorder.setRGB(1, trimedHeight + 1, trimedWidth, 1, + bottomBorder.getRGB(0, 0, trimedWidth, 1, null, 0, + trimedWidth), 0, trimedWidth); + } + + return finalBorder; + } + + private BufferedImage resizeBorder(final BufferedImage border, + int targetWidth, int targetHeight) { + if (targetWidth > border.getWidth() + || targetHeight > border.getHeight()) { + BufferedImage endImage = this.rescaleImage(border, targetWidth, + targetHeight); + this.enforceBorderColors(endImage); + return endImage; + } + + int w = border.getWidth(); + int h = border.getHeight(); + int[] data = border.getRGB(0, 0, w, h, null, 0, w); + int[] newData = new int[targetWidth * targetHeight]; + + float widthRatio = (float) Math.max(targetWidth - 1, 1) + / (float) Math.max(w - 1, 1); + float heightRatio = (float) Math.max(targetHeight - 1, 1) + / (float) Math.max(h - 1, 1); + + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + if ((0xff000000 & data[y * w + x]) != 0) { + int newX = Math.min(Math.round(x * widthRatio), + targetWidth - 1); + int newY = Math.min(Math.round(y * heightRatio), + targetHeight - 1); + + newData[newY * targetWidth + newX] = data[y * w + x]; + } + } + } + + BufferedImage img = new BufferedImage(targetWidth, targetHeight, + BufferedImage.TYPE_INT_ARGB); + img.setRGB(0, 0, targetWidth, targetHeight, newData, 0, targetWidth); + + return img; + } + + private void verifyBorderImage(BufferedImage border) + throws Wrong9PatchException { + int[] rgb = border.getRGB(0, 0, border.getWidth(), border.getHeight(), + null, 0, border.getWidth()); + for (int i = 0; i < rgb.length; i++) { + if ((0xff000000 & rgb[i]) != 0) { + if (rgb[i] != 0xff000000 && rgb[i] != 0xffff0000) { + throw new Wrong9PatchException(); + } + } + } + } } diff --git a/src/net/redwarp/tool/resizer/worker/ScreenDensity.java b/src/net/redwarp/tool/resizer/worker/ScreenDensity.java index eadb5a7..94ba418 100644 --- a/src/net/redwarp/tool/resizer/worker/ScreenDensity.java +++ b/src/net/redwarp/tool/resizer/worker/ScreenDensity.java @@ -1,6 +1,4 @@ /* - * Copyright 2012 redwarp - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,74 +10,112 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * Copyright 2013 Redwarp */ package net.redwarp.tool.resizer.worker; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.reflect.TypeToken; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; public class ScreenDensity { - private float density; - private String name; - - private static List list = null; - - public static final int LDPI = 0; - public static final int MDPI = 1; - public static final int HDPI = 2; - public static final int XHDPI = 3; - - private ScreenDensity(String name, float density) { - this.density = density; - this.name = name; - } - - @Override - public String toString() { - return this.name + String.format(" (%.2f)", this.density); - } - - public String getName() { - return this.name; - } - - public float getDensity() { - return this.density; - } - - public static ScreenDensity getDensity(int density) - throws UnsupportedDensityException { - if (density == LDPI) { - return new ScreenDensity("ldpi", 0.75f); - } - if (density == MDPI) { - return new ScreenDensity("mdpi", 1f); - } - if (density == HDPI) { - return new ScreenDensity("hdpi", 1.5f); - } - if (density == XHDPI) { - return new ScreenDensity("xhdpi", 2f); - } - throw new UnsupportedDensityException(); - } - - public static List getSupportedScreenDensity() { - if (list == null) { - list = new ArrayList(); - list.add(getDensity(LDPI)); - list.add(getDensity(MDPI)); - list.add(getDensity(HDPI)); - list.add(getDensity(XHDPI)); - } - return list; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof ScreenDensity) { - return this.name.equals(((ScreenDensity) obj).getName()); - } - return false; - } + private float scale; + private String name; + + + private boolean active; + + private static List list = null; + private static ScreenDensity defaultInputDensity = null; + + static { + try { + Gson gson = new Gson(); + JsonParser parser = new JsonParser(); + InputStream preferenceStream; + try { + preferenceStream = new FileInputStream(new File("./densities.json")); + } catch (Exception e) { + preferenceStream = ScreenDensity.class.getClassLoader().getResourceAsStream("misc/densities.json"); + } + JsonObject densitiesObject = parser.parse(new InputStreamReader(preferenceStream)).getAsJsonObject(); + JsonArray densitiesArray = densitiesObject.get("densities").getAsJsonArray(); + + Type listType = new TypeToken>() { + }.getType(); + list = gson.fromJson(densitiesArray, listType); + String defaultDensityName = densitiesObject.get("source").getAsString(); + for (ScreenDensity density : list) { + if (density.getName().equals(defaultDensityName)) { + defaultInputDensity = density; + break; + } + } + if (defaultInputDensity == null) { + defaultInputDensity = list.get(0); + } + } catch (Exception e) { + list = new ArrayList(); + list.add(new ScreenDensity("xhdpi", 2.0f, true)); + defaultInputDensity = list.get(0); + } + } + + private ScreenDensity(String name, float density, boolean active) { + this.scale = density; + this.name = name; + this.active = active; + } + + @Override + public String toString() { + return this.name; + } + + public String getName() { + return this.name; + } + + public float getScale() { + return this.scale; + } + + public static List getSupportedScreenDensity() { + return list; + } + + public static ScreenDensity getDefaultInputDensity() { + return defaultInputDensity; + } + + public static void setDefaultInputDensity(ScreenDensity density) { + defaultInputDensity = density; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ScreenDensity) { + return this.name.equals(((ScreenDensity) obj).getName()); + } + return false; + } + + public boolean isActive() { + return active; + } + + public void setActive(boolean active) { + this.active = active; + } } diff --git a/src/net/redwarp/tool/resizer/worker/UnsupportedDensityException.java b/src/net/redwarp/tool/resizer/worker/UnsupportedDensityException.java index 332b614..d00643f 100644 --- a/src/net/redwarp/tool/resizer/worker/UnsupportedDensityException.java +++ b/src/net/redwarp/tool/resizer/worker/UnsupportedDensityException.java @@ -1,6 +1,4 @@ /* - * Copyright 2012 redwarp - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,10 +10,12 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * Copyright 2013 Redwarp */ package net.redwarp.tool.resizer.worker; public class UnsupportedDensityException extends RuntimeException { - private static final long serialVersionUID = -8219133514177459994L; + private static final long serialVersionUID = -8219133514177459994L; } diff --git a/src/net/redwarp/tool/resizer/worker/Wrong9PatchException.java b/src/net/redwarp/tool/resizer/worker/Wrong9PatchException.java index 03c6696..9ec7609 100644 --- a/src/net/redwarp/tool/resizer/worker/Wrong9PatchException.java +++ b/src/net/redwarp/tool/resizer/worker/Wrong9PatchException.java @@ -1,6 +1,4 @@ /* - * Copyright 2012 redwarp - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,6 +10,8 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * Copyright 2013 Redwarp */ package net.redwarp.tool.resizer.worker;