package com.baselet.diagram.io; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.filechooser.FileFilter; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import com.baselet.control.config.Config; import com.baselet.control.constants.Constants; import com.baselet.control.enums.Program; import com.baselet.control.util.Path; import com.baselet.control.util.RecentlyUsedFilesList; import com.baselet.diagram.CurrentDiagram; import com.baselet.diagram.DiagramHandler; import com.baselet.diagram.Notifier; import com.baselet.element.NewGridElement; import com.baselet.element.interfaces.GridElement; import com.baselet.element.old.custom.CustomElement; import com.baselet.gui.CurrentGui; public class DiagramFileHandler { private static final Logger log = LoggerFactory.getLogger(DiagramFileHandler.class); private String fileName; private final DiagramHandler handler; private File file; private File lastExportFile; private final HashMap<String, FileFilter> filters = new HashMap<String, FileFilter>(); private final HashMap<FileFilter, String> fileextensions = new HashMap<FileFilter, String>(); private final OwnFileFilter filterxml = new OwnFileFilter(Program.getInstance().getExtension(), Program.getInstance().getProgramName() + " diagram format"); private final OwnFileFilter filterbmp = new OwnFileFilter("bmp", "BMP"); private final OwnFileFilter filtereps = new OwnFileFilter("eps", "EPS"); private final OwnFileFilter filtergif = new OwnFileFilter("gif", "GIF"); private final OwnFileFilter filterjpg = new OwnFileFilter("jpg", "JPG"); private final OwnFileFilter filterpdf = new OwnFileFilter("pdf", "PDF"); private final OwnFileFilter filterpng = new OwnFileFilter("png", "PNG"); private final OwnFileFilter filtersvg = new OwnFileFilter("svg", "SVG"); private final OwnFileFilter[] saveFileFilter = new OwnFileFilter[] { filterxml }; private final OwnFileFilter[] exportFileFilter = new OwnFileFilter[] { filterbmp, filtereps, filtergif, filterjpg, filterpdf, filterpng, filtersvg }; private final List<OwnFileFilter> allFileFilters = new ArrayList<OwnFileFilter>(); protected DiagramFileHandler(DiagramHandler diagramHandler, File file) { handler = diagramHandler; if (file != null) { fileName = file.getName(); } else { fileName = "new." + Program.getInstance().getExtension(); } this.file = file; lastExportFile = file; allFileFilters.addAll(Arrays.asList(saveFileFilter)); allFileFilters.addAll(Arrays.asList(exportFileFilter)); for (OwnFileFilter filter : allFileFilters) { filters.put(filter.getFormat(), filter); fileextensions.put(filter, filter.getFormat()); } } public static DiagramFileHandler createInstance(DiagramHandler diagramHandler, File file) { return new DiagramFileHandler(diagramHandler, file); } private JFileChooser createSaveFileChooser(boolean exportCall) { JFileChooser fileChooser = new JFileChooser(calcInitialDir(exportCall)); fileChooser.setAcceptAllFileFilterUsed(false); // We don't want "all files" as a choice // The input field should show the diagram name as preset fileChooser.setSelectedFile(new File(CurrentDiagram.getInstance().getDiagramHandler().getName())); return fileChooser; } private File calcInitialDir(boolean exportCall) { if (exportCall && lastExportFile != null) { // if this is an export-diagram call the diagram was exported once before (for consecutive export calls - see Issue 82) return lastExportFile; } else if (file != null) { // otherwise if diagram has a fixed uxf path, use this return file; } else { // otherwise use the last used save path return new File(Config.getInstance().getSaveFileHome()); } } public String getFileName() { return fileName; } public String getFullPathName() { if (file != null) { return file.getAbsolutePath(); } return ""; } private void setFileName(String fileName) { this.fileName = fileName; CurrentGui.getInstance().getGui().updateDiagramName(handler, handler.getName()); } private void createXMLOutputDoc(Document doc, Collection<GridElement> elements, Element current) { for (GridElement e : elements) { appendRecursively(doc, current, e); } } private void appendRecursively(Document doc, Element parentXmlElement, GridElement e) { parentXmlElement.appendChild(createXmlElementForGridElement(doc, e)); } private Element createXmlElementForGridElement(Document doc, GridElement e) { // insert normal entity element java.lang.Class<? extends GridElement> c = e.getClass(); String sElType = c.getName(); String sElPanelAttributes = e.getPanelAttributes(); String sElAdditionalAttributes = e.getAdditionalAttributes(); Element el = doc.createElement("element"); if (e instanceof NewGridElement) { Element elType = doc.createElement("id"); elType.appendChild(doc.createTextNode(((NewGridElement) e).getId().toString())); el.appendChild(elType); } else { // OldGridElement Element elType = doc.createElement("type"); elType.appendChild(doc.createTextNode(sElType)); el.appendChild(elType); } Element elCoor = doc.createElement("coordinates"); el.appendChild(elCoor); Element elX = doc.createElement("x"); elX.appendChild(doc.createTextNode("" + e.getRectangle().x)); elCoor.appendChild(elX); Element elY = doc.createElement("y"); elY.appendChild(doc.createTextNode("" + e.getRectangle().y)); elCoor.appendChild(elY); Element elW = doc.createElement("w"); elW.appendChild(doc.createTextNode("" + e.getRectangle().width)); elCoor.appendChild(elW); Element elH = doc.createElement("h"); elH.appendChild(doc.createTextNode("" + e.getRectangle().height)); elCoor.appendChild(elH); Element elPA = doc.createElement("panel_attributes"); elPA.appendChild(doc.createTextNode(sElPanelAttributes)); el.appendChild(elPA); Element elAA = doc.createElement("additional_attributes"); elAA.appendChild(doc.createTextNode(sElAdditionalAttributes)); el.appendChild(elAA); if (e instanceof CustomElement) { Element elCO = doc.createElement("custom_code"); elCO.appendChild(doc.createTextNode(((CustomElement) e).getCode())); el.appendChild(elCO); } return el; } protected String createStringToBeSaved() { DocumentBuilder db = null; String returnString = null; try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); db = dbf.newDocumentBuilder(); Document doc = db.newDocument(); Element root = doc.createElement("diagram"); root.setAttribute("program", Program.getInstance().getProgramName().toLowerCase()); root.setAttribute("version", String.valueOf(Program.getInstance().getVersion())); doc.appendChild(root); // save helptext String helptext = handler.getHelpText(); if (!helptext.equals(Constants.getDefaultHelptext())) { Element help = doc.createElement("help_text"); help.appendChild(doc.createTextNode(helptext)); root.appendChild(help); } // save zoom Element zoom = doc.createElement("zoom_level"); zoom.appendChild(doc.createTextNode(String.valueOf(handler.getGridSize()))); root.appendChild(zoom); createXMLOutputDoc(doc, handler.getDrawPanel().getGridElements(), root); // output the stuff... DOMSource source = new DOMSource(doc); StringWriter stringWriter = new StringWriter(); StreamResult result = new StreamResult(stringWriter); TransformerFactory transFactory = TransformerFactory.newInstance(); Transformer transformer = transFactory.newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); transformer.transform(source, result); returnString = stringWriter.toString(); } catch (Exception e) { log.error("Error saving XML.", e); } return returnString; } public void doOpen() { try { SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); FileInputStream input = new FileInputStream(file); InputHandler xmlhandler = new InputHandler(handler); parser.parse(input, xmlhandler); input.close(); } catch (Exception e) { log.error("Cannot open the file: " + file.getAbsolutePath(), e); } } public void doSaveAs(String fileextension) throws IOException { boolean ownXmlFormat = fileextension.equals(Program.getInstance().getExtension()); JFileChooser fileChooser = createSaveFileChooser(!ownXmlFormat); String fileName = chooseFileName(ownXmlFormat, filters.get(fileextension), fileChooser); String extension = fileextensions.get(fileChooser.getFileFilter()); if (fileName == null) { return; // If the filechooser has been closed without saving } if (!fileName.endsWith("." + extension)) { fileName += "." + extension; } File fileToSave = new File(fileName); Config.getInstance().setSaveFileHome(fileToSave.getParent()); if (extension.equals(Program.getInstance().getExtension())) { file = fileToSave; setFileName(file.getName()); save(); } else { lastExportFile = fileToSave; doExportAs(extension, fileToSave); } } public File doSaveTempDiagram(String filename, String fileextension) throws IOException { File tempFile = new File(Path.temp() + filename + "." + fileextension); tempFile.deleteOnExit(); if (fileextension.equals(Program.getInstance().getExtension())) { save(tempFile, true); } else { doExportAs(fileextension, tempFile); } return tempFile; } public void doSave() throws IOException { if (file == null || !file.exists()) { doSaveAs(Program.getInstance().getExtension()); } else { save(); } } public void doExportAs(String extension, File file) throws IOException { // CustomElementSecurityManager.addThreadPrivileges(Thread.currentThread(), fileName); try { OutputHandler.createAndOutputToFile(extension, file, handler); } catch (Exception e) { throw new IOException(e.getMessage()); } // CustomElementSecurityManager.remThreadPrivileges(Thread.currentThread()); } private void save() throws UnsupportedEncodingException, FileNotFoundException { save(file, false); // If save is called without a parameter it uses the class variable "file" } private void save(File saveToFile, boolean tempFile) throws UnsupportedEncodingException, FileNotFoundException { String tmp = createStringToBeSaved(); PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(saveToFile), "UTF-8")); out.print(tmp); out.close(); if (!tempFile) { handler.setChanged(false); RecentlyUsedFilesList.getInstance().add(saveToFile.getAbsolutePath()); } Notifier.getInstance().showInfo(saveToFile.getAbsolutePath() + " saved"); } private String chooseFileName(boolean ownXmlFormat, FileFilter filefilter, JFileChooser fileChooser) { String fileName = null; setAvailableFileFilters(ownXmlFormat, fileChooser); fileChooser.setFileFilter(filefilter); int returnVal = fileChooser.showSaveDialog(CurrentGui.getInstance().getGui().getMainFrame()); if (returnVal == JFileChooser.APPROVE_OPTION) { File selectedFileWithExt = getFileWithExtension(fileChooser); if (selectedFileWithExt.exists()) { int overwriteQuestionResult = JOptionPane.showConfirmDialog(CurrentGui.getInstance().getGui().getMainFrame(), "File already exists! Overwrite?", "Overwrite File", JOptionPane.YES_NO_OPTION); if (overwriteQuestionResult == JOptionPane.NO_OPTION) { return chooseFileName(ownXmlFormat, filefilter, fileChooser); } } fileName = selectedFileWithExt.getAbsolutePath(); } return fileName; } /** * If the filename of the filechooser has no extension, the extension from the filefilter is added to the name * @param saveFileChooser2 */ private File getFileWithExtension(JFileChooser fileChooser) { String extension = "." + fileextensions.get(fileChooser.getFileFilter()); String filename = fileChooser.getSelectedFile().getAbsolutePath(); if (!filename.endsWith(extension)) { filename += extension; } File selectedFileWithExt = new File(filename); return selectedFileWithExt; } /** * Updates the available FileFilter to "only uxf/pxf" or "all but uxf/pxf" * * @param ownXmlFormat * If this param is set, only uxf/pxf is visible, otherwise all but uxf/pxf is visible */ private void setAvailableFileFilters(boolean ownXmlFormat, JFileChooser fileChooser) { if (ownXmlFormat) { fileChooser.resetChoosableFileFilters(); fileChooser.addChoosableFileFilter(filterxml); } else { fileChooser.resetChoosableFileFilters(); fileChooser.addChoosableFileFilter(filterbmp); fileChooser.addChoosableFileFilter(filtereps); fileChooser.addChoosableFileFilter(filtergif); fileChooser.addChoosableFileFilter(filterjpg); fileChooser.addChoosableFileFilter(filterpdf); fileChooser.addChoosableFileFilter(filterpng); fileChooser.addChoosableFileFilter(filtersvg); } } protected static class OwnFileFilter extends FileFilter { private final String format; private final String description; protected OwnFileFilter(String format, String description) { this.format = format; this.description = description; } @Override public boolean accept(File f) { return f.getName().endsWith("." + format) || f.isDirectory(); } @Override public String getDescription() { return description + " (*." + format + ")"; } public String getFormat() { return format; } } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (file == null ? 0 : file.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } DiagramFileHandler other = (DiagramFileHandler) obj; if (file == null) { if (other.file != null) { return false; } } else if (!file.equals(other.file)) { return false; } return true; } }