/* ****************************************************************************** * Copyright (c) 2006-2012 XMind Ltd. and others. * * This file is a part of XMind 3. XMind releases 3 and * above are dual-licensed under the Eclipse Public License (EPL), * which is available at http://www.eclipse.org/legal/epl-v10.html * and the GNU Lesser General Public License (LGPL), * which is available at http://www.gnu.org/licenses/lgpl.html * See http://www.xmind.net/license.html for details. * * Contributors: * XMind Ltd. - initial API and implementation *******************************************************************************/ package org.xmind.ui.internal.wizards; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.internal.DPIUtil; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xmind.core.CoreException; import org.xmind.core.IFileEntry; import org.xmind.core.IImage; import org.xmind.core.INotes; import org.xmind.core.INotesContent; import org.xmind.core.ISheet; import org.xmind.core.ISummary; import org.xmind.core.ITopic; import org.xmind.core.internal.dom.DOMConstants; import org.xmind.core.marker.IMarker; import org.xmind.core.marker.IMarkerRef; import org.xmind.core.marker.IMarkerResource; import org.xmind.core.marker.IMarkerVariation; import org.xmind.core.style.IStyle; import org.xmind.core.util.DOMUtils; import org.xmind.core.util.FileUtils; import org.xmind.core.util.HyperlinkUtils; import org.xmind.core.util.Property; import org.xmind.ui.mindmap.MindMapImageExporter; import org.xmind.ui.util.ImageFormat; import org.xmind.ui.util.MindMapUtils; import org.xmind.ui.wizards.ExportContants; import org.xmind.ui.wizards.ExportUtils; import org.xmind.ui.wizards.Exporter; import org.xmind.ui.wizards.IExportPart; import org.xmind.ui.wizards.RelationshipDescription; public class HtmlExporter extends Exporter { private static class TitlePart extends HtmlExportPart { private final int level; private static final String SPACE = "\u00A0"; //$NON-NLS-1$ public TitlePart(HtmlExporter exporter, ITopic topic, int level) { super(exporter, topic); this.level = level; } protected Node createNode() { ITopic topic = (ITopic) getElement(); String tag = HtmlConstants.TAGS_H[Math .min(HtmlConstants.TAGS_H.length - 1, level)]; Element ele = createDOMElement(tag); boolean isRoot = isCentralTopic(topic); ele.setAttribute(HtmlConstants.ATT_CLASS, isRoot ? "root" : "topic"); //$NON-NLS-1$ //$NON-NLS-2$ if (isRoot) { ele.setAttribute(HtmlConstants.ATT_ALIGN, HtmlConstants.CENTER); } writeStyle(ele, topic); String num = ExportUtils.getNumberingText(topic, getExporter().getCentralTopic()); if (num != null) { ele.appendChild(createText(num)); ele.appendChild(createText(" ")); //$NON-NLS-1$ } String title = getLeftIndent() + topic.getTitleText(); Element titleAnchor = createDOMElement(HtmlConstants.TAG_A); titleAnchor.setAttribute(HtmlConstants.ATT_NAME, topic.getId()); String hyperlink = topic.getHyperlink(); if (HyperlinkUtils.isAttachmentURL(hyperlink) && !isLinkToWeb(hyperlink)) { if (getExporter() .getBoolean(ExportContants.INCLUDE_ATTACHMENT)) { hyperlink = getExporter().createFilePath(hyperlink, title); } else { hyperlink = null; } } else { if (!getExporter() .getBoolean(ExportContants.INCLUDE_HYPERLINK)) { hyperlink = null; } else if (hyperlink != null && hyperlink.startsWith("xmind:")) { //$NON-NLS-1$ hyperlink = hyperlink.substring(6); } else if (isLinkToWeb(hyperlink) && !hyperlink.startsWith("http:") //$NON-NLS-1$ && !hyperlink.startsWith("https:")) { //$NON-NLS-1$ hyperlink = "http://" + hyperlink; //$NON-NLS-1$ } } if (hyperlink != null) { titleAnchor.setAttribute(HtmlConstants.ATT_HREF, hyperlink); } titleAnchor.appendChild(createText(title)); ele.appendChild(titleAnchor); return ele; } private String getLeftIndent() { StringBuffer sb = new StringBuffer(); for (int i = 1; i < level; i++) sb.append(SPACE); return sb.toString(); } @SuppressWarnings("nls") private boolean isLinkToWeb(String hyperlink) { if (hyperlink == null) return false; if (hyperlink.contains("www.") || hyperlink.contains(".com") || hyperlink.contains(".cn") || hyperlink.contains(".org") || hyperlink.contains(".cc") || hyperlink.contains(".net")) { return true; } return false; } } private static class OverviewPart extends HtmlExportPart { private static final ImageFormat FORMAT = ImageFormat.JPEG; public OverviewPart(HtmlExporter exporter, ITopic topic) { super(exporter, topic); } protected Node createNode() { ITopic topic = (ITopic) getElement(); boolean root = isCentralTopic(topic); String path = getExporter().createOverview(topic, FORMAT); Element div = createDOMElement(HtmlConstants.TAG_DIV); div.setAttribute(HtmlConstants.ATT_CLASS, root ? "globalOverview" : "overview"); //$NON-NLS-1$ //$NON-NLS-2$ if (root) { div.setAttribute(HtmlConstants.ATT_ALIGN, HtmlConstants.CENTER); } Element img = createDOMElement(HtmlConstants.TAG_IMG); img.setAttribute(HtmlConstants.ATT_SRC, path); div.appendChild(img); return div; } } private static class TagsPart extends HtmlExportPart { private Set<IMarkerRef> markers; private Set<String> labels; public TagsPart(HtmlExporter exporter, ITopic topic, Set<IMarkerRef> markers, Set<String> labels) { super(exporter, topic); this.markers = markers; this.labels = labels; } protected Node createNode() { Element ele = createDOMElement(HtmlConstants.TAG_P); ele.setAttribute(HtmlConstants.ATT_CLASS, "labelsAndMarkers"); //$NON-NLS-1$ ITopic topic = (ITopic) getElement(); boolean isRoot = isCentralTopic(topic); if (isRoot) { ele.setAttribute(HtmlConstants.ATT_ALIGN, HtmlConstants.CENTER); } boolean hasMarkers = false; boolean hasLabels = labels != null; if (markers != null) { Iterator<IMarkerRef> markerIt = markers.iterator(); while (markerIt.hasNext()) { IMarkerRef m = markerIt.next(); String markerId = m.getMarkerId(); String path = getExporter().createMarkerPath(markerId); if (path != null) { hasMarkers = true; Element img = createDOMElement(HtmlConstants.TAG_IMG); img.setAttribute(HtmlConstants.ATT_CLASS, "marker"); //$NON-NLS-1$ img.setAttribute(HtmlConstants.ATT_SRC, path); ele.appendChild(img); if (markerIt.hasNext()) { ele.appendChild(createText(" ")); //$NON-NLS-1$ } } } } if (hasMarkers && hasLabels && !isRoot) { ele.appendChild(createText(COMMA)); } if (hasLabels) { Iterator<String> labelIt = labels.iterator(); while (labelIt.hasNext()) { String label = labelIt.next(); Element span = createDOMElement(HtmlConstants.TAG_SPAN); span.setAttribute(HtmlConstants.ATT_CLASS, "label"); //$NON-NLS-1$ span.appendChild(createText(label)); ele.appendChild(span); if (labelIt.hasNext()) { ele.appendChild(createText(COMMA)); } } } return ele; } } private static class ImagePart extends HtmlExportPart { public ImagePart(HtmlExporter exporter, IImage element) { super(exporter, element); } protected Node createNode() { IImage image = (IImage) getElement(); Element ele = createDOMElement(HtmlConstants.TAG_P); ele.setAttribute(HtmlConstants.ATT_CLASS, "topicImage"); //$NON-NLS-1$ if (isCentralTopic(image.getParent())) { ele.setAttribute(HtmlConstants.ATT_ALIGN, HtmlConstants.CENTER); } String url = image.getSource(); if (HyperlinkUtils.isAttachmentURL(url)) { url = getExporter().createFilePath(url, null); } if (url != null) { Element img = createDOMElement(HtmlConstants.TAG_IMG); img.setAttribute(HtmlConstants.ATT_SRC, url); int width = image.getWidth(); if (width != IImage.UNSPECIFIED) { img.setAttribute(HtmlConstants.ATT_WIDTH, String.valueOf(width)); } int height = image.getHeight(); if (height != IImage.UNSPECIFIED) { img.setAttribute(HtmlConstants.ATT_HEIGHT, String.valueOf(height)); } ele.appendChild(img); } return ele; } } private static class NotesPart extends HtmlExportPart { public NotesPart(HtmlExporter exporter, INotesContent element) { super(exporter, element); } protected Node createNode() { Element ele = createDOMElement(HtmlConstants.TAG_DIV); ele.setAttribute(HtmlConstants.ATT_CLASS, "notesContainer"); //$NON-NLS-1$ INotesContent content = (INotesContent) getElement(); Element contentEle = (Element) content.getAdapter(Element.class); if (contentEle != null) { String format = content.getFormat(); if (INotes.PLAIN.equals(format)) { appendPlainNotes(ele, content, contentEle); } else { appendHtmlNotes(ele, content, contentEle); } } return ele; } private void appendPlainNotes(Element ele, INotesContent content, Element contentEle) { String textContent = contentEle.getTextContent(); String[] lines = textContent.split("\\r\\n|\\r|\\n"); //$NON-NLS-1$ for (String line : lines) { Element p = createDOMElement(HtmlConstants.TAG_P); p.setTextContent(line); ele.appendChild(p); } } private void appendHtmlNotes(Element ele, INotesContent content, Element contentEle) { Document doc = ele.getOwnerDocument(); NodeList children = contentEle.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node n = children.item(i); n = importNode(doc, n); ele.appendChild(n); } } private Node importNode(Document doc, Node n) { if (n instanceof Element) { return importElement(doc, (Element) n); } return doc.importNode(n, true); } private Element importElement(Document doc, Element e) { String tag = DOMUtils.getLocalName(e.getTagName()); Element e2 = doc.createElement(tag); NamedNodeMap attrs = e.getAttributes(); for (int i = 0; i < attrs.getLength(); i++) { Node item = attrs.item(i); String name = item.getNodeName(); String value = item.getNodeValue(); if (DOMConstants.ATTR_STYLE_ID.equals(name)) { name = HtmlConstants.ATT_CLASS; value = getExporter().addStyle(value); } else if (DOMConstants.ATTR_SRC.equals(name)) { if (HyperlinkUtils.isAttachmentURL(value)) { value = getExporter().createFilePath(value, null); } } e2.setAttribute(DOMUtils.getLocalName(name), value); } NodeList children = e.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node c = children.item(i); Node c2 = importNode(doc, c); e2.appendChild(c2); } return e2; } } private static class RelationshipsPart extends HtmlExportPart { private List<RelationshipDescription> relationships; public RelationshipsPart(HtmlExporter exporter, ITopic element, List<RelationshipDescription> relationships) { super(exporter, element); this.relationships = relationships; } protected Node createNode() { Element ele = createDOMElement(HtmlConstants.TAG_P); ele.setAttribute(HtmlConstants.ATT_CLASS, "relationships"); //$NON-NLS-1$ ele.appendChild(createText(SEE_ALSO)); ele.appendChild(createText(" ")); //$NON-NLS-1$ Iterator<RelationshipDescription> relIt = relationships.iterator(); while (relIt.hasNext()) { RelationshipDescription rel = relIt.next(); Element anchor = createDOMElement(HtmlConstants.TAG_A); anchor.setAttribute(HtmlConstants.ATT_HREF, "#" + rel.target.getId()); //$NON-NLS-1$ anchor.setTextContent(rel.description); ele.appendChild(anchor); if (relIt.hasNext()) { ele.appendChild(createText(COMMA)); } } return ele; } } private static class SummaryPart extends HtmlExportPart { public SummaryPart(HtmlExporter exporter, ISummary summary) { super(exporter, summary); } protected Node createNode() { Element ele = createDOMElement(HtmlConstants.TAG_P); ele.setAttribute(HtmlConstants.ATT_CLASS, "summary"); //$NON-NLS-1$ ele.appendChild(createText("(")); //$NON-NLS-1$ ISummary summary = (ISummary) getElement(); List<ITopic> topics = summary.getEnclosingTopics(); Iterator<ITopic> topicIt = topics.iterator(); while (topicIt.hasNext()) { ITopic topic = topicIt.next(); Element anchor = createDOMElement(HtmlConstants.TAG_A); anchor.setAttribute(HtmlConstants.ATT_HREF, "#" + topic.getId()); //$NON-NLS-1$ anchor.setTextContent(topic.getTitleText()); ele.appendChild(anchor); if (topicIt.hasNext()) { ele.appendChild(createText(COMMA)); } } ele.appendChild(createText(")")); //$NON-NLS-1$ return ele; } } // private static class BoundariesPart extends HtmlExportPart { // // public BoundariesPart(HtmlExporter exporter, ITopic topic) { // super(exporter, topic); // } // // protected Node createNode() { // Element ele = createDOMElement(HtmlConstants.TAG_P); // ele.setAttribute(HtmlConstants.ATT_CLASS, "boundaries"); //$NON-NLS-1$ // ele.appendChild(createText(WizardMessages.Export_Groups)); // return ele; // } // // public Node getContentNode(HtmlExportPart child) { // if (child instanceof BoundaryPart) { // return DOMUtils.ensureChildElement(getNode(), // HtmlConstants.TAG_UL); // } // return super.getContentNode(child); // } // // } // // private static class BoundaryPart extends HtmlExportPart { // // private List<ITopic> topics; // // public BoundaryPart(HtmlExporter exporter, IBoundary boundary, // List<ITopic> topics) { // super(exporter, boundary); // this.topics = topics; // } // // protected Node createNode() { // Element ele = createDOMElement(HtmlConstants.TAG_LI); // ele.setAttribute(HtmlConstants.ATT_CLASS, "boundary"); //$NON-NLS-1$ // // IBoundary boundary = (IBoundary) getElement(); // // Element boundaryAnchor = createDOMElement(HtmlConstants.TAG_A); // boundaryAnchor.setAttribute(HtmlConstants.ATT_NAME, boundary // .getId()); // boundaryAnchor.appendChild(createText(boundary.getTitleText())); // ele.appendChild(boundaryAnchor); // // ele.appendChild(createText(": ")); //$NON-NLS-1$ // // Iterator<ITopic> topicIt = topics.iterator(); // while (topicIt.hasNext()) { // ITopic topic = topicIt.next(); // Element topicAnchor = createDOMElement(HtmlConstants.TAG_A); // topicAnchor.setAttribute(HtmlConstants.ATT_HREF, // "#" + topic.getId()); //$NON-NLS-1$ // topicAnchor.appendChild(createText(topic.getTitleText())); // ele.appendChild(topicAnchor); // if (topicIt.hasNext()) { // ele.appendChild(createText(COMMA)); // } // } // return ele; // } // // } private static final Object NULL = new Object(); private static final String IMAGES = "images"; //$NON-NLS-1$ private static final String FILES = "_files"; //$NON-NLS-1$ private String title; private String targetPath; private String filesPath; private String imagesPath; private String relativeFilesPath; private String relativeImagesPath; private Document document; private Element headEle; private Element bodyEle; private Map<String, List<String>> usedStyles = null; private Map<String, IStyle> styleMap = null; private Map<String, String> styleIdMap = null; private Map<String, Object> files = null; private Map<String, Object> markerPaths = null; public HtmlExporter(ISheet sheet, ITopic centralTopic, String targetPath, String title) { super(sheet, centralTopic); this.targetPath = targetPath; this.title = title; } public void init() { appendTopic(getCentralTopic(), 0, null); } private void appendTopic(ITopic topic, int level, HtmlExportPart parent) { TitlePart topicPart = new TitlePart(this, topic, level); topicPart.setParent(parent); append(topicPart); appendTopicContent(topic, level, parent); } private void appendTopicContent(ITopic topic, int level, HtmlExportPart parent) { Set<IMarkerRef> markers = topic.getMarkerRefs(); Set<String> labels = topic.getLabels(); boolean hasMarker = getBoolean(ExportContants.INCLUDE_MARKERS) && !markers.isEmpty(); boolean hasLabel = getBoolean(ExportContants.INCLUDE_LABELS) && !labels.isEmpty(); if (hasMarker || hasLabel) { TagsPart tags = new TagsPart(this, topic, hasMarker ? markers : null, hasLabel ? labels : null); tags.setParent(parent); append(tags); } if (hasOverview(topic)) { OverviewPart overview = new OverviewPart(this, topic); overview.setParent(parent); append(overview); } if (getBoolean(ExportContants.INCLUDE_IMAGE)) { IImage image = topic.getImage(); if (image.getSource() != null) { ImagePart imagePart = new ImagePart(this, image); imagePart.setParent(parent); append(imagePart); } } if (getBoolean(ExportContants.INCLUDE_NOTES)) { INotesContent content = topic.getNotes().getContent(INotes.HTML); if (content == null) content = topic.getNotes().getContent(INotes.PLAIN); if (content != null) { NotesPart notesPart = new NotesPart(this, content); notesPart.setParent(parent); append(notesPart); } } if (getBoolean(ExportContants.INCLUDE_RELATIONSHIPS)) { List<RelationshipDescription> relationships = ExportUtils .getRelationships(topic, getRelationships()); if (!relationships.isEmpty()) { RelationshipsPart relsPart = new RelationshipsPart(this, topic, relationships); relsPart.setParent(parent); append(relsPart); } } // List<IBoundary> bs = null; // List<List<ITopic>> ts = null; // Collection<IBoundary> boundaries = topic.getBoundaries(); // if (!boundaries.isEmpty()) { // for (IBoundary boundary : boundaries) { // if (!boundary.isOverall()) { // List<ITopic> topics = boundary.getEnclosingTopics(); // if (!topics.isEmpty()) { // if (bs == null) // bs = new ArrayList<IBoundary>(); // bs.add(boundary); // if (ts == null) // ts = new ArrayList<List<ITopic>>(); // ts.add(topics); // } // } // } // } // // for (ITopic child : topic.getAllChildren()) { // for (IBoundary b : child.getBoundaries()) { // if (b.isOverall()) { // if (bs == null) // bs = new ArrayList<IBoundary>(); // bs.add(b); // if (ts == null) // ts = new ArrayList<List<ITopic>>(); // ts.add(Arrays.asList(child)); // break; // } // } // } // // if (bs != null && ts != null) { // BoundariesPart boundariesPart = new BoundariesPart(this, topic); // boundariesPart.setParent(parent); // append(boundariesPart); // // Iterator<IBoundary> bsIt = bs.iterator(); // Iterator<List<ITopic>> tsIt = ts.iterator(); // while (bsIt.hasNext() && tsIt.hasNext()) { // IBoundary boundary = bsIt.next(); // List<ITopic> topics = tsIt.next(); // BoundaryPart boundaryPart = new BoundaryPart(this, boundary, // topics); // boundaryPart.setParent(boundariesPart); // append(boundaryPart); // } // } int nextLevel = level + 1; for (ITopic sub : topic.getChildren(ITopic.ATTACHED)) { appendTopic(sub, nextLevel, parent); } if (getBoolean(ExportContants.INCLUDE_SUMMARIES)) { for (ISummary summary : topic.getSummaries()) { appendSummary(summary, topic, nextLevel, parent); } } if (getBoolean(ExportContants.INCLUDE_FLOATING_TOPICS)) { for (ITopic sub : topic.getChildren(ITopic.DETACHED)) { appendTopic(sub, nextLevel, parent); } } } private void appendSummary(ISummary summary, ITopic topic, int nextLevel, HtmlExportPart parent) { ITopic summaryTopic = summary.getTopic(); if (summaryTopic == null) return; TitlePart topicPart = new TitlePart(this, summaryTopic, nextLevel); topicPart.setParent(parent); append(topicPart); SummaryPart summaryPart = new SummaryPart(this, summary); summaryPart.setParent(parent); append(summaryPart); appendTopicContent(summaryTopic, nextLevel, parent); } public String getTargetPath() { return targetPath; } public String getFilesPath() { if (filesPath == null) { filesPath = createFilesPath(); } return filesPath; } private String createFilesPath() { File f = new File(getTargetPath()); String name = f.getName(); String parent = f.getParent(); int index = name.lastIndexOf('.'); if (index >= 0) { name = name.substring(0, index) + FILES; } else { name += FILES; } return new File(parent, name).getAbsolutePath(); } public String getImagesPath() { if (imagesPath == null) { imagesPath = createImagesPath(); } return imagesPath; } private String createImagesPath() { String path = getFilesPath(); return new File(path, IMAGES).getAbsolutePath(); } public String getRelativeFilesPath() { if (relativeFilesPath == null) { relativeFilesPath = new File(getFilesPath()).getName(); } return relativeFilesPath; } public String getRelativeImagesPath() { if (relativeImagesPath == null) { relativeImagesPath = connectPath(getRelativeFilesPath(), IMAGES); } return relativeImagesPath; } public String connectPath(String parent, String child) { return parent + "/" + child; //$NON-NLS-1$ } public String newPath(String parent, String name, String ext) { File f = new File(parent, name + ext); String newName; int i = 1; while (f.exists()) { i++; newName = name + " " + i; //$NON-NLS-1$ f = new File(parent, newName + ext); } return f.getAbsolutePath(); } public Document getDocument() { if (document == null) document = createDocument(); return document; } protected Element getHeadElement() { if (headEle == null) { headEle = DOMUtils.ensureChildElement( getDocument().getDocumentElement(), HtmlConstants.TAG_HEAD); } return headEle; } private Document createDocument() { Document doc = DOMUtils.createDocument(); Element ele = DOMUtils.createElement(doc, HtmlConstants.TAG_HTML); Element head = DOMUtils.createElement(ele, HtmlConstants.TAG_HEAD); createMeta(head, "Content-Type", "text/html; charset=utf-8"); //$NON-NLS-1$ //$NON-NLS-2$ createMeta(head, "Content-Style-Type", "text/css"); //$NON-NLS-1$ //$NON-NLS-2$ if (title != null) { Element titleEle = DOMUtils.createElement(head, HtmlConstants.TAG_TITLE); titleEle.setTextContent(title); } return doc; } private Element createMeta(Element head, String httpEquiv, String content) { Element meta = DOMUtils.createElement(head, HtmlConstants.TAG_META); meta.setAttribute("http-equiv", httpEquiv); //$NON-NLS-1$ meta.setAttribute("content", content); //$NON-NLS-1$ return meta; } protected Node getBodyNode() { if (bodyEle == null) { bodyEle = createBodyNode(); } return bodyEle; } private Element createBodyNode() { return DOMUtils.createElement(getDocument().getDocumentElement(), HtmlConstants.TAG_BODY); } public String addStyle(String styleId) { if (styleId == null) return null; String cachedStyleId = styleIdMap == null ? null : styleIdMap.get(styleId); if (cachedStyleId != null) return cachedStyleId; IStyle style = getStyle(styleId); if (style == null) return null; String type = style.getType(); if (!isStyleInteresting(style, type)) return null; if (usedStyles == null) usedStyles = new HashMap<String, List<String>>(); List<String> list = usedStyles.get(type); if (list == null) { list = new ArrayList<String>(); usedStyles.put(type, list); } String newStyleId = newStyleId(type, list.size() + 1); list.add(newStyleId); if (styleIdMap == null) styleIdMap = new HashMap<String, String>(); styleIdMap.put(styleId, newStyleId); if (styleMap == null) styleMap = new HashMap<String, IStyle>(); styleMap.put(newStyleId, style); return newStyleId; } private String newStyleId(String type, int index) { if (IStyle.PARAGRAPH.equals(type)) return "p" + index; //$NON-NLS-1$ else /* if (IStyle.TEXT.equals(type)) */ return "s" + index; //$NON-NLS-1$ } private boolean isStyleInteresting(IStyle style, String type) { return IStyle.PARAGRAPH.equals(type) || IStyle.TEXT.equals(type); } protected void write(IProgressMonitor monitor, IExportPart part) throws InvocationTargetException, InterruptedException { HtmlExportPart child = (HtmlExportPart) part; HtmlExportPart parent = child.getParent(); if (parent != null) { child.addToParent(parent); } else { getBodyNode().appendChild(child.getNode()); } } public void end() throws InvocationTargetException { createStyles(); try { FileOutputStream out = new FileOutputStream(targetPath); try { DOMUtils.save(getDocument(), out, true); } catch (IOException e) { throw new InvocationTargetException(e); } catch (CoreException e) { throw new InvocationTargetException(e); } } catch (FileNotFoundException e) { throw new InvocationTargetException(e); } finally { super.end(); } } private void createStyles() { if (usedStyles == null || usedStyles.isEmpty()) return; StringBuilder sb = new StringBuilder(); sb.append(HtmlConstants.LINE_SEP); List<String> ps = usedStyles.get(IStyle.PARAGRAPH); if (ps != null && !ps.isEmpty()) { createStyles(HtmlConstants.TAG_P, ps, sb); } List<String> ts = usedStyles.get(IStyle.TEXT); if (ts != null && !ts.isEmpty()) { createStyles(HtmlConstants.TAG_SPAN, ts, sb); } String content = sb.toString(); Element styleEle = DOMUtils.ensureChildElement(getHeadElement(), HtmlConstants.TAG_STYLE); styleEle.setAttribute(HtmlConstants.ATT_TYPE, "text/css"); //$NON-NLS-1$ styleEle.setTextContent(content); } private void createStyles(String tag, List<String> styleIds, StringBuilder sb) { for (String styleId : styleIds) { IStyle style = styleMap == null ? null : styleMap.get(styleId); if (style != null) { createStyle(tag, styleId, style, sb); } } } private void createStyle(String tag, String styleId, IStyle style, StringBuilder sb) { sb.append(tag); sb.append('.'); sb.append(styleId); sb.append(' '); sb.append('{'); Iterator<Property> properties = style.properties(); while (properties.hasNext()) { Property property = properties.next(); String name = DOMUtils.getLocalName(property.key); String value = property.value; sb.append(name); sb.append(':'); sb.append(' '); sb.append(value); if (properties.hasNext()) { sb.append(';'); sb.append(' '); } } sb.append('}'); sb.append(HtmlConstants.LINE_SEP); } public String createOverview(ITopic topic, ImageFormat format) { String title = topic.getTitleText(); String path = newPath(getImagesPath(), MindMapUtils.trimFileName(title), format.getExtensions().get(0)); FileUtils.ensureFileParent(new File(path)); String relativePath = connectPath(getRelativeImagesPath(), new File(path).getName()); MindMapImageExporter exporter = createOverviewExporter(topic); exporter.setTargetFile(new File(path)); exporter.export(); // Display display = getDisplay(); // Shell shell = getShell(); // MindMapPreviewBuilder overviewBuilder = createOverviewBuilder(topic); // if (overviewBuilder != null) { // try { // if (shell != null) { // overviewBuilder.build(shell, path); // } else { // overviewBuilder.build(display, path); // } // } catch (IOException e) { // String message = NLS // .bind(Message_FailedToCreateOverview, title); // log(e, message); // } // } return relativePath; } public String createFilePath(String hyperlink, String suggestedName) { Object cache = files == null ? null : files.get(hyperlink); if (cache == NULL) return null; if (cache instanceof String) return (String) cache; String entryPath = HyperlinkUtils.toAttachmentPath(hyperlink); IFileEntry entry = getFileEntry(entryPath); if (entry == null) { return cacheFile(hyperlink, NULL); } if (suggestedName == null) { suggestedName = FileUtils.getFileName(entryPath); } String name = FileUtils.getNoExtensionFileName(suggestedName); String ext = FileUtils.getExtension(suggestedName); String path = newPath(getFilesPath(), name, ext); InputStream in = entry.getInputStream(); if (in != null) { FileUtils.ensureFileParent(new File(path)); try { FileUtils.transfer(in, new FileOutputStream(path), true); } catch (IOException e) { String message = NLS.bind(Message_FailedToCopyAttachment, suggestedName); log(e, message); } } String fileName = new File(path).getName(); String relativePath = connectPath(getRelativeFilesPath(), fileName); return cacheFile(hyperlink, relativePath); } private String cacheFile(String hyperlink, Object path) { if (files == null) files = new HashMap<String, Object>(); files.put(hyperlink, path); return path == NULL ? null : (String) path; } public String createMarkerPath(String markerId) { if (markerId == null) return null; Object cache = markerPaths == null ? null : markerPaths.get(markerId); if (cache == NULL) return null; if (cache instanceof String) return (String) cache; IMarker marker = getMarker(markerId); if (marker == null) return cacheMarker(markerId, NULL); IMarkerResource resource = marker.getResource(); if (resource == null) return cacheMarker(markerId, NULL); String name = FileUtils.getFileName(resource.getPath()); String ext = FileUtils.getExtension(name); name = FileUtils.getNoExtensionFileName(name); String path = newPath(getImagesPath(), name, ext); FileUtils.ensureFileParent(new File(path)); int zoom = DPIUtil.getDeviceZoom(); List<IMarkerVariation> variations = resource.getVariations(); InputStream in = null; try { if (variations.size() > 0) { in = resource.openInputStream( variations.get(variations.size() - 1), zoom); } else { in = resource.openInputStream(zoom); } } catch (IOException e) { e.printStackTrace(); } if (in != null) { try { FileUtils.transfer(in, new FileOutputStream(path), true); } catch (IOException e) { log(e, NLS.bind(Message_FailedToCopyMarker, markerId)); } } String fileName = new File(path).getName(); String relativePath = connectPath(getRelativeImagesPath(), fileName); return cacheMarker(markerId, relativePath); } private String cacheMarker(String markerId, Object path) { if (markerPaths == null) markerPaths = new HashMap<String, Object>(); markerPaths.put(markerId, path); return path == NULL ? null : (String) path; } }