/* * @(#)DOMStorableOutputFormat.java * * Copyright (c) 1996-2010 The authors and contributors of JHotDraw. * You may not use, copy or modify this file, except in compliance with the * accompanying license terms. */ package org.jhotdraw.draw.io; import org.jhotdraw.gui.filechooser.ExtensionFileFilter; import org.jhotdraw.draw.*; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.*; import java.net.URI; import java.net.URL; import java.util.LinkedList; import java.util.List; import javax.swing.JComponent; import org.jhotdraw.gui.datatransfer.InputStreamTransferable; import org.jhotdraw.xml.*; /** * An OutputFormat that can write Drawings with DOMStorable Figure's. * <p> * This class is here to support quick-and-dirty implementations of drawings * that can be read and written from/to output streams. For example, in student * projects. * <p> * This class should no be used as a means to implement long-term storage of * drawings, since it does not support structural changes that might occur in * a drawing application over time. * * @author Werner Randelshofer * @version $Id$ */ public class DOMStorableInputOutputFormat implements OutputFormat, InputFormat { private DOMFactory factory; /** * Format description used for the file filter. */ private String description; /** * File name extension used for the file filter. */ private String fileExtension; /** * Image IO image format name. */ private String formatName; /** * The mime type is used for clipboard access. */ private String mimeType; /** * The data flavor constructed from the mime type. */ private DataFlavor dataFlavor; /** Creates a new instance with format name "Drawing", file extension "xml" * and mime type "image/x-jhotdraw". */ public DOMStorableInputOutputFormat(DOMFactory factory) { this(factory, "Drawing", "xml", "image/x-jhotdraw"); } /** Creates a new instance using the specified parameters. * * @param factory The factory for creating Figures from XML elements. * @param description The format description to be used for the file filter. * @param fileExtension The file extension to be used for file filter. * @param mimeType The Mime Type is used for clipboard access. */ public DOMStorableInputOutputFormat( DOMFactory factory, String description, String fileExtension, String mimeType) { this.factory = factory; this.description = description; this.fileExtension = fileExtension; this.mimeType = mimeType; try { this.dataFlavor = new DataFlavor(mimeType); } catch (ClassNotFoundException ex) { InternalError error = new InternalError("Unable to create data flavor for mime type:" + mimeType); error.initCause(ex); throw error; } } @Override public javax.swing.filechooser.FileFilter getFileFilter() { return new ExtensionFileFilter(description, fileExtension); } @Override public JComponent getOutputFormatAccessory() { return null; } @Override public JComponent getInputFormatAccessory() { return null; } /** * Reads a list of figures into the specified drawing. * This method expects that there is a child element named "figures" * in the element that represents the drawing. */ protected void read(URL url, InputStream in, Drawing drawing, LinkedList<Figure> figures) throws IOException { NanoXMLDOMInput domi = new NanoXMLDOMInput(factory, in); domi.openElement(factory.getName(drawing)); domi.openElement("figures", 0); figures.clear(); for (int i = 0, n = domi.getElementCount(); i < n; i++) { Figure f = (Figure) domi.readObject(); figures.add(f); } domi.closeElement(); domi.closeElement(); drawing.basicAddAll(drawing.getChildCount(), figures); } @Override public String getFileExtension() { return fileExtension; } @Override public boolean isDataFlavorSupported(DataFlavor flavor) { return flavor.equals(dataFlavor); } @Override public void write(URI uri, Drawing drawing) throws IOException { write(new File(uri),drawing); } public void write(File file, Drawing drawing) throws IOException { try (BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file))) { write(out, drawing); } } @Override public void write(OutputStream out, Drawing drawing) throws IOException { NanoXMLDOMOutput domo = new NanoXMLDOMOutput(factory); domo.openElement(factory.getName(drawing)); drawing.write(domo); domo.closeElement(); domo.save(out); domo.dispose(); } @Override public void read(URI uri, Drawing drawing) throws IOException { read(new File(uri), drawing); } @Override public void read(URI uri, Drawing drawing, boolean replace) throws IOException { read(new File(uri), drawing, replace); } public void read(File file, Drawing drawing) throws IOException { read(file, drawing, true); } public void read(File file, Drawing drawing, boolean replace) throws IOException { try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(file))) { read(in, drawing, replace); } } @Override public void read(InputStream in, Drawing drawing, boolean replace) throws IOException { NanoXMLDOMInput domi = new NanoXMLDOMInput(factory, in); domi.openElement(factory.getName(drawing)); if (replace) { drawing.removeAllChildren(); } drawing.read(domi); domi.closeElement(); domi.dispose(); } @Override public void read(Transferable t, Drawing drawing, boolean replace) throws UnsupportedFlavorException, IOException { LinkedList<Figure> figures = new LinkedList<>(); InputStream in = (InputStream) t.getTransferData(new DataFlavor(mimeType, description)); NanoXMLDOMInput domi = new NanoXMLDOMInput(factory, in); domi.openElement("Drawing-Clip"); for (int i = 0, n = domi.getElementCount(); i < n; i++) { Figure f = (Figure) domi.readObject(i); figures.add(f); } domi.closeElement(); if (replace) { drawing.removeAllChildren(); } drawing.addAll(figures); } @Override public Transferable createTransferable(Drawing drawing, List<Figure> figures, double scaleFactor) throws IOException { ByteArrayOutputStream buf = new ByteArrayOutputStream(); NanoXMLDOMOutput domo = new NanoXMLDOMOutput(factory); domo.openElement("Drawing-Clip"); for (Figure f : figures) { domo.writeObject(f); } domo.closeElement(); domo.save(buf); return new InputStreamTransferable(new DataFlavor(mimeType, description), buf.toByteArray()); } }