/*
* Freeplane - mind map editor
* Copyright (C) 2008 Joerg Mueller, Daniel Polansky, Christian Foltin, Dimitry Polivaev
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.freeplane.features.export.mindmapmode;
import java.awt.image.RenderedImage;
import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.URL;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
import javax.swing.ListModel;
import javax.swing.filechooser.FileFilter;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.lang.StringUtils;
import org.freeplane.core.resources.ResourceController;
import org.freeplane.core.ui.ExampleFileFilter;
import org.freeplane.core.ui.components.UITools;
import org.freeplane.core.util.Compat;
import org.freeplane.core.util.FileUtils;
import org.freeplane.core.util.LogUtils;
import org.freeplane.core.util.TextUtils;
import org.freeplane.features.icon.UIIcon;
import org.freeplane.features.map.MapModel;
import org.freeplane.features.map.MapWriter.Mode;
import org.freeplane.features.mode.Controller;
import org.freeplane.features.mode.ModeController;
import org.freeplane.features.url.UrlManager;
/**
* @author foltin To change the template for this generated type comment go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
public class ExportWithXSLT implements IExportEngine {
private static final Pattern propertyReferenceEpression = Pattern.compile("\\$\\{[^}]+\\}");
/**
* @param map
*/
static void copyIconsToDirectory(final MapModel map, final String directoryName) {
final ListModel icons = map.getIconRegistry().getIconsAsListModel();
for (int i = 0; i < icons.getSize(); i++) {
final UIIcon icon = (UIIcon) icons.getElementAt(i);
final String iconName = icon.getName();
final StringBuilder sb = new StringBuilder(directoryName);
final int lastIndexOfSeparator = iconName.lastIndexOf('/');
if (lastIndexOfSeparator != -1) {
sb.append(File.separatorChar);
sb.append(iconName.substring(0, lastIndexOfSeparator));
}
final File destinationDirectory = new File(sb.toString());
destinationDirectory.mkdirs();
FileUtils.copyFromURL(icon.getUrl(), destinationDirectory);
}
}
/**
* For test purposes. True=no error
*/
private boolean mTransformResultWithoutError = false;
final private Properties properties;
private final String name;
public ExportWithXSLT(final String name, final Properties properties) {
this.name = name;
this.properties = properties;
}
/**
*/
private void copyFilesFromResourcesToDirectory(final String targetDirectoryName, final String sourceDirectoryPath,
final String files) {
final StringTokenizer tokenizer = new StringTokenizer(files, ",");
final File destinationDirectory = new File(targetDirectoryName);
while (tokenizer.hasMoreTokens()) {
final String sourceFile = tokenizer.nextToken();
int nameStartPosition = sourceFile.lastIndexOf('/') + 1;
String sourceFileDirectory = nameStartPosition > 0 ? sourceFile.substring(0, nameStartPosition) : "";
String sourceFileName = nameStartPosition > 0 ? sourceFile.substring(nameStartPosition) : sourceFile;
FileUtils.copyFromResource(sourceDirectoryPath + sourceFileDirectory, sourceFileName, destinationDirectory);
}
}
/**
* @param map
*/
private boolean copyIcons(final MapModel map, final String directoryName) {
boolean success;
final String iconDirectoryName = directoryName + File.separatorChar + "icons";
success = FileUtils.createDirectory(iconDirectoryName);
if (success) {
ExportWithXSLT.copyIconsToDirectory(map, iconDirectoryName);
}
return success;
}
private boolean copyMap(final MapModel map, final String pDirectoryName) {
boolean success = true;
try {
final BufferedWriter fileout = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(
pDirectoryName + File.separator + "map" + UrlManager.FREEPLANE_FILE_EXTENSION)));
final Mode mode = Mode.valueOf(getProperty("copymode", Mode.EXPORT.name()));
Controller.getCurrentModeController().getMapController().getFilteredXml(map, fileout, mode, Mode.EXPORT.equals(mode));
}
catch (final IOException e) {
success = false;
}
return success;
}
private int getImageResolutionDPI() {
return ResourceController.getResourceController().getIntProperty("exported_image_resolution_dpi", 300);
}
/**
* @param map
*/
private boolean createImageFromMap(MapModel map, final String directoryName) {
if (Controller.getCurrentController().getMapViewManager().getMapViewComponent() == null) {
return false;
}
final RenderedImage image = new ImageCreator(getImageResolutionDPI()).createBufferedImage(map);
if(image == null){
return false;
}
try {
final FileOutputStream out = new FileOutputStream(directoryName + File.separator + "image.png");
ImageIO.write(image, "png", out);
out.close();
return true;
}
catch (final IOException e1) {
LogUtils.severe(e1);
return false;
}
}
/**
* @param create_image
*/
private String getAreaCode(final boolean create_image) {
String areaCode = "";
if (create_image) {
areaCode = Controller.getCurrentController().getMapViewManager().createHtmlMap();
}
return areaCode;
}
/**
* @param mode
* @throws IOException
*/
private String getMapXml(final Mode mode) throws IOException {
final StringWriter writer = new StringWriter();
final ModeController modeController = Controller.getCurrentModeController();
final Controller controller = modeController.getController();
final MapModel map = controller.getMap();
modeController.getMapController().getFilteredXml(map, writer, mode, Mode.EXPORT.equals(mode));
return writer.getBuffer().toString();
}
String getProperty(final String key) {
final String property = getProperty(key, null);
if (property == null)
return property;
Matcher r = propertyReferenceEpression.matcher(property);
r.reset();
boolean result = r.find();
if (result) {
StringBuffer sb = new StringBuffer();
do {
String propertyReference = r.group();
String propertyName = propertyReference.substring(2, propertyReference.length() - 1);
r.appendReplacement(sb, System.getProperty(propertyName, propertyReference));
result = r.find();
} while (result);
r.appendTail(sb);
return sb.toString();
}
return property;
}
String getProperty(final String key, final String value) {
return properties.getProperty(key, value);
}
public boolean isTransformResultWithoutError() {
return mTransformResultWithoutError;
}
/**
* @param saveFile
*/
public void export(final MapModel map, final File saveFile) {
try {
mTransformResultWithoutError = true;
final boolean create_image = StringUtils.equals(getProperty("create_html_linked_image"), "true");
final String areaCode = getAreaCode(create_image);
final String xsltFileName = getProperty("xslt_file");
final Mode mode = Mode.valueOf(getProperty("mode", Mode.EXPORT.name()));
String[] parameters = getProperty("set_properties", "").split(",\\s*");
boolean success = transformMapWithXslt(xsltFileName, saveFile, areaCode, mode, parameters);
if (!success) {
JOptionPane.showMessageDialog(UITools.getFrame(), getProperty("error_applying_template"), "Freeplane",
JOptionPane.ERROR_MESSAGE);
return;
}
if (success && StringUtils.equals(getProperty("create_dir"), "true")) {
final String directoryName = saveFile.getAbsolutePath() + "_files";
success = FileUtils.createDirectory(directoryName);
if (success) {
final String files = getProperty("files_to_copy");
final String filePrefix = getProperty("file_prefix");
copyFilesFromResourcesToDirectory(directoryName, filePrefix, files);
}
if (success && StringUtils.equals(getProperty("copy_icons"), "true")) {
success = copyIcons(map, directoryName);
}
if (success && StringUtils.equals(getProperty("copy_map"), "true")) {
String copyМapХsltFile = getProperty("copy_map_xslt_file");
if (copyМapХsltFile != null)
success = transformMapWithXslt(copyМapХsltFile, new File(directoryName, "map.mm"), "", Mode.EXPORT, new String[]{});
else
success = copyMap(map, directoryName);
}
if (success && create_image) {
success = createImageFromMap(map, directoryName);
}
}
if (!success) {
JOptionPane.showMessageDialog(UITools.getFrame(), getProperty("error_creating_directory"), "Freeplane",
JOptionPane.ERROR_MESSAGE);
return;
}
if (StringUtils.equals(getProperty("load_file"), "true")) {
Controller.getCurrentController().getViewController().openDocument(Compat.fileToUrl(saveFile));
}
}
catch (final Exception e) {
LogUtils.severe(e);
mTransformResultWithoutError = false;
}
}
private boolean transformMapWithXslt(final String xsltFileName, final File saveFile, final String areaCode,
final Mode mode, String[] parameters) throws IOException,
TransformerFactoryConfigurationError {
final String map = getMapXml(mode);
final StringReader reader = new StringReader(map);
ResourceController resourceController = ResourceController.getResourceController();
final URL xsltUrl = resourceController.getResource(xsltFileName);
if (xsltUrl == null) {
LogUtils.severe("Can't find " + xsltFileName + " as resource.");
throw new IllegalArgumentException("Can't find " + xsltFileName + " as resource.");
}
final InputStream xsltFile = new BufferedInputStream(xsltUrl.openStream());
final Source xsltSource = new StreamSource(xsltFile);
final Result result = new StreamResult(saveFile);
try {
final TransformerFactory transFact = TransformerFactory.newInstance();
final Transformer trans = transFact.newTransformer(xsltSource);
trans.setParameter("destination_dir", saveFile.getName() + "_files/");
trans.setParameter("area_code", areaCode);
trans.setParameter("folding_type", resourceController.getProperty(
"html_export_folding"));
StringBuilder sb = new StringBuilder();
for(String p : parameters){
String value = resourceController.getProperty(p, null);
if(value != null && ! value.equals(resourceController.getDefaultProperty(p))){
sb.append(p);
sb.append('=');
sb.append(value);
sb.append("$$$");
}
}
trans.setParameter("propertyList", sb.toString());
trans.transform(new StreamSource(reader), result);
}
catch (final Exception e) {
LogUtils.warn(e);
return false;
}
finally {
FileUtils.silentlyClose(xsltFile);
}
return true;
}
public FileFilter getFileFilter() {
return new ExampleFileFilter(getProperty("file_type"), TextUtils.getText(name + ".text"));
}
}