/* ****************************************************************************** * 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 static org.xmind.core.internal.dom.DOMConstants.ATTR_LINE_TAPERED; import static org.xmind.core.internal.dom.DOMConstants.ATTR_MULTI_LINE_COLORS; import static org.xmind.core.internal.dom.DOMConstants.ATTR_STYLE_FAMILY; import static org.xmind.core.internal.dom.DOMConstants.ATTR_TYPE; import static org.xmind.core.internal.dom.DOMConstants.VAL_NONE; import static org.xmind.core.internal.dom.DOMConstants.VAL_TAPERED; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.xml.parsers.ParserConfigurationException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Text; import org.xmind.core.CoreException; import org.xmind.core.IBoundary; import org.xmind.core.IControlPoint; import org.xmind.core.IFileEntry; import org.xmind.core.IHtmlNotesContent; import org.xmind.core.IImage; import org.xmind.core.IImageSpan; import org.xmind.core.ILegend; import org.xmind.core.IManifest; import org.xmind.core.INotes; import org.xmind.core.INumbering; import org.xmind.core.IParagraph; import org.xmind.core.IPlainNotesContent; import org.xmind.core.IPositioned; import org.xmind.core.IRelationship; import org.xmind.core.ISheet; import org.xmind.core.ISpan; import org.xmind.core.ITextSpan; import org.xmind.core.ITitled; import org.xmind.core.ITopic; import org.xmind.core.IWorkbook; import org.xmind.core.internal.zip.ArchiveConstants; import org.xmind.core.marker.IMarker; import org.xmind.core.marker.IMarkerGroup; import org.xmind.core.marker.IMarkerRef; import org.xmind.core.marker.IMarkerSheet; import org.xmind.core.style.IStyleSheet; import org.xmind.core.style.IStyled; import org.xmind.core.util.DOMUtils; import org.xmind.core.util.FileUtils; import org.xmind.core.util.HyperlinkUtils; import org.xmind.core.util.Point; /** * @author frankshaka * */ public class XMind2008Exporter { private IWorkbook sourceWorkbook; private String targetPath; private IProgressMonitor monitor; private Document contentDocument; private Document styleDocument; private Document metaDocument; private Document manifestDocument; // /** // * Marker path -> marker id // */ // private Map<String, String> attachmentMarkerPaths; /** * @param sheet * @param centralTopic */ public XMind2008Exporter(IWorkbook sourceWorkbook, String targetPath) { this.sourceWorkbook = sourceWorkbook; this.targetPath = targetPath; } /** * @return the monitor */ public IProgressMonitor getMonitor() { if (monitor == null) { monitor = new NullProgressMonitor(); } return monitor; } /** * @param monitor * the monitor to set */ public void setMonitor(IProgressMonitor monitor) { this.monitor = monitor; } /** * @return the sourceWorkbook */ public IWorkbook getSourceWorkbook() { return sourceWorkbook; } /** * @return the targetPath */ public String getTargetPath() { return targetPath; } public void export() throws InvocationTargetException, InterruptedException { saveContent(); saveStyles(); saveMeta(); saveManifest(); try { ZipOutputStream os = new ZipOutputStream(new FileOutputStream( getTargetPath())); try { os.putNextEntry(new ZipEntry(ArchiveConstants.CONTENT_XML)); save(os, contentDocument); os.putNextEntry(new ZipEntry(ArchiveConstants.STYLES_XML)); save(os, styleDocument); os.putNextEntry(new ZipEntry(ArchiveConstants.META_XML)); save(os, metaDocument); os.putNextEntry(new ZipEntry(ArchiveConstants.MANIFEST_XML)); save(os, manifestDocument); IManifest manifest = sourceWorkbook.getManifest(); for (IFileEntry entry : manifest.getFileEntries()) { if (!entry.isDirectory()) { String path = entry.getPath(); if (shouldCopyEntry(path)) { copyEntry(os, entry, path); } } } } finally { try { os.close(); } catch (IOException e) { } } } catch (IOException e) { throw new InvocationTargetException(e); } } /** * @param os * @param entry * @param path */ private void copyEntry(ZipOutputStream os, IFileEntry entry, String path) throws InvocationTargetException { InputStream is = entry.getInputStream(); if (is == null) return; // String attachmentMarkerId = getAttachmentMarkerId(path); // if (attachmentMarkerId != null) { // path = "Pictures/" + attachmentMarkerId + FileUtils.getExtension(path); //$NON-NLS-1$ // } else if (path.startsWith(ArchiveConstants.PATH_ATTACHMENTS)) { path = upperFirst(path); } try { os.putNextEntry(new ZipEntry(path)); FileUtils.transfer(is, os, false); } catch (IOException e) { throw new InvocationTargetException(e); } finally { try { is.close(); } catch (IOException e) { } } } // private String getAttachmentMarkerId(String path) { // if (attachmentMarkerPaths != null) { // for (Entry<String, String> en : attachmentMarkerPaths.entrySet()) { // String p = en.getKey(); // if (path.contains(p) || p.contains(path)) { // return en.getValue(); // } // } // } // return null; // } /** * @param path * @return */ private boolean shouldCopyEntry(String path) { return !ArchiveConstants.CONTENT_XML.equals(path) && !ArchiveConstants.STYLES_XML.equals(path) && !ArchiveConstants.META_XML.equals(path) && !ArchiveConstants.MANIFEST_XML.equals(path); } /** * */ private void saveManifest() throws InvocationTargetException { manifestDocument = createDocument(); Element docEle; Document sourceDoc = (Document) sourceWorkbook.getManifest() .getAdapter(Document.class); if (sourceDoc != null) { docEle = (Element) manifestDocument.importNode(sourceDoc .getDocumentElement(), true); downgradeManifest(docEle); manifestDocument.appendChild(docEle); } else { docEle = DOMUtils.createElement(manifestDocument, "manifest"); //$NON-NLS-1$ } docEle.setAttribute("xmlns", "urn:xmind:xmap:xmlns:manifest:1.0"); //$NON-NLS-1$ //$NON-NLS-2$ } /** * @param docEle */ private void downgradeManifest(Element element) { if ("file-entry".equals(element.getTagName())) { //$NON-NLS-1$ String path = element.getAttribute("full-path"); //$NON-NLS-1$ // String attachmentMarkerId = getAttachmentMarkerId(path); // if (attachmentMarkerId != null) { // path = "Pictures/" + attachmentMarkerId + FileUtils.getExtension(path); //$NON-NLS-1$ // } else if (path.startsWith(ArchiveConstants.PATH_ATTACHMENTS)) { path = upperFirst(path); } element.setAttribute("full-path", path); //$NON-NLS-1$ } Iterator<Element> it = DOMUtils.childElementIter(element); while (it.hasNext()) { downgradeManifest(it.next()); } } /** * * @throws InvocationTargetException */ private void saveMeta() throws InvocationTargetException { metaDocument = createDocument(); Element docEle = DOMUtils.createElement(metaDocument, "xmap-meta"); //$NON-NLS-1$ docEle.setAttribute("xmlns", "urn:xmind:xmap:xmlns:meta:1.0"); //$NON-NLS-1$ //$NON-NLS-2$ docEle.setAttribute("version", "1.0"); //$NON-NLS-1$ //$NON-NLS-2$ } /** * @throws InvocationTargetException * */ private void saveStyles() throws InvocationTargetException { styleDocument = createDocument(); Element docEle = DOMUtils.createElement(styleDocument, "xmap-styles"); //$NON-NLS-1$ docEle.setAttribute("xmlns", "urn:xmind:xmap:xmlns:style:1.0"); //$NON-NLS-1$ //$NON-NLS-2$ docEle.setAttribute("xmlns:fo", "http://www.w3.org/1999/XSL/Format"); //$NON-NLS-1$ //$NON-NLS-2$ docEle.setAttribute("xmlns:svg", "http://www.w3.org/2000/svg"); //$NON-NLS-1$ //$NON-NLS-2$ docEle.setAttribute("version", "1.0"); //$NON-NLS-1$ //$NON-NLS-2$ docEle.setAttribute("version", "1.0"); //$NON-NLS-1$ //$NON-NLS-2$ IStyleSheet styleSheet = sourceWorkbook.getStyleSheet(); if (styleSheet.isEmpty()) return; saveStyleContent(docEle, styleSheet); } /** * @param docEle * @param styleSheet */ private void saveStyleContent(Element docEle, IStyleSheet styleSheet) { Document sourceDoc = (Document) styleSheet.getAdapter(Document.class); if (sourceDoc == null) return; Element sourceDocEle = sourceDoc.getDocumentElement(); Iterator<Element> it = DOMUtils.childElementIter(sourceDocEle); Document doc = docEle.getOwnerDocument(); while (it.hasNext()) { Element sourceEle = it.next(); Element targetEle = (Element) doc.importNode(sourceEle, true); downgradeStyles(targetEle); docEle.appendChild(targetEle); } } /** * @param element */ private void downgradeStyles(Element element) { downgradeStyle(element); Iterator<Element> it = DOMUtils.childElementIter(element); while (it.hasNext()) { downgradeStyles(it.next()); } } /** * @param element */ private void downgradeStyle(Element element) { NamedNodeMap attributes = element.getAttributes(); Map<String, String> added = null; for (int i = 0; i < attributes.getLength(); i++) { Attr attr = (Attr) attributes.item(i); String name = attr.getName(); String value = attr.getValue(); if (ATTR_TYPE.equals(name)) { attr.setValue(upperFirst(value)); } else if (ATTR_STYLE_FAMILY.equals(name)) { attr.setValue(upperFirst(value)); } else if (ATTR_MULTI_LINE_COLORS.equals(name)) { if (value != null && !VAL_NONE.equals(value)) { added = add(added, "rainbowcolor", "true"); //$NON-NLS-1$ //$NON-NLS-2$ } } else if (ATTR_LINE_TAPERED.equals(name)) { if (value.contains(VAL_TAPERED)) { added = add(added, "spinylines", "true"); //$NON-NLS-1$ //$NON-NLS-2$ } } // if ("floatingMainTopic".equals(value)) { //$NON-NLS-1$ // attr.setValue("floatingTopic"); //$NON-NLS-1$ // } else if (VAL_NONE.equals(value)) { attr.setValue("$none$"); //$NON-NLS-1$ } else if (HyperlinkUtils.isAttachmentURL(value)) { value = toAttachmentURL(value); attr.setValue(value); } } if (added != null) { for (Entry<String, String> e : added.entrySet()) { element.setAttribute(e.getKey(), e.getValue()); } } } private Map<String, String> add(Map<String, String> map, String key, String value) { if (map == null) map = new HashMap<String, String>(); map.put(key, value); return map; } /** * @param os * @param document * @throws CoreException */ private void save(OutputStream os, Document document) throws InvocationTargetException { try { DOMUtils.save(document, os, false); } catch (Exception e) { throw new InvocationTargetException(e); } } /** * */ private void saveContent() throws InvocationTargetException { contentDocument = createDocument(); Element docEle = DOMUtils .createElement(contentDocument, "xmap-content"); //$NON-NLS-1$ docEle.setAttribute("xmlns", "urn:xmind:xmap:xmlns:content:1.0"); //$NON-NLS-1$ //$NON-NLS-2$ docEle.setAttribute("xmlns:xhtml", "http://www.w3.org/1999/xhtml"); //$NON-NLS-1$ //$NON-NLS-2$ docEle.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink"); //$NON-NLS-1$ //$NON-NLS-2$ docEle.setAttribute("xmlns:fo", "http://www.w3.org/1999/XSL/Format"); //$NON-NLS-1$ //$NON-NLS-2$ docEle.setAttribute("xmlns:svg", "http://www.w3.org/2000/svg"); //$NON-NLS-1$ //$NON-NLS-2$ docEle.setAttribute("version", "1.0"); //$NON-NLS-1$ //$NON-NLS-2$ saveMaps(docEle); } /** * @param parentEle */ private void saveMaps(Element parentEle) { for (ISheet sheet : sourceWorkbook.getSheets()) { saveMap(parentEle, sheet); } } /** * @param parentEle * @param sheet */ private void saveMap(Element parentEle, ISheet sheet) { Element mapEle = DOMUtils.createElement(parentEle, "map"); //$NON-NLS-1$ DOMUtils.replaceId(mapEle, sheet.getId()); saveTheme(mapEle, sheet); saveTitle(mapEle, sheet); saveStyle(mapEle, sheet); saveRootTopic(mapEle, sheet); saveRelationships(mapEle, sheet.getRelationships()); saveLegend(mapEle, sheet.getLegend()); } /** * @param mapEle * @param sheet */ private void saveTheme(Element mapEle, ISheet sheet) { DOMUtils.setAttribute(mapEle, "theme", sheet.getThemeId()); //$NON-NLS-1$ } /** * @param mapEle * @param sheet */ private void saveRootTopic(Element mapEle, ISheet sheet) { Element rootTopicEle = DOMUtils.createElement(mapEle, "root-topic"); //$NON-NLS-1$ saveTopic(rootTopicEle, sheet.getRootTopic()); } /** * @param rootTopicEle * @param rootTopic */ private void saveTopic(Element topicEle, ITopic topic) { DOMUtils.replaceId(topicEle, topic.getId()); saveFolded(topicEle, topic); saveHyperlink(topicEle, topic); saveStructureClass(topicEle, topic); saveStyle(topicEle, topic); saveTitle(topicEle, topic); savePosition(topicEle, topic); saveImage(topicEle, topic); saveLabels(topicEle, topic); saveMarkers(topicEle, topic); saveNotes(topicEle, topic); saveNumbering(topicEle, topic); saveAttachedSubtopics(topicEle, topic.getChildren(ITopic.ATTACHED)); saveDetachedSubtopics(topicEle, topic.getChildren(ITopic.DETACHED)); saveDetachedSubtopics(topicEle, topic.getChildren(ITopic.SUMMARY)); saveBoundaries(topicEle, topic); } /** * @param topicEle * @param topic */ private void saveBoundaries(Element topicEle, ITopic topic) { Set<IBoundary> boundaries = topic.getBoundaries(); if (boundaries.isEmpty()) return; Element boundariesEle = DOMUtils.createElement(topicEle, "boundaries"); //$NON-NLS-1$ for (IBoundary boundary : boundaries) { saveBoundary(boundariesEle, boundary); } } /** * @param boundariesEle * @param boundary */ private void saveBoundary(Element boundariesEle, IBoundary boundary) { Element boundaryEle = DOMUtils.createElement(boundariesEle, "boundary"); //$NON-NLS-1$ DOMUtils.setAttribute(boundaryEle, "start-index", String.valueOf(boundary.getStartIndex())); //$NON-NLS-1$ DOMUtils.setAttribute(boundaryEle, "end-index", String.valueOf(boundary.getEndIndex())); //$NON-NLS-1$ saveStyle(boundaryEle, boundary); } /** * @param topicEle * @param children */ private void saveDetachedSubtopics(Element topicEle, List<ITopic> subtopics) { if (subtopics.isEmpty()) return; Element subtopicsEle = DOMUtils.createElement(topicEle, "detached-topics"); //$NON-NLS-1$ saveSubtopics(subtopicsEle, subtopics); } /** * @param topicEle * @param children */ private void saveAttachedSubtopics(Element topicEle, List<ITopic> subtopics) { if (subtopics.isEmpty()) return; Element subtopicsEle = DOMUtils.createElement(topicEle, "attached-topics"); //$NON-NLS-1$ saveSubtopics(subtopicsEle, subtopics); } /** * @param subtopicsEle * @param subtopics */ private void saveSubtopics(Element subtopicsEle, List<ITopic> subtopics) { for (ITopic subtopic : subtopics) { Element subtopicEle = DOMUtils.createElement(subtopicsEle, "topic"); //$NON-NLS-1$ saveTopic(subtopicEle, subtopic); } } /** * @param topicEle * @param topic */ private void saveNumbering(Element topicEle, ITopic topic) { INumbering numbering = topic.getNumbering(); String format = numbering.getNumberFormat(); String prefix = numbering.getPrefix(); String suffix = numbering.getSuffix(); boolean prepend = numbering.prependsParentNumbers(); if (prepend && format == null && prefix == null && suffix == null) return; Element numEle = DOMUtils.createElement(topicEle, "numbering"); //$NON-NLS-1$ if (!prepend) { DOMUtils.setAttribute(numEle, "inherited", "false"); //$NON-NLS-1$ //$NON-NLS-2$ } if (format != null) { DOMUtils.setAttribute(numEle, "number-format", format); //$NON-NLS-1$ } if (prefix != null) { DOMUtils.setAttribute(numEle, "prefix", prefix); //$NON-NLS-1$ } if (suffix != null) { DOMUtils.setAttribute(numEle, "suffix", suffix); //$NON-NLS-1$ } } /** * @param topicEle * @param topic */ private void saveNotes(Element topicEle, ITopic topic) { INotes notes = topic.getNotes(); if (notes.isEmpty()) return; Element notesEle = DOMUtils.createElement(topicEle, "notes"); //$NON-NLS-1$ IPlainNotesContent plain = (IPlainNotesContent) notes .getContent(INotes.PLAIN); if (plain != null) { String textContent = plain.getTextContent(); DOMUtils.createText(notesEle, "plain", textContent); //$NON-NLS-1$ } IHtmlNotesContent html = (IHtmlNotesContent) notes .getContent(INotes.HTML); if (html != null) { saveHtmlNotesContent(notesEle, html, topic.getOwnedWorkbook()); } } /** * @param notesEle * @param html * @param workbook */ private void saveHtmlNotesContent(Element notesEle, IHtmlNotesContent html, IWorkbook workbook) { Element richEle = DOMUtils.createElement(notesEle, "rich"); //$NON-NLS-1$ for (IParagraph p : html.getParagraphs()) { // for (IBaseParagraph p : html.getParagraphs()) { Element pEle = DOMUtils.createElement(richEle, "xhtml:p"); //$NON-NLS-1$ saveStyle(pEle, p); for (ISpan span : p.getSpans()) { if (span instanceof IImageSpan) { saveImageSpan(pEle, (IImageSpan) span); } else { saveTextSpan(pEle, (ITextSpan) span); } } } } /** * @param ele * @param span */ private void saveImageSpan(Element pEle, IImageSpan span) { String source = span.getSource(); if (source == null) return; if (HyperlinkUtils.isAttachmentURL(source)) { source = toAttachmentURL(source); } Element imgEle = DOMUtils.createElement(pEle, "xhtml:img"); //$NON-NLS-1$ DOMUtils.setAttribute(imgEle, "xhtml:src", source); //$NON-NLS-1$ } /** * @param ele * @param span */ private void saveTextSpan(Element pEle, ITextSpan span) { String styleId = span.getStyleId(); if (styleId == null) { Text textNode = pEle.getOwnerDocument().createTextNode( span.getTextContent()); pEle.appendChild(textNode); } else { Element spanEle = DOMUtils.createElement(pEle, "xhtml:span"); //$NON-NLS-1$ DOMUtils.setAttribute(spanEle, "style-id", styleId); //$NON-NLS-1$ spanEle.setTextContent(span.getTextContent()); } } /** * @param topicEle * @param topic */ private void saveMarkers(Element topicEle, ITopic topic) { Set<IMarkerRef> markerRefs = topic.getMarkerRefs(); if (markerRefs.isEmpty()) return; Element markersEle = DOMUtils.createElement(topicEle, "markers"); //$NON-NLS-1$ IMarkerSheet markerSheet = topic.getOwnedWorkbook().getMarkerSheet(); // boolean isSystemSheet = markerSheet.findMarkerGroup("priorityMarkers") != null; for (IMarkerRef mr : markerRefs) { Element markerEle = DOMUtils.createElement(markersEle, "marker"); //$NON-NLS-1$ IMarker marker = mr.getMarker(); if (marker != null) { String type; String id; IMarkerSheet ownedSheet = marker.getOwnedSheet(); if (ownedSheet != null && !ownedSheet.equals(markerSheet)) { type = "Brainy"; //$NON-NLS-1$ } else { type = "User"; //$NON-NLS-1$ } IMarkerGroup group = marker.getParent(); if (group != null) { id = "#" + group.getId() + "/" + marker.getId(); //$NON-NLS-1$ //$NON-NLS-2$ } else { id = marker.getId(); } // if (ownedSheet != null && !ownedSheet.equals(markerSheet)) { // type = isSystemSheet ? "Brainy" : "User"; //$NON-NLS-1$ //$NON-NLS-2$ // IMarkerGroup group = marker.getParent(); // if (group != null) { // id = "#" + group.getId() + "/" + marker.getId(); //$NON-NLS-1$ //$NON-NLS-2$ // } else { // id = marker.getId(); // } // } else { // type = "Attachment"; //$NON-NLS-1$ // id = "#" + marker.getId(); //$NON-NLS-1$ // if (attachmentMarkerPaths == null) // attachmentMarkerPaths = new HashMap<String, String>(); // attachmentMarkerPaths.put(marker.getResourcePath(), marker // .getId()); // } DOMUtils.setAttribute(markerEle, "id", id); //$NON-NLS-1$ DOMUtils.setAttribute(markerEle, "type", type); //$NON-NLS-1$ } } } /** * @param topicEle * @param topic */ private void saveLabels(Element topicEle, ITopic topic) { Set<String> labels = topic.getLabels(); if (labels.isEmpty()) return; Element labelsEle = DOMUtils.createElement(topicEle, "labels"); //$NON-NLS-1$ for (String label : labels) { Element labelEle = DOMUtils.createElement(labelsEle, "label"); //$NON-NLS-1$ labelEle.setTextContent(label); } } /** * @param topicEle * @param topic */ private void saveImage(Element topicEle, ITopic topic) { IImage image = topic.getImage(); String source = image.getSource(); if (source == null) return; Element imgEle = DOMUtils.createElement(topicEle, "xhtml:img"); //$NON-NLS-1$ if (HyperlinkUtils.isAttachmentURL(source)) { source = toAttachmentURL(source); } DOMUtils.setAttribute(imgEle, "xhtml:src", source); //$NON-NLS-1$ int width = image.getWidth(); if (width != IImage.UNSPECIFIED) { DOMUtils.setAttribute(imgEle, "svg:width", String.valueOf(width)); //$NON-NLS-1$ } int height = image.getHeight(); if (height != IImage.UNSPECIFIED) { DOMUtils.setAttribute(imgEle, "svg:height", String.valueOf(height)); //$NON-NLS-1$ } DOMUtils.setAttribute(imgEle, "align", image.getAlignment()); //$NON-NLS-1$ } /** * @param topicEle * @param topic */ private void saveHyperlink(Element topicEle, ITopic topic) { String url = topic.getHyperlink(); if (url == null) return; if (HyperlinkUtils.isAttachmentURL(url)) { url = toAttachmentURL(url); } DOMUtils.setAttribute(topicEle, "xlink:href", url); //$NON-NLS-1$ } private String toAttachmentURL(String url) { String path = HyperlinkUtils.toAttachmentPath(url); String attId = FileUtils.getNoExtensionFileName(path); return HyperlinkUtils.toAttachmentURL("#" + attId); //$NON-NLS-1$ } /** * @param element * @param positionOwner */ private void savePosition(Element element, IPositioned positionOwner) { if (positionOwner.hasPosition()) { savePosition(element, positionOwner.getPosition()); } } /** * @param topicEle * @param topic */ private void saveFolded(Element topicEle, ITopic topic) { if (topic.isFolded()) { DOMUtils.setAttribute(topicEle, "extended", "false"); //$NON-NLS-1$ //$NON-NLS-2$ } } /** * @param topicEle * @param topic */ private void saveStructureClass(Element topicEle, ITopic topic) { String structureClass = topic.getStructureClass(); structureClass = downgradeStructureClass(structureClass); DOMUtils.setAttribute(topicEle, "structure-class", structureClass); //$NON-NLS-1$ } private String downgradeStructureClass(String structureClass) { if (structureClass == null) return null; if ("org.xmind.ui.logic.left".equals(structureClass)) { //$NON-NLS-1$ structureClass = "org.xmind.branchPolicy.org-chart.left"; //$NON-NLS-1$ } else if ("org.xmind.ui.logic.right".equals(structureClass)) { //$NON-NLS-1$ structureClass = "org.xmind.branchPolicy.org-chart.right"; //$NON-NLS-1$ } else if ("org.xmind.ui.spreadsheet".equals(structureClass)) { //$NON-NLS-1$ structureClass = "org.xmind.branchPolicy.chart2d"; //$NON-NLS-1$ } else if (structureClass.startsWith("org.xmind.ui.")) { //$NON-NLS-1$ structureClass = "org.xmind.branchPolicy." + structureClass.substring(13); //$NON-NLS-1$ } return structureClass; } private void savePosition(Element element, Point p) { if (p == null) return; Element posEle = DOMUtils.createElement(element, "position"); //$NON-NLS-1$ DOMUtils.setAttribute(posEle, "svg:x", String.valueOf(p.x)); //$NON-NLS-1$ DOMUtils.setAttribute(posEle, "svg:y", String.valueOf(p.y)); //$NON-NLS-1$ } /** * @param mapEle * @param legend */ private void saveLegend(Element parentEle, ILegend legend) { Element legendEle = DOMUtils.createElement(parentEle, "legend"); //$NON-NLS-1$ if (legend.isVisible()) { DOMUtils.setAttribute(legendEle, "svg:visibility", "visible"); //$NON-NLS-1$ //$NON-NLS-2$ } savePosition(legendEle, legend); for (String markerId : legend.getMarkerIds()) { Element markerDescriptionEle = DOMUtils.createElement(legendEle, "marker"); //$NON-NLS-1$ DOMUtils.replaceId(markerDescriptionEle, markerId); DOMUtils.setAttribute(markerDescriptionEle, "description", legend.getMarkerDescription(markerId)); //$NON-NLS-1$ } } /** * @param mapEle * @param relationships */ private void saveRelationships(Element parentEle, Set<IRelationship> relationships) { if (relationships.isEmpty()) return; Element relationshipsEle = DOMUtils.createElement(parentEle, "relationships"); //$NON-NLS-1$ for (IRelationship relationship : relationships) { saveRelationship(relationshipsEle, relationship); } } /** * @param relationshipsEle * @param relationship */ private void saveRelationship(Element relationshipsEle, IRelationship relationship) { Element relationshipEle = DOMUtils.createElement(relationshipsEle, "relationship"); //$NON-NLS-1$ DOMUtils.replaceId(relationshipEle, relationship.getId()); DOMUtils.setAttribute(relationshipEle, "from-id", relationship.getEnd1Id()); //$NON-NLS-1$ DOMUtils.setAttribute(relationshipEle, "to-id", relationship.getEnd2Id()); //$NON-NLS-1$ saveStyle(relationshipEle, relationship); saveTitle(relationshipEle, relationship); saveControlPoint(relationshipEle, relationship.getControlPoint(0), 0); } /** * @param relationshipEle * @param controlPoint * @param i */ private void saveControlPoint(Element relationshipEle, IControlPoint controlPoint, int index) { Point position = controlPoint.getPosition(); if (position == null) return; String attrName = "control-point" + String.valueOf(index + 1); //$NON-NLS-1$ String value = String.format("%d, %d", position.x, position.y); //$NON-NLS-1$ DOMUtils.setAttribute(relationshipEle, attrName, value); } private void saveStyle(Element element, IStyled styleOwner) { if (styleOwner == null) return; String styleId = styleOwner.getStyleId(); if (styleId == null) return; DOMUtils.setAttribute(element, "style-id", styleId); //$NON-NLS-1$ } private void saveTitle(Element element, ITitled titleOwner) { if (titleOwner == null || !titleOwner.hasTitle()) return; DOMUtils.setText(element, "title", titleOwner.getTitleText()); //$NON-NLS-1$ } private Document createDocument() throws InvocationTargetException { try { return DOMUtils.doCreateDocument(); } catch (ParserConfigurationException e) { throw new InvocationTargetException(e); } } private static String upperFirst(String string) { return string.substring(0, 1).toUpperCase() + string.substring(1); } }