/*
* @(#)SerializationInputOutputFormat.java
*
* Copyright (c) 2009-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.draw.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.filechooser.FileFilter;
import org.jhotdraw.gui.datatransfer.AbstractTransferable;
import org.jhotdraw.gui.filechooser.ExtensionFileFilter;
/**
* {@code SerializationInputOutputFormat} uses Java Serialization for reading and
* and writing {@code Drawing} objects.
*
* @author Werner Randelshofer
* @version $Id$
*/
public class SerializationInputOutputFormat implements InputFormat, OutputFormat {
/**
* 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;
private Drawing prototype;
/** Creates a new instance with format name "Drawing", file extension "xml"
* and mime type "image/x-jhotdraw".
*/
public SerializationInputOutputFormat() {
this("Drawing", "ser", new DefaultDrawing());
}
/** Creates a new instance using the specified parameters.
*/
public SerializationInputOutputFormat(
String description, String fileExtension, Drawing prototype) {
this.description = description;
this.fileExtension = fileExtension;
this.mimeType = DataFlavor.javaSerializedObjectMimeType;
this.prototype = prototype;
this.dataFlavor = new DataFlavor(prototype.getClass(), description);
}
@Override
public FileFilter getFileFilter() {
return new ExtensionFileFilter(description, fileExtension);
}
@Override
public JComponent getInputFormatAccessory() {
return null;
}
@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 {
BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
try {
read(in, drawing, replace);
} finally {
in.close();
}
}
@SuppressWarnings("unchecked")
@Override
public void read(InputStream in, Drawing drawing, boolean replace) throws IOException {
try {
ObjectInputStream oin = new ObjectInputStream(in);
Drawing d = (Drawing) oin.readObject();
if (replace) {
for (Map.Entry<AttributeKey<?>, Object> e : d.getAttributes().entrySet()) {
drawing.set((AttributeKey<Object>)e.getKey(), e.getValue());
}
}
for (Figure f : d.getChildren()) {
drawing.add(f);
}
} catch (ClassNotFoundException ex) {
IOException ioe = new IOException("Couldn't read drawing.");
ioe.initCause(ex);
throw ioe;
}
}
@Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.equals(dataFlavor);
}
@SuppressWarnings("unchecked")
@Override
public void read(Transferable t, Drawing drawing, boolean replace) throws UnsupportedFlavorException, IOException {
try {
Drawing d = (Drawing) t.getTransferData(dataFlavor);
if (replace) {
for (Map.Entry<AttributeKey<?>, Object> e : d.getAttributes().entrySet()) {
drawing.set((AttributeKey<Object>)e.getKey(), e.getValue());
}
}
for (Figure f : d.getChildren()) {
drawing.add(f);
}
} catch (Throwable th) {
th.printStackTrace();
}
}
@Override
public String getFileExtension() {
return fileExtension;
}
@Override
public JComponent getOutputFormatAccessory() {
return null;
}
@Override
public void write(URI uri, Drawing drawing) throws IOException {
write(new File(uri),drawing);
}
public void write(File file, Drawing drawing) throws IOException {
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
try {
write(out, drawing);
} finally {
out.close();
}
}
@Override
public void write(OutputStream out, Drawing drawing) throws IOException {
ObjectOutputStream oout = new ObjectOutputStream(out);
oout.writeObject(drawing);
oout.flush();
}
@SuppressWarnings("unchecked")
@Override
public Transferable createTransferable(Drawing drawing, List<Figure> figures, double scaleFactor) throws IOException {
final Drawing d = (Drawing) prototype.clone();
HashMap<Figure, Figure> originalToDuplicateMap = new HashMap<Figure, Figure>(figures.size());
final ArrayList<Figure> duplicates = new ArrayList<Figure>(figures.size());
for (Figure f : figures) {
Figure df = f.clone();
d.add(df);
duplicates.add(df);
originalToDuplicateMap.put(f, df);
}
for (Figure f : duplicates) {
f.remap(originalToDuplicateMap, true);
}
return new AbstractTransferable(dataFlavor) {
@Override
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
if (isDataFlavorSupported(flavor)) {
return d;
} else {
throw new UnsupportedFlavorException(flavor);
}
}
};
}
}