/******************************************************************************* * Copyright (c) 2009, Adobe Systems Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * · Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * · Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * · Neither the name of Adobe Systems Incorporated nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ package com.adobe.dp.epub.conv; import java.awt.AlphaComposite; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Point; import java.awt.Rectangle; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragSource; import java.awt.dnd.DragSourceDragEvent; import java.awt.dnd.DragSourceDropEvent; import java.awt.dnd.DragSourceEvent; import java.awt.dnd.DragSourceListener; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; import java.awt.image.FilteredImageSource; import java.awt.image.ImageFilter; import java.awt.image.ImageProducer; import java.awt.image.MemoryImageSource; import java.awt.image.RGBImageFilter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.net.URL; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Properties; import java.util.Random; import java.util.StringTokenizer; import java.util.Vector; import javax.imageio.ImageIO; import javax.swing.AbstractAction; import javax.swing.Box; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; public class GUIDriver extends JFrame { public static final long serialVersionUID = 0; BufferedImage epubIcon; BufferedImage cssIcon; BufferedImage otfIcon; BufferedImage ttfIcon; BufferedImage errIcon; DragSource dragSource = DragSource.getDefaultDragSource(); boolean dragActive; Point dragStart = new Point(0, 0); Vector conversionQueue = new Vector(); FileIcon currentlyConverting; FileIcon[] localDrag; JTabbedPane tabbedPane; FilePanel docPane; FilePanel resourcePane; SettingsPanel settingsPane; JEditorPane helpPane; File docFolder; File resourceFolder; File settingsFile; File workFolder; Properties settings = new Properties(); static DataFlavor urilist; static { try { urilist = new DataFlavor("text/uri-list;class=java.lang.String"); } catch (Exception e) { e.printStackTrace(); } } static class HighlightedFilter extends RGBImageFilter { public HighlightedFilter() { canFilterIndexColorModel = true; } public int filterRGB(int x, int y, int rgb) { return (((rgb & 0xFEFEFE) >> 1) + 0x80) | (rgb & 0xFF000000); } } class AlphaFilter extends RGBImageFilter { private int alpha; public AlphaFilter() { canFilterIndexColorModel = true; } public void setLevel(float f) { alpha = (int) Math.round(f * 255); } public int filterRGB(int x, int y, int rgb) { int alpha = ((this.alpha * (rgb >>> 24)) / 255) << 24; return (rgb & 0x00FFFFFF) | alpha; } } class Updater extends AbstractAction { public static final long serialVersionUID = 0; Updater() { new Timer(50, this).start(); } public void actionPerformed(ActionEvent evt) { if (currentlyConverting != null) currentlyConverting.repaint(); } } class FileCheck extends AbstractAction { public static final long serialVersionUID = 0; Timer timer; FileCheck() { timer = new Timer(500, this); timer.start(); } public void actionPerformed(ActionEvent evt) { timer.setDelay(3000); docPane.checkFiles(); resourcePane.checkFiles(); } } class SettingsPanel extends JPanel implements ChangeListener { public static final long serialVersionUID = 0; JCheckBox translit = new JCheckBox("Transliterate cyrillic metadata"); JCheckBox embedFonts = new JCheckBox("Embed fonts"); JCheckBox adobeMangling = new JCheckBox("Use Adobe font mangling"); JCheckBox pageBreaks = new JCheckBox("Add page map using page breaks (DOCX only)"); SettingsPanel() { Box box = Box.createVerticalBox(); add(box); box.add(translit); box.add(embedFonts); box.add(adobeMangling); // does not work all that well //box.add(pageBreaks); translit.setSelected(getBooleanProperty("translit", true)); embedFonts.setSelected(getBooleanProperty("embedFonts", true)); adobeMangling.setSelected(getBooleanProperty("adobeMangling", true)); pageBreaks.setSelected(getBooleanProperty("pageBreaks", false)); translit.addChangeListener(this); embedFonts.addChangeListener(this); adobeMangling.addChangeListener(this); pageBreaks.addChangeListener(this); } boolean getBooleanProperty(String name, boolean def) { String s = settings.getProperty(name); if (s == null) return def; return s.toLowerCase().startsWith("t"); } void setBooleanProperty(String name, boolean val) { settings.setProperty(name, val ? "true" : "false"); } public void stateChanged(ChangeEvent arg) { setBooleanProperty("translit", translit.isSelected()); setBooleanProperty("embedFonts", embedFonts.isSelected()); setBooleanProperty("adobeMangling", adobeMangling.isSelected()); setBooleanProperty("pageBreaks", pageBreaks.isSelected()); try { FileOutputStream out = new FileOutputStream(settingsFile); settings.store(out, "EPUBGen"); } catch (Exception e) { e.printStackTrace(); } } } class FilePanel extends JPanel implements DropTargetListener, DragSourceListener { public static final long serialVersionUID = 0; File folder; HashSet blackList = new HashSet(); public FilePanel(File folder) { this.folder = folder; setBackground(new Color(0xFFFFFFFF)); setLayout(null); new DropTarget(this, this); addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent evt) { resetSelection(); } }); } void resetSelection() { Component[] components = getComponents(); for (int i = 0; i < components.length; i++) { if (components[i] instanceof FileIcon) { FileIcon fi = (FileIcon) components[i]; fi.clearHighlight(); } } } public void paint(Graphics g) { super.paint(g); if (getComponentCount() == 0) { String label; if (this == docPane) label = "Drop documents here"; else label = "Drop resources here"; Dimension d = getSize(); int size = 20; Font f = new Font("Serif", Font.PLAIN, size); g.setFont(f); FontMetrics fm = g.getFontMetrics(); char[] arr = label.toCharArray(); int width = fm.charsWidth(arr, 0, arr.length); int fs = (2 * size * d.width) / (3 * width); f = new Font("Serif", Font.PLAIN, fs); g.setFont(f); int x = (d.width - (fs * width) / size) / 2; int y = (d.height + (2 * fs) / 3) / 2; g.setColor(new Color(0xCCCCCC)); g.drawString(label, x, y); } } public void add(FileIcon component) { if (getComponentCount() == 0) repaint(); super.add(component); } private boolean isEPub(File f) { return f.getName().toLowerCase().endsWith(".epub"); } private boolean isErrorLog(File f) { String nm = f.getName(); return nm.startsWith("error") && nm.endsWith(".txt"); } private boolean canUse(File f) { String nm = f.getName().toLowerCase(); return nm.endsWith(".css") || nm.endsWith(".otf") || nm.endsWith(".ttf") || nm.endsWith(".ttc"); } private BufferedImage getResIcon(String nm) { if (nm.endsWith(".ttf") || nm.endsWith(".ttc")) return ttfIcon; if (nm.endsWith(".otf")) return otfIcon; if (nm.endsWith(".css")) return cssIcon; return null; } public void dragEnter(DropTargetDragEvent dtde) { if (!dragActive) { dragActive = true; if (localDrag != null) { for (int i = 0; i < localDrag.length; i++) { localDrag[i].repaint(); } } } dragOver(dtde); } public void dragExit(DropTargetEvent dte) { if (dragActive) { dragActive = false; if (localDrag != null) { for (int i = 0; i < localDrag.length; i++) { localDrag[i].repaint(); } } } } private List getFilesFromTransferable(Transferable t) throws Exception { if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) return (List) t.getTransferData(DataFlavor.javaFileListFlavor); String uris = (String) t.getTransferData(urilist); StringTokenizer tok = new StringTokenizer(uris); Vector files = new Vector(); while (tok.hasMoreTokens()) { String uri = tok.nextToken(); try { URL url = new URL(uri); if (url.getProtocol().equals("file")) { files.add(new File(url.getFile())); } } catch (Exception e) { e.printStackTrace(); } } return files; } public void dragOver(DropTargetDragEvent dtde) { if (!dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor) && !dtde.isDataFlavorSupported(urilist)) { // DataFlavor[] list = dtde.getCurrentDataFlavors(); // for( int i = 0 ; i < list.length ; i++ ) // System.out.println("" + list[i]); return; } if (localDrag != null) { for (int i = 0; i < localDrag.length; i++) { localDrag[i].setDragLocation(dtde.getLocation()); } dtde.acceptDrag(DnDConstants.ACTION_MOVE); return; } Transferable t = dtde.getTransferable(); try { List files = getFilesFromTransferable(t); if (files == null) { // well, we cannot really make much of it, just accept dtde.acceptDrag(DnDConstants.ACTION_COPY); return; } Iterator f = files.iterator(); boolean canUse = false; while (f.hasNext()) { File file = ((File) f.next()); Iterator it = ConversionService.registeredSerivces(); while (it.hasNext()) { ConversionService service = (ConversionService) it.next(); if (service.canConvert(file)) { dtde.acceptDrag(DnDConstants.ACTION_COPY); tabbedPane.setSelectedIndex(0); // doc pane return; } if (canUse(file) || service.canUse(file)) { canUse = true; } } } if (canUse) { dtde.acceptDrag(DnDConstants.ACTION_COPY); tabbedPane.setSelectedIndex(1); // resource pane return; } } catch (Exception e) { e.printStackTrace(); } dtde.rejectDrag(); } void nextLocation(FilePanel panel, Point loc, FileIcon icon) { loc.x += icon.getWidth() + 5; if (loc.x + icon.getWidth() > panel.getWidth()) { loc.x = 5; loc.y += icon.getHeight() + 5; } } private void copyResourceFile(File file, Image fileIcon, Point loc) { byte[] buffer = new byte[4096]; try { // for now, copy it synchronously if (!resourceFolder.equals(file.getParentFile())) { InputStream in = new FileInputStream(file); File target = GUIDriver.makeFile(resourceFolder, file.getName()); OutputStream out = new FileOutputStream(target); int len; while ((len = in.read(buffer)) > 0) { out.write(buffer, 0, len); } out.close(); in.close(); file = target; } FileIcon icon = new FileIcon(file, fileIcon, null, file.getName()); resourcePane.add(icon); icon.setLocation(loc); nextLocation(resourcePane, loc, icon); } catch (IOException e) { e.printStackTrace(); } } boolean addFile(File file, Point loc, boolean anyType) { boolean canAddResources = anyType || this == resourcePane; boolean canAddDocs = anyType || this == docPane; if (canAddResources && canUse(file)) { String nm = file.getName().toLowerCase(); BufferedImage fileIcon = getResIcon(nm); if (fileIcon != null) { copyResourceFile(file, fileIcon, loc); return true; } } Iterator it = ConversionService.registeredSerivces(); while (it.hasNext()) { ConversionService service = (ConversionService) it.next(); if (canAddDocs && service.canConvert(file)) { Image image = service.getIcon(file); FileIcon icon = new FileIcon(file, image, service, file.getName()); docPane.add(icon); icon.setLocation(loc); nextLocation(docPane, loc, icon); scheduleConversion(icon); return true; } if (canAddResources && service.canUse(file)) { Image image = service.getIcon(file); if (image != null) { copyResourceFile(file, image, loc); return true; } } } return false; } public void drop(DropTargetDropEvent dtde) { dragActive = false; if (!dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor) && !dtde.isDataFlavorSupported(urilist)) { dtde.rejectDrop(); return; } dtde.acceptDrop(DnDConstants.ACTION_LINK); Transferable t = dtde.getTransferable(); if (dtde.isLocalTransfer()) { localDrop(dtde); dtde.dropComplete(true); return; } try { Point loc = dtde.getLocation(); List files = getFilesFromTransferable(t); Iterator f = files.iterator(); boolean success = false; while (f.hasNext()) { File file = (File) f.next(); if (addFile(file, loc, true)) success = true; } dtde.dropComplete(success); } catch (Exception e) { e.printStackTrace(); } } public void startDrag(FileIcon src, DragGestureEvent dge) { InputEvent trigger = dge.getTriggerEvent(); Point dragStart = null; if (trigger instanceof MouseEvent) { dragStart = ((MouseEvent) trigger).getPoint(); Point pos = src.getLocation(); GUIDriver.this.dragStart = new Point(dragStart.x + pos.x, dragStart.y + pos.y); } Vector files = new Vector(); Vector dragIcons = new Vector(); Component[] components = getComponents(); for (int i = 0; i < components.length; i++) { if (components[i] instanceof FileIcon) { FileIcon fi = (FileIcon) components[i]; if (fi.highlighted) { files.add(fi.file); FileIcon di = fi.makeDragIcon(); dragIcons.add(di); add(di); setComponentZOrder(di, 0); } } } Transferable transferable = new FileTransferable(files); if (DragSource.isDragImageSupported()) { BufferedImage dragImage = new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_INT_ARGB); Graphics g = dragImage.getGraphics(); src.paint(g); g.dispose(); Point imageOffset = new Point(-dragStart.x, -dragStart.y); dge.startDrag(null, dragImage, imageOffset, transferable, this); } else { dge.startDrag(null, transferable, this); } localDrag = new FileIcon[dragIcons.size()]; dragIcons.copyInto(localDrag); } public void dropActionChanged(DropTargetDragEvent dtde) { // int action = dtde.getDropAction(); // System.err.println("Drop action: " + action); } public void localDrop(DropTargetDropEvent dtde) { Point dragEnd = dtde.getLocation(); int dx = dragEnd.x - dragStart.x; int dy = dragEnd.y - dragStart.y; Component[] components = getComponents(); for (int i = 0; i < components.length; i++) { if (components[i] instanceof FileIcon) { FileIcon fi = (FileIcon) components[i]; if (fi.highlighted) { Point loc = fi.getLocation(); loc.x += dx; loc.y += dy; fi.setLocation(loc); } } } } public void dragDropEnd(DragSourceDropEvent dsde) { for (int i = 0; i < localDrag.length; i++) { remove(localDrag[i]); } localDrag = null; // int action = dsde.getDropAction(); // System.err.println("Drop end: " + action); // we cannot really trust dsde.getDropSuccess() and action // check if any of our files got removed checkFiles(); } public void checkFiles() { Component[] components = getComponents(); boolean repaint = false; HashSet names = new HashSet(); int maxy = 0; for (int i = 0; i < components.length; i++) { if (components[i] instanceof FileIcon) { FileIcon fi = (FileIcon) components[i]; if (fi.file == null) return; if (!fi.file.exists()) { // file was moved remove(fi); repaint = true; } else if (fi.file.getParentFile().equals(folder)) { names.add(fi.file.getName()); int y = fi.getY() + fi.getHeight(); if (y > maxy) maxy = y; } } } Point location = new Point(5, maxy + 5); String[] list = folder.list(); if (list != null) { for (int i = 0; i < list.length; i++) { String name = list[i]; if (names.contains(name)) continue; File newFile = new File(folder, name); if (blackList.contains(newFile)) { if (newFile.delete()) blackList.remove(newFile); } else if (this == docPane && (isErrorLog(newFile) || isEPub(newFile))) { Image img = isErrorLog(newFile) ? errIcon : epubIcon; FileIcon icon = new FileIcon(newFile, img, null, name); add(icon); repaint = true; icon.setLocation(location); nextLocation(this, location, icon); } else { addFile(newFile, location, false); } } } if (repaint) { validate(); repaint(); } } public void dragEnter(DragSourceDragEvent dsde) { // System.err.println("Drag entered"); } public void dragExit(DragSourceEvent dse) { // System.err.println("Drag exited"); } public void dragOver(DragSourceDragEvent dsde) { // System.err.println("Drag over"); } public void dropActionChanged(DragSourceDragEvent dsde) { // int action = dsde.getDropAction(); // System.err.println("Drop source action: " + action); } public Dimension getPreferredSize() { Component[] components = getComponents(); int width = 100; int height = 100; if (components != null) for (int i = 0; i < components.length; i++) { Component c = components[i]; int w = c.getX() + c.getWidth(); int h = c.getY() + c.getHeight(); if (w > width) width = w; if (h > height) height = h; } return new Dimension(width, height); } } class FileIcon extends JComponent implements DragGestureListener { public static final long serialVersionUID = 0; File file; Image icon; Image highlightedIcon; ConversionService service; boolean highlighted; boolean dragIcon; String name; Point initial; String log; FileIcon(File file, Image icon, ConversionService service, String name) { this.file = file; this.icon = icon; this.service = service; this.name = name; this.dragIcon = file == null; setOpaque(false); setSize(64, 88); if (!FileIcon.this.dragIcon) { addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent evt) { if (!highlighted && !evt.isControlDown()) ((FilePanel) getParent()).resetSelection(); highlighted = true; repaint(); } public void mouseReleased(MouseEvent evt) { if (highlighted && !evt.isControlDown()) { ((FilePanel) getParent()).resetSelection(); highlighted = true; } } }); int actions = DnDConstants.ACTION_COPY_OR_MOVE; dragSource.createDefaultDragGestureRecognizer(this, actions, this); } } void setLog(String log) { this.log = log; } void clearHighlight() { highlighted = false; repaint(); } FileIcon makeDragIcon() { FileIcon fi = new FileIcon(null, icon, null, name); fi.highlighted = true; fi.initial = getLocation(); fi.setLocation(fi.initial); return fi; } void setDragLocation(Point dragNow) { if (dragStart != null) { int newX = initial.x + dragNow.x - dragStart.x; int newY = initial.y + dragNow.y - dragStart.y; setLocation(newX, newY); } } public void paint(Graphics g) { Graphics baseG = g; BufferedImage group = null; if (dragIcon) { if (!dragActive) return; group = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB); g = group.getGraphics(); } Graphics2D g2d = ((Graphics2D) g); int width = getWidth(); int height = 50; if (this == currentlyConverting) { // show being converted Random r = new Random(); int[] pix = new int[50 * 50]; for (int i = 0; i < 50; i++) { int xd; if (i < 11) xd = 11 - i; else if (i > 38) xd = i - 38; else xd = 0; for (int j = 0; j < 50; j++) { int yd; if (j < 11) yd = 11 - j; else if (j > 38) yd = j - 38; else yd = 0; float d; if (xd == 0 && yd == 0) d = 11; else d = 11 - (float) Math.sqrt(xd * xd + yd * yd); float p = 20 * r.nextFloat(); if (d > p) { p = 11 * r.nextFloat(); if (p > d) pix[i * 50 + j] = 0xFFFFFF00; else pix[i * 50 + j] = 0xFFFF0000; } else pix[i * 50 + j] = 0; } } Image img = createImage(new MemoryImageSource(50, 50, pix, 0, 50)); g.drawImage(img, 7, 0, null); } if (icon != null) { int iwidth = icon.getWidth(this); int iheight = icon.getHeight(this); int x = (width - iwidth) / 2; int y = (height - iheight) / 2; if (highlighted) { if (highlightedIcon == null) { ImageFilter filter = new HighlightedFilter(); ImageProducer producer = new FilteredImageSource(icon.getSource(), filter); highlightedIcon = createImage(producer); } g.drawImage(highlightedIcon, x, y, this); } else g.drawImage(icon, x, y, this); } int[] lineBreaks = new int[3]; int[] offx = new int[lineBreaks.length]; int lbi = 0; Font font = new Font("SansSerif", Font.PLAIN, 11); g.setFont(font); FontMetrics fm = g.getFontMetrics(); int em = fm.charWidth('m'); int emlen = width / em; char[] nameChars = name.toCharArray(); int chi = 0; while (chi < nameChars.length && lbi < lineBreaks.length) { int len = emlen; if (chi + len > nameChars.length) len = nameChars.length - chi; int chw = fm.charsWidth(nameChars, chi, len); if (chw > width) { while (len > 1) { len--; chw = fm.charsWidth(nameChars, chi, len); if (chw <= width) break; } } else { while (chi + len < nameChars.length) { len++; int chw1 = fm.charsWidth(nameChars, chi, len); if (chw1 > width) { len--; break; } chw = chw1; } } chi += len; offx[lbi] = (width - chw) / 2; lineBreaks[lbi++] = chi; } chi = 0; if (highlighted) { // g.setColor(new Color(0x4070C0)); g2d.setPaint(new Color(0, 0.2f, 0.8f, 0.75f)); Rectangle rect = new Rectangle(0, getHeight() - lineBreaks.length * fm.getHeight(), width, lbi * fm.getHeight()); g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); g2d.fill(rect); g.setColor(Color.white); } for (int line = 0; line < lbi; line++) { int chi1 = lineBreaks[line]; int ty = getHeight() - fm.getDescent() - (lineBreaks.length - 1 - line) * fm.getHeight(); g.drawString(name.substring(chi, chi1), offx[line], ty); chi = chi1; } if (group != null) { g.dispose(); AlphaFilter filter = new AlphaFilter(); filter.setLevel(0.5f); ImageProducer producer = new FilteredImageSource(group.getSource(), filter); Image filtered = createImage(producer); baseG.drawImage(filtered, 0, 0, null); } } public void dragGestureRecognized(DragGestureEvent dge) { ((FilePanel) getParent()).startDrag(this, dge); } void changeFile(File file, Image icon) { FilePanel fp = ((FilePanel) getParent()); File folder = fp.folder; if (folder.equals(this.file.getParentFile())) { if (!this.file.delete()) { fp.blackList.add(this.file); } } service = null; this.file = file; this.icon = icon; this.name = file.getName(); highlightedIcon = null; repaint(); } } class FileTransferable implements Transferable { Vector list; FileTransferable(Vector list) { this.list = list; } public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { if (flavor.equals(DataFlavor.javaFileListFlavor)) return list; if (flavor.equals(urilist)) { StringBuffer sb = new StringBuffer(); Iterator it = list.iterator(); while (it.hasNext()) { File f = (File) it.next(); if (sb.length() > 0) sb.append(' '); sb.append(f.toURI()); } return sb.toString(); } throw new UnsupportedFlavorException(flavor); } public DataFlavor[] getTransferDataFlavors() { DataFlavor[] flavors = { DataFlavor.javaFileListFlavor, urilist }; return flavors; } public boolean isDataFlavorSupported(DataFlavor flavor) { return flavor.equals(DataFlavor.javaFileListFlavor) || flavor.equals(urilist); } } class Converter extends Thread implements ConversionClient { Converter() { super("Converter"); setDaemon(true); } public void run() { while (true) { FileIcon item; synchronized (conversionQueue) { while (conversionQueue.size() == 0) { try { conversionQueue.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } item = (FileIcon) conversionQueue.get(0); conversionQueue.removeElementAt(0); currentlyConverting = item; } final Vector resources = new Vector(); try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { Component[] components = resourcePane.getComponents(); for (int i = 0; i < components.length; i++) { if (components[i] instanceof FileIcon) { FileIcon fi = (FileIcon) components[i]; if (fi.file != null) { resources.add(fi.file); } } } } }); } catch (Exception e) { e.printStackTrace(); } File[] reslist = new File[resources.size()]; resources.copyInto(reslist); reportProgress(0); item.service.setProperties(settings); final FileIcon srcItem = item; StringWriter log = new StringWriter(); PrintWriter plog = new PrintWriter(log); plog.println("Conversion log for " + item.file.getAbsolutePath()); plog.println("Start: " + new Date()); final File res = item.service.convert(item.file, reslist, this, plog); plog.println("End: " + new Date()); final String logTxt = log.toString(); try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { if (res == null) { File dest = GUIDriver.makeFile(docFolder, "error.txt"); try { Writer out = new OutputStreamWriter(new FileOutputStream(dest), "UTF-8"); out.write(logTxt); out.close(); } catch (Exception e) { e.printStackTrace(); } srcItem.changeFile(dest, errIcon); } else { File dest = GUIDriver.makeFile(docFolder, res.getName()); if (res.renameTo(dest)) srcItem.changeFile(dest, epubIcon); else srcItem.changeFile(res, epubIcon); } srcItem.setLog(logTxt); currentlyConverting = null; } }); } catch (Exception e) { e.printStackTrace(); } reportProgress(1); } } public void reportIssue(String errorCode) { } public void reportProgress(float progress) { } public File makeFile(String baseName) { return GUIDriver.makeFile(workFolder, baseName); } } public GUIDriver(File epubgenHome) { super("EPUBGen - Buttonless Converter"); if (epubgenHome == null || !epubgenHome.isDirectory()) { File home = new File(System.getProperty("user.home")); epubgenHome = new File(home, "EPUBGen"); } docFolder = new File(epubgenHome, "Documents"); docFolder.mkdirs(); resourceFolder = new File(epubgenHome, "Resources"); resourceFolder.mkdirs(); File settingsFolder = new File(epubgenHome, "Settings"); settingsFolder.mkdirs(); settingsFile = new File(settingsFolder, "settings.prop"); workFolder = new File(epubgenHome, "Work"); workFolder.mkdirs(); if (settingsFile.exists()) { try { settings.load(new FileInputStream(settingsFile)); } catch (Exception e) { e.printStackTrace(); } } docPane = new FilePanel(docFolder); resourcePane = new FilePanel(resourceFolder); settingsPane = new SettingsPanel(); tabbedPane = new JTabbedPane(); try { helpPane = new JEditorPane(GUIDriver.class.getResource("help.html")); helpPane.setEditable(false); } catch (IOException e) { e.printStackTrace(); } getContentPane().setLayout(new BorderLayout()); getContentPane().add(tabbedPane); tabbedPane.add("Documents", new JScrollPane(docPane)); tabbedPane.add("Resources", new JScrollPane(resourcePane)); tabbedPane.add("Settings", new JScrollPane(settingsPane)); if (helpPane != null) tabbedPane.add("Help", new JScrollPane(helpPane)); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); setSize(350, 250); try { InputStream png = GUIDriver.class.getResourceAsStream("epub.png"); epubIcon = ImageIO.read(png); png = GUIDriver.class.getResourceAsStream("css.png"); cssIcon = ImageIO.read(png); png = GUIDriver.class.getResourceAsStream("otf.png"); otfIcon = ImageIO.read(png); png = GUIDriver.class.getResourceAsStream("ttf.png"); ttfIcon = ImageIO.read(png); png = GUIDriver.class.getResourceAsStream("err.png"); errIcon = ImageIO.read(png); } catch (IOException e) { e.printStackTrace(); } (new Converter()).start(); new Updater(); new FileCheck(); } public static File makeFile(File folder, String baseName) { File file = new File(folder, baseName); if (file.exists()) { String baseStr; String extStr; int ext = baseName.indexOf('.'); if (ext < 0) { baseStr = baseName; extStr = ""; } else { baseStr = baseName.substring(0, ext); extStr = baseName.substring(ext); } int count = 1; while (true) { file = new File(folder, baseStr + "-" + count + extStr); if (!file.exists()) break; count++; } } return file; } void scheduleConversion(FileIcon file) { synchronized (conversionQueue) { conversionQueue.add(file); conversionQueue.notify(); } } public static void main(String[] args) { File home = null; if (args.length == 1) { home = new File(args[0]); if (!home.isDirectory()) System.err.println(args[0] + ": not a folder"); } GUIDriver conv = new GUIDriver(home); conv.setVisible(true); } }