package org.xmind.ui.internal.imports.novamind;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
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.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipInputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
import org.eclipse.osgi.util.NLS;
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.Core;
import org.xmind.core.CoreException;
import org.xmind.core.IBoundary;
import org.xmind.core.IFileEntry;
import org.xmind.core.IHtmlNotesContent;
import org.xmind.core.IHyperlinkSpan;
import org.xmind.core.IIdentifiable;
import org.xmind.core.IImage;
import org.xmind.core.INotes;
import org.xmind.core.INumbering;
import org.xmind.core.IParagraph;
import org.xmind.core.IRelationship;
import org.xmind.core.ISheet;
import org.xmind.core.ISpan;
import org.xmind.core.ITopic;
import org.xmind.core.ITopicExtension;
import org.xmind.core.ITopicExtensionElement;
import org.xmind.core.IWorkbook;
import org.xmind.core.internal.Image;
import org.xmind.core.internal.dom.StyleSheetImpl;
import org.xmind.core.io.DirectoryStorage;
import org.xmind.core.io.IInputSource;
import org.xmind.core.io.IStorage;
import org.xmind.core.io.ResourceMappingManager;
import org.xmind.core.style.IStyle;
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.ui.internal.MindMapUIPlugin;
import org.xmind.ui.internal.imports.ImportMessages;
import org.xmind.ui.internal.protocols.FilePathParser;
import org.xmind.ui.io.MonitoredInputStream;
import org.xmind.ui.resources.ColorUtils;
import org.xmind.ui.resources.FontUtils;
import org.xmind.ui.style.StyleUtils;
import org.xmind.ui.style.Styles;
import org.xmind.ui.wizards.MindMapImporter;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* @author lyn
*/
public class NovaMindImporter extends MindMapImporter
implements NMConstants, ErrorHandler {
private static final Pattern DATE_PATTERN = Pattern.compile(
"((\\d+)-(\\d{1,2})-(\\d{1,2}))T((\\d{1,2}):(\\d{1,2}):(\\d{1,2}))"); //$NON-NLS-1$
private static final String TRANSPARENT_VALUE = "0.00"; //$NON-NLS-1$
private static final double DPM = 1d;
private static final String CONTENT_XML = "content.xml"; //$NON-NLS-1$
private static final String MANIFEST_XML = "manifest.xml"; //$NON-NLS-1$
private static final String STYLE_SHEET_XML = "style-sheet.xml"; //$NON-NLS-1$
private static final String SEP = File.separator;
private static final String RESOURCES_FOLDER = "Resources" + SEP; //$NON-NLS-1$
private class NotesImporter {
IParagraph currentParagraph = null;
IHtmlNotesContent content;
public NotesImporter(IHtmlNotesContent content) {
this.content = content;
}
public void loadFrom(Element notesEle) throws InterruptedException {
checkInterrupted();
Element richTextEle = child(notesEle, "rich-text"); //$NON-NLS-1$
if (richTextEle == null)
return;
NodeList nl = richTextEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
String nodeName = node.getNodeName();
if ("text-run".equals(nodeName)) { //$NON-NLS-1$
loadText(node);
} else if ("hyperlink".equals(nodeName)) { //$NON-NLS-1$
/// TODO add hyperlink to notes
NamedNodeMap atts = node.getAttributes();
Node href = atts.getNamedItem("url"); //$NON-NLS-1$
IHyperlinkSpan linkSpan = content
.createHyperlinkSpan(href.getTextContent());
addSpan(node, linkSpan);
NodeList hnl = node.getChildNodes();
for (int j = 0; j < hnl.getLength(); j++) {
Node hNode = hnl.item(j);
if (hNode != null
&& "text-run".equals(hNode.getNodeName())) { //$NON-NLS-1$
loadText(hNode);
}
}
}
}
}
private void loadText(Node node) throws InterruptedException {
NodeList ps = node.getChildNodes();
for (int pi = 0; pi < ps.getLength(); pi++) {
Node p = ps.item(pi);
if (p.getNodeType() == Node.TEXT_NODE) {
addText(node, p.getTextContent());
} else if ("p".equals(p.getNodeName())) { //$NON-NLS-1$
addParagraph(node);
}
}
}
private void addText(Node node, String text)
throws InterruptedException {
if (text == null || "".equals(text)) //$NON-NLS-1$
return;
addSpan(node, content.createTextSpan(text));
}
private void addSpan(Node node, ISpan span)
throws InterruptedException {
if (currentParagraph == null)
addParagraph(node);
currentParagraph.addSpan(span);
loadStyle(node, span);
loadAlign(node, currentParagraph);
}
private void addParagraph(Node node) throws InterruptedException {
currentParagraph = content.createParagraph();
content.addParagraph(currentParagraph);
loadAlign(node, currentParagraph);
}
@SuppressWarnings({ "nls" })
private void loadStyle(Node node, IStyled host)
throws InterruptedException {
checkInterrupted();
NamedNodeMap atts = node.getAttributes();
Node nmColorNode = atts.getNamedItem("font-color");
if (nmColorNode != null) {
String nmColor = nmColorNode.getTextContent();
nmColor = NovaMindImporter.this.realNmColor(nmColor);
registerStyle(host, Styles.TextColor,
parseColor(nmColor.substring(3)));
}
Node fontSizeNode = atts.getNamedItem("font-size");
if (fontSizeNode != null)
registerStyle(host, Styles.FontSize, NovaMindImporter
.parseFontSize(fontSizeNode.getTextContent()));
Node boldNode = atts.getNamedItem("bold");
if (boldNode != null)
registerStyle(host, Styles.FontWeight,
Boolean.parseBoolean(boldNode.getTextContent())
? Styles.FONT_WEIGHT_BOLD : null);
Node italicNode = atts.getNamedItem("italic");
if (italicNode != null)
registerStyle(host, Styles.FontStyle,
Boolean.parseBoolean(italicNode.getTextContent())
? Styles.FONT_STYLE_ITALIC : null);
String textDecoration = StyleUtils.toTextDecoration(
atts.getNamedItem("underline-style") != null,
atts.getNamedItem("strikethrough-style") != null);
registerStyle(host, Styles.TextDecoration, textDecoration);
String fontName = null;
Node macFontNameNode = atts.getNamedItem("mac-font-name");
if (macFontNameNode != null)
fontName = macFontNameNode.getTextContent();
if (fontName == null || "".equals(fontName)) {
Node windowsFontNameNode = atts
.getNamedItem("windows-font-name");
if (windowsFontNameNode != null)
fontName = windowsFontNameNode.getTextContent();
}
if (fontName != null) {
String availableFontName = FontUtils
.getAAvailableFontNameFor(fontName);
fontName = availableFontName != null ? availableFontName
: fontName;
registerStyle(host, Styles.FontFamily, fontName);
}
}
private void loadAlign(Node node, IStyled host)
throws InterruptedException {
checkInterrupted();
NamedNodeMap atts = node.getAttributes();
Node alignmentNode = atts.getNamedItem("alignment"); //$NON-NLS-1$
if (alignmentNode != null)
registerStyle(host, Styles.TextAlign,
alignmentNode.getTextContent().toLowerCase());
}
}
private static ResourceMappingManager mappings = null;
private IStorage tempStorage;
private IInputSource tempSource;
private Document content;
private Document manifest;
private Document styleSheet;
private ISheet targetSheet;
private Map<IStyled, IStyle> styleMap = new HashMap<IStyled, IStyle>(30);
private IStyle theme = null;
private IStyleSheet tempStyleSheet = null;
private Map<String, String> topicIdMap = new HashMap<String, String>(30);
private Map<String, String> refIdMap = new HashMap<String, String>(30);
private Map<String, List<ITopic>> topicLinkMap = new HashMap<String, List<ITopic>>(
10);
private Map<String, Element> resourceRefMap = new HashMap<String, Element>();
private Map<String, String> resourceMap = new HashMap<String, String>(30);
private Map<String, Element> themeRefMap = new HashMap<String, Element>();
private Map<String, String> assignRefMap = new HashMap<String, String>();
private NovaMindImporter(String sourcePath) {
super(sourcePath);
}
public NovaMindImporter(String sourcePath, IWorkbook targetWorkbook) {
super(sourcePath, targetWorkbook);
}
public void build() throws InvocationTargetException, InterruptedException {
MindMapUIPlugin.getDefault().getUsageDataCollector()
.increase("ImportFromNovaCount"); //$NON-NLS-1$
getMonitor().beginTask(null, 100);
try {
getMonitor()
.subTask(ImportMessages.MindManagerImporter_ReadingContent);
tempStorage = createTemporaryStorage();
extractSourceFileToTemporaryStorage();
tempSource = tempStorage.getInputSource();
content = readFile(CONTENT_XML);
manifest = readFile(MANIFEST_XML);
styleSheet = readFile(STYLE_SHEET_XML);
getMonitor().worked(45);
checkInterrupted();
getMonitor().subTask(
ImportMessages.MindManagerImporter_ReadingElements);
loadWorkbook(content.getDocumentElement());
setTopicLinks();
getMonitor().worked(45);
checkInterrupted();
getMonitor().subTask(
ImportMessages.MindManagerImporter_ArrangingStyles);
arrangeStyles();
getMonitor().worked(5);
checkInterrupted();
getMonitor().subTask(
ImportMessages.MindManagerImporter_GeneratingTheme);
generateTheme();
getMonitor().worked(5);
getMonitor().done();
} catch (Exception e) {
throw new InvocationTargetException(e);
} finally {
clearTempStorage();
}
postBuilded();
}
private Document readFile(String name) throws Exception {
InputStream docEntryStream = tempSource.getEntryStream(name);
if (docEntryStream == null)
throw new IOException("No content entry"); //$NON-NLS-1$
DocumentBuilder builder = getDocumentBuilder();
builder.setErrorHandler(this);
InputStream in = new MonitoredInputStream(docEntryStream, getMonitor());
Document doc;
try {
doc = builder.parse(in);
} finally {
builder.setErrorHandler(null);
try {
in.close();
} catch (Exception e) {
}
}
return doc;
}
private IStorage createTemporaryStorage() throws IOException {
String id = String.format("%1$tY%1$tm%1$td%1$tH%1$tM%1$tS", //$NON-NLS-1$
System.currentTimeMillis());
File tempDir = FileUtils.ensureDirectory(new File(
Core.getWorkspace().getTempDir("import/mindmanager"), id)); //$NON-NLS-1$
return new DirectoryStorage(tempDir);
}
private void extractSourceFileToTemporaryStorage()
throws IOException, CoreException {
FileInputStream fin = new FileInputStream(getSourcePath());
try {
ZipInputStream zin = new ZipInputStream(new MonitoredInputStream(
new BufferedInputStream(fin), getMonitor()));
try {
FileUtils.extractZipFile(zin, tempStorage.getOutputTarget());
} finally {
zin.close();
}
} finally {
fin.close();
}
}
private void checkInterrupted() throws InterruptedException {
if (getMonitor().isCanceled())
throw new InterruptedException();
}
private void clearTempStorage() {
if (tempStorage != null) {
tempStorage.clear();
tempStorage = null;
}
}
private void loadWorkbook(Element docEle) throws InterruptedException {
checkInterrupted();
Element workbookEle = child(docEle, "maps"); //$NON-NLS-1$
if (workbookEle == null)
return;
Element sheetEle = child(workbookEle, "map"); //$NON-NLS-1$
if (sheetEle == null)
return;
loadSheet(sheetEle);
}
private void loadSheet(Element sheetEle) throws InterruptedException {
checkInterrupted();
targetSheet = getTargetWorkbook().createSheet();
Element topicEle = child(sheetEle, "topic-node"); //$NON-NLS-1$
if (topicEle != null)
loadRootTopic(topicEle);
Element relationshipsEle = child(sheetEle, "link-lines"); //$NON-NLS-1$
if (relationshipsEle != null)
loadRelationships(relationshipsEle);
String themeRef = att(sheetEle, "theme-ref"); //$NON-NLS-1$
Element themeEle = findThemeEle(themeRef);
if (themeEle != null)
loadTheme(themeEle);
addTargetSheet(targetSheet);
}
public ISheet getTargetSheet() {
return targetSheet;
}
private void loadRootTopic(Element topicEle) throws InterruptedException {
checkInterrupted();
ITopic rootTopic = getTargetSheet().getRootTopic();
loadTopic(topicEle, rootTopic);
Element subTopicsEle = child(topicEle, "sub-topics"); //$NON-NLS-1$
if (subTopicsEle != null)
loadSubElements(subTopicsEle, rootTopic);
}
private void loadSubElements(Element topicsEle, ITopic topic)
throws InterruptedException {
checkInterrupted();
Iterator<Element> subElements = children(topicsEle, "topic-node"); //$NON-NLS-1$
while (subElements.hasNext()) {
Element subElement = subElements.next();
String type = att(subElement, "type"); //$NON-NLS-1$
if ("Boundary".equals(type)) { //$NON-NLS-1$
loadBoundary(subElement, topic);
} else {
ITopic subTopic = addElement(topic, subElement, type);
loadTopic(subElement, subTopic);
Element subTopicsEle = child(subElement, "sub-topics"); //$NON-NLS-1$
if (subTopicsEle != null)
loadSubElements(subTopicsEle, subTopic);
}
}
}
private void loadTopic(Element topicEle, ITopic topic)
throws InterruptedException {
checkInterrupted();
loadOId(topicEle, topic);
loadTopicContent(topicEle, topic);
loadTopicNodeStyle(topicEle, topic);
}
private ITopic addElement(ITopic topic, Element topicEle, String type) {
ITopic subTopic = getTargetWorkbook().createTopic();
if ("FloatingTopic".equals(type)) //$NON-NLS-1$
topic.add(subTopic, ITopic.DETACHED);
else if ("Callout".equals(type)) //$NON-NLS-1$
topic.add(subTopic, ITopic.CALLOUT);
else
topic.add(subTopic);
return subTopic;
}
private void loadOId(Element nmEle, IIdentifiable element) {
String OId = att(nmEle, "id"); //$NON-NLS-1$
if (OId != null)
topicIdMap.put(OId, element.getId());
}
private void loadTopicContent(Element topicEle, ITopic topic)
throws InterruptedException {
checkInterrupted();
String id = att(topicEle, "id"); //$NON-NLS-1$
String ref = att(topicEle, "topic-ref"); //$NON-NLS-1$
refIdMap.put(ref, id);
Element contentEle = findTopicContentEle(ref);
if (contentEle == null)
return;
loadTitleText(contentEle, topic);
loadNotes(contentEle, topic);
loadHyperlink(contentEle, topic);
loadAttachments(contentEle, topic);
loadImages(contentEle, topic);
loadTask(contentEle, topic);
}
private Element findTopicContentEle(String refId)
throws InterruptedException {
checkInterrupted();
if (refId == null)
return null;
Element contentEle = content.getDocumentElement();
Element topicsEle = child(contentEle, "topics"); //$NON-NLS-1$
if (topicsEle == null)
return null;
Iterator<Element> topicEles = children(topicsEle, "topic"); //$NON-NLS-1$
while (topicEles.hasNext()) {
Element topic = topicEles.next();
String id = att(topic, "id"); //$NON-NLS-1$
if (refId.equals(id))
return topic;
}
return null;
}
private void loadTitleText(Element contentEle, ITopic topic)
throws InterruptedException {
Element text = child(contentEle, "rich-text"); //$NON-NLS-1$
if (text == null)
return;
Element titleRun = child(text, "text-run"); //$NON-NLS-1$
if (titleRun == null)
return;
topic.setTitleText(titleRun.getTextContent());
loadTextStyle(titleRun, topic);
}
private void loadNotes(Element contentEle, ITopic topic)
throws InterruptedException {
checkInterrupted();
Element notesEle = child(contentEle, "notes"); //$NON-NLS-1$
if (notesEle == null)
return;
IHtmlNotesContent content = (IHtmlNotesContent) getTargetWorkbook()
.createNotesContent(INotes.HTML);
NotesImporter notesImporter = new NotesImporter(content);
notesImporter.loadFrom(notesEle);
topic.getNotes().setContent(INotes.HTML, content);
}
private void loadHyperlink(Element contentEle, ITopic topic)
throws InterruptedException {
checkInterrupted();
Element linksEle = child(contentEle, "links"); //$NON-NLS-1$
if (linksEle == null)
return;
Iterator<Element> it = children(linksEle, "link"); //$NON-NLS-1$
while (it.hasNext()) {
Element linkDataEle = it.next();
String url = att(linkDataEle, "url"); //$NON-NLS-1$
if (url == null)
continue;
String name = att(linkDataEle, "display-name"); //$NON-NLS-1$
if (name == null || "".equals(name)) //$NON-NLS-1$
name = url;
ITopic linkTopic = getTargetWorkbook().createTopic();
linkTopic.setTitleText(name);
topic.add(linkTopic);
if (url.startsWith("novamind://topic/")) { //$NON-NLS-1$
recordTopicLink(url.replace("novamind://topic/", ""), //$NON-NLS-1$//$NON-NLS-2$
linkTopic);
continue;
} else if (!HyperlinkUtils.isLinkToWeb(url)) {
url = FilePathParser.toURI(url, false);
}
linkTopic.setHyperlink(url);
}
}
private void loadAttachments(Element contentEle, ITopic topic)
throws InterruptedException {
checkInterrupted();
if (manifest == null)
return;
Element attachmentsEle = child(contentEle, "attachments"); //$NON-NLS-1$
if (attachmentsEle == null)
return;
Iterator<Element> attachmentEles = children(attachmentsEle,
"attachment"); //$NON-NLS-1$
while (attachmentEles.hasNext()) {
Element attDataEle = attachmentEles.next();
IFileEntry entry = getResourceFileEntry(attDataEle);
if (entry != null) {
ITopic attTopic = getTargetWorkbook().createTopic();
String title = getResourceTitle(attDataEle);
attTopic.setTitleText(title == null
? new File(entry.getPath()).getName() : title);
attTopic.setHyperlink(
HyperlinkUtils.toAttachmentURL(entry.getPath()));
topic.add(attTopic, ITopic.ATTACHED);
}
}
}
private void loadImages(Element contentEle, ITopic topic)
throws InterruptedException {
checkInterrupted();
if (manifest == null)
return;
loadImage(contentEle, topic, "top-image", IImage.TOP, 0, 64); //$NON-NLS-1$
loadImage(contentEle, topic, "bottom-image", IImage.BOTTOM, 0, 64); //$NON-NLS-1$
loadImage(contentEle, topic, "left-image", Image.LEFT, 64, 0); //$NON-NLS-1$
loadImage(contentEle, topic, "right-image", Image.RIGHT, 64, 0); //$NON-NLS-1$
}
private void loadImage(Element contentEle, ITopic topic, String imageAtt,
String alignment, int w, int h) throws InterruptedException {
Element imageEle = child(contentEle, imageAtt);
if (imageEle != null) {
IFileEntry entry = getResourceFileEntry(imageEle);
if (entry != null) {
String title = getResourceTitle(imageEle);
ITopic attTopic = getTargetWorkbook().createTopic();
attTopic.setTitleText(title == null
? new File(entry.getPath()).getName() : title);
IImage image = attTopic.getImage();
image.setSource(
HyperlinkUtils.toAttachmentURL(entry.getPath()));
image.setAlignment(alignment);
image.setSize(w == 0 ? IImage.UNSPECIFIED : w,
h == 0 ? IImage.UNSPECIFIED : h);
topic.add(attTopic);
}
}
}
private void loadTask(Element contentEle, ITopic topic)
throws InterruptedException {
checkInterrupted();
Element taskEle = child(contentEle, "project-task"); //$NON-NLS-1$
if (taskEle == null)
return;
ITopicExtensionElement taskContent = null;
String priority = att(taskEle, "priority"); //$NON-NLS-1$
loadMarker(topic, parsePriority(priority));
String pc = att(taskEle, "percentage-complete"); //$NON-NLS-1$
loadMarker(topic, parsePercentage(pc));
if (pc != null) {
taskContent = ensureTaskContent(topic, taskContent);
taskContent.deleteChildren("progress"); //$NON-NLS-1$
ITopicExtensionElement ele = taskContent.createChild("progress"); //$NON-NLS-1$
ele.setTextContent(pc);
}
String start = att(taskEle, "start-time"); //$NON-NLS-1$
if (start != null && !"".equals(start)) { //$NON-NLS-1$
Matcher m = DATE_PATTERN.matcher(start);
if (m.find()) {
taskContent = ensureTaskContent(topic, taskContent);
taskContent.deleteChildren("start-date"); //$NON-NLS-1$
ITopicExtensionElement ele = taskContent
.createChild("start-date"); //$NON-NLS-1$
ele.setTextContent(m.group(1) + " " + m.group(5)); //$NON-NLS-1$
}
}
String end = att(taskEle, "end-time"); //$NON-NLS-1$
if (end != null) {
Matcher m = DATE_PATTERN.matcher(end);
if (m.find()) {
taskContent = ensureTaskContent(topic, taskContent);
taskContent.deleteChildren("end-date");//$NON-NLS-1$
ITopicExtensionElement ele = taskContent
.createChild("end-date"); //$NON-NLS-1$
ele.setTextContent(m.group(1) + " " + m.group(5)); //$NON-NLS-1$
}
}
String duration = att(taskEle, "duration"); //$NON-NLS-1$
String dUnit = att(taskEle, "duration-unit"); //$NON-NLS-1$
if (duration != null && !"".equals(duration)) { //$NON-NLS-1$
String durationLabel = null;
if ("Years".equals(dUnit)) { //$NON-NLS-1$
durationLabel = NLS.bind(
ImportMessages.NovaMindImporter_Duration_Years_label,
duration);
} else if ("Months".equals(dUnit)) { //$NON-NLS-1$
durationLabel = NLS.bind(
ImportMessages.NovaMindImporter_Duration_Months_label,
duration);
} else if ("Weeks".equals(dUnit)) { //$NON-NLS-1$
durationLabel = NLS.bind(
ImportMessages.NovaMindImporter_Duration_Weeks_label,
duration);
} else if ("Hours".equals(dUnit)) { //$NON-NLS-1$
durationLabel = NLS.bind(
ImportMessages.NovaMindImporter_Duration_Hours_label,
duration);
} else if ("Minutes".equals(dUnit)) { //$NON-NLS-1$
durationLabel = NLS.bind(
ImportMessages.NovaMindImporter_Duration_Minutes_label,
duration);
} else {
durationLabel = NLS.bind(
ImportMessages.NovaMindImporter_Duration_Days_label,
duration);
}
topic.addLabel(
NLS.bind(ImportMessages.NovaMindImporter_Duration_label,
durationLabel));
}
Element resourcesEle = child(taskEle, "assigned-resources"); //$NON-NLS-1$
if (resourcesEle != null) {
Iterator<Element> it = children(resourcesEle,
"project-resource-ref"); //$NON-NLS-1$
String assigns = ""; //$NON-NLS-1$
while (it.hasNext()) {
Element next = it.next();
String ref = next.getTextContent();
assigns += findAssign(ref) + ","; //$NON-NLS-1$
}
if (assigns != null && !"".equals(assigns)) { //$NON-NLS-1$
assigns = assigns.substring(0, assigns.length() - 2);
taskContent = ensureTaskContent(topic, taskContent);
taskContent.deleteChildren("assigned-to");//$NON-NLS-1$
ITopicExtensionElement ele = taskContent
.createChild("assigned-to"); //$NON-NLS-1$
ele.setTextContent(assigns);
topic.addLabel(
NLS.bind(ImportMessages.NovaMindImporter_Resource_label,
assigns.replaceAll(",", ";"))); //$NON-NLS-1$//$NON-NLS-2$
}
}
}
private void loadMarker(ITopic topic, String markerId)
throws InterruptedException {
checkInterrupted();
if (markerId != null)
topic.addMarker(markerId);
}
private static String parsePriority(String nmPriority) {
if (nmPriority == null)
return null;
try {
int priority = Integer.parseInt(nmPriority);
switch (priority) {
case 1:
return "priority-1"; //$NON-NLS-1$
case 2:
return "priority-2"; //$NON-NLS-1$
case 3:
return "priority-3"; //$NON-NLS-1$
case 4:
return "priority-4"; //$NON-NLS-1$
case 5:
return "priority-5"; //$NON-NLS-1$
case 6:
return "priority-6"; //$NON-NLS-1$
case 7:
return "priority-7"; //$NON-NLS-1$
case 8:
return "priority-8"; //$NON-NLS-1$
case 9:
return "priority-9"; //$NON-NLS-1$
}
} catch (NumberFormatException e) {
}
return null;
}
@SuppressWarnings("nls")
private static String parsePercentage(String nmPercentage) {
if (nmPercentage == null)
return null;
try {
int pc = Integer.parseInt(nmPercentage);
if (pc < 12)
return "task-start";
if (pc < 25)
return "task-oct";
if (pc < 37)
return "task-quarter";
if (pc < 50)
return "task-3oct";
if (pc < 62)
return "task-half";
if (pc < 75)
return "task-5oct";
if (pc < 87)
return "task-3quar";
if (pc < 100)
return "task-7oct";
if (pc == 100)
return "task-done";
} catch (NumberFormatException e) {
}
return null;
}
private void loadTextStyle(Element titleEle, IStyled host)
throws InterruptedException {
checkInterrupted();
String nmColor = att(titleEle, "font-color"); //$NON-NLS-1$
if (nmColor != null) {
nmColor = realNmColor(nmColor);
registerStyle(host, Styles.TextColor,
parseColor(nmColor.substring(3)));
}
registerStyle(host, Styles.FontSize,
parseFontSize(att(titleEle, "font-size"))); //$NON-NLS-1$
registerStyle(host, Styles.FontWeight,
Boolean.parseBoolean(att(titleEle, "bold")) //$NON-NLS-1$
? Styles.FONT_WEIGHT_BOLD : null);
registerStyle(host, Styles.FontStyle,
Boolean.parseBoolean(att(titleEle, "italic")) //$NON-NLS-1$
? Styles.FONT_STYLE_ITALIC : null);
String textDecoration = StyleUtils.toTextDecoration(
att(titleEle, "underline-style") != null, //$NON-NLS-1$
att(titleEle, "strikethrough-style") != null); //$NON-NLS-1$
registerStyle(host, Styles.TextDecoration, textDecoration);
String alignment = att(titleEle, "alignment"); //$NON-NLS-1$
if (alignment != null)
registerStyle(host, Styles.TextAlign, alignment.toLowerCase());
String fontName = att(titleEle, "mac-font-name"); //$NON-NLS-1$
if (fontName == null)
fontName = att(titleEle, "windows-font-name"); //$NON-NLS-1$
if (fontName != null) {
String availableFontName = FontUtils
.getAAvailableFontNameFor(fontName);
fontName = availableFontName != null ? availableFontName : fontName;
registerStyle(host, Styles.FontFamily, fontName);
}
}
private void loadTopicNodeStyle(Element topicEle, ITopic topic)
throws InterruptedException {
checkInterrupted();
Element nodeViewEle = child(topicEle, "topic-node-view"); //$NON-NLS-1$
if (nodeViewEle == null)
return;
loadPosition(nodeViewEle, topic);
Element nodeStyleEle = child(nodeViewEle, "topic-node-style"); //$NON-NLS-1$
if (nodeStyleEle == null)
return;
loadFillStyle(nodeStyleEle, topic, null);
loadShapeStyle(nodeStyleEle, topic);
loadLineStyle(nodeStyleEle, topic);
loadStructure(nodeStyleEle, topic);
loadConnectionStyle(nodeStyleEle, topic);
loadNumbering(nodeStyleEle, topic);
}
private void loadPosition(Element nodeViewEle, ITopic topic)
throws InterruptedException {
checkInterrupted();
String location = att(nodeViewEle, "manual-location"); //$NON-NLS-1$
if ((location == null || "".equals(location)) //$NON-NLS-1$
&& (ITopic.DETACHED.equals(topic.getType())
|| ITopic.CALLOUT.equals(topic.getType())))
location = att(nodeViewEle, "location"); //$NON-NLS-1$
if (location == null || "".equals(location)) //$NON-NLS-1$
return;
String[] split = location.split(","); //$NON-NLS-1$
if (split.length != 2)
return;
Float x = parseFloat(split[0]);
Float y = parseFloat(split[1]);
if (x != null && y != null && x.floatValue() != 0
&& y.floatValue() != 0) {
topic.setPosition(mm2Dots(x), mm2Dots(y));
}
}
private void loadFillStyle(Element nodeStyleEle, IStyled host,
String defaultColor) throws InterruptedException {
checkInterrupted();
Element fillStyleEle = child(nodeStyleEle, "fill-style"); //$NON-NLS-1$
if (fillStyleEle == null)
return;
String nmColor = getFillValue(fillStyleEle);
if (nmColor == null) {
if (defaultColor == null)
return;
nmColor = defaultColor;
}
nmColor = realNmColor(nmColor);
String opacity = parseAlpha(nmColor);
String fillColor = parseColor(nmColor.substring(3));
if (opacity != null && !opacity.equals(TRANSPARENT_VALUE))
registerStyle(host, Styles.Opacity, opacity);
if (fillColor != null)
registerStyle(host, Styles.FillColor, fillColor);
}
private String realNmColor(String nmColor) {
if (!nmColor.startsWith("#")) //$NON-NLS-1$
nmColor = getMapping("nmColor", nmColor, "#FFFFF"); //$NON-NLS-1$//$NON-NLS-2$
return nmColor;
}
private String getFillValue(Element fillStyleEle)
throws InterruptedException {
checkInterrupted();
String fillValue = null;
Element advancedGradientEle = child(fillStyleEle, "advanced-gradient"); //$NON-NLS-1$
if (advancedGradientEle != null) {
Element advancedColors = child(advancedGradientEle, "colors"); //$NON-NLS-1$
if (advancedColors != null) {
Element colorEle = child(advancedColors, "color-stop"); //$NON-NLS-1$
if (colorEle != null)
fillValue = att(colorEle, "color"); //$NON-NLS-1$
}
}
if (fillValue == null) {
Element simpleGradientEle = child(fillStyleEle, "simple-gradient"); //$NON-NLS-1$
if (simpleGradientEle != null) {
String sColor = att(simpleGradientEle, "start-color"); //$NON-NLS-1$
String eColor = att(simpleGradientEle, "end-color"); //$NON-NLS-1$
fillValue = sColor != null ? sColor : eColor;
}
}
if (fillValue == null) {
Element solidColorEle = child(fillStyleEle, "solid-color"); //$NON-NLS-1$
if (solidColorEle != null)
fillValue = att(solidColorEle, "color"); //$NON-NLS-1$
}
return fillValue;
}
private String parseAlpha(String color) {
if (color != null && color.startsWith("#")) { //$NON-NLS-1$
try {
int alpha = Integer.parseInt(color.substring(1, 2), 16);
double opacity = ((double) alpha) * 100 / 255;
return String.format("%.2f", opacity); //$NON-NLS-1$
} catch (Exception e) {
}
}
return null;
}
private static String parseColor(String color) {
if (color != null) {
int r;
int g;
int b;
try {
r = Integer.parseInt(color.substring(0, 2), 16);
g = Integer.parseInt(color.substring(2, 4), 16);
b = Integer.parseInt(color.substring(4, 6), 16);
return ColorUtils.toString(r, g, b);
} catch (Throwable t) {
}
}
return null;
}
private static String parseFontSize(String size) {
if (size != null) {
try {
double value = Double.parseDouble(size);
size = StyleUtils.addUnitPoint((int) value);
} catch (Exception e) {
}
}
return size;
}
private void loadShapeStyle(Element nodeStyleEle, IStyled host)
throws InterruptedException {
checkInterrupted();
Element shapeStyleEle = child(nodeStyleEle, "shape-style"); //$NON-NLS-1$
if (shapeStyleEle == null)
return;
if (host instanceof ITopic) {
Element topicShapeEle = child(shapeStyleEle, "topic-shape-style"); //$NON-NLS-1$
if (topicShapeEle != null) {
String shape = att(topicShapeEle, "type"); //$NON-NLS-1$
if (ITopic.CALLOUT.equals(((ITopic) host).getType()))
registerStyle(host, Styles.CalloutShapeClass,
parseCalloutShape(shape));
else
registerStyle(host, Styles.ShapeClass,
parseTopicShape(shape));
}
}
if (host instanceof IBoundary) {
Element boundaryShapeEle = child(shapeStyleEle,
"boundary-shape-style"); //$NON-NLS-1$
if (boundaryShapeEle != null)
registerStyle(host, Styles.ShapeClass,
parseBoundaryShape(att(boundaryShapeEle, "type"))); //$NON-NLS-1$
}
}
private void loadLineStyle(Element nodeStyleEle, IStyled host)
throws InterruptedException {
checkInterrupted();
Element lineStyleEle = child(nodeStyleEle, "line-style"); //$NON-NLS-1$
if (lineStyleEle == null)
return;
String nmColor = att(lineStyleEle, "color"); //$NON-NLS-1$
if (nmColor != null) {
nmColor = realNmColor(nmColor);
registerStyle(host, Styles.LineColor,
parseColor(nmColor.substring(3)));
}
String width = parseLineWidth(att(lineStyleEle, "stroke-width")); //$NON-NLS-1$
registerStyle(host, Styles.LineWidth, width);
String stroke = att(lineStyleEle, "draws-stroke"); //$NON-NLS-1$
if (Boolean.parseBoolean(stroke))
registerStyle(host, Styles.BorderLineWidth, "0"); //$NON-NLS-1$
String linePattern = att(lineStyleEle, "dash"); //$NON-NLS-1$
registerStyle(host, Styles.LinePattern, parseLinePattern(linePattern));
}
private static String parseLinePattern(String linePattern) {
if (linePattern == null)
return Styles.LINE_PATTERN_SOLID;
char c = linePattern.charAt(0);
switch (c) {
case 'b':
case 'e':
case 'i':
case 'r':
return Styles.LINE_PATTERN_DASH;
case 'c':
case 'f':
case 'l':
case 's':
case 'y':
return Styles.LINE_PATTERN_DOT;
case 'd':
case 'g':
case 'j':
case 'm':
case 'o':
case 'p':
case 't':
case 'v':
case 'w':
return Styles.LINE_PATTERN_DASH_DOT;
case 'h':
case 'k':
case 'n':
case 'q':
case 'u':
case 'x':
return Styles.LINE_PATTERN_DASH_DOT_DOT;
}
return Styles.LINE_PATTERN_SOLID;
}
private static String parseLineWidth(String width) {
if (width == null)
return null;
Float w = parseFloat(width.replace("pt", "")); //$NON-NLS-1$ //$NON-NLS-2$
if (w != null) {
if (w <= 2)
return "1"; //$NON-NLS-1$
if (w <= 4)
return "2"; //$NON-NLS-1$
if (w <= 6)
return "3"; //$NON-NLS-1$
if (w <= 8)
return "4"; //$NON-NLS-1$
return "5"; //$NON-NLS-1$
}
return null;
}
private static Float parseFloat(String value) {
if (value != null) {
try {
return Float.valueOf(value);
} catch (Throwable e) {
}
}
return null;
}
private void loadStructure(Element styleEle, ITopic topic)
throws InterruptedException {
checkInterrupted();
Element layoutStyle = child(styleEle, "children-layout-style"); //$NON-NLS-1$
if (layoutStyle == null)
return;
topic.setStructureClass(
parseStructureType(topic, att(layoutStyle, "angle"), //$NON-NLS-1$
att(layoutStyle, "layout-mode"))); //$NON-NLS-1$
}
private static String parseStructureType(ITopic topic, String angle,
String mode) {
if (mode != null && mode.equalsIgnoreCase("Radial")) { //$NON-NLS-1$
return "org.xmind.ui.map.unbalanced"; //$NON-NLS-1$
} else {
if ("0".equals(angle)) //$NON-NLS-1$
return "org.xmind.ui.logic.right"; //$NON-NLS-1$
if ("90".equals(angle)) //$NON-NLS-1$
return "org.xmind.ui.org-chart.down"; //$NON-NLS-1$
if ("180".equals(angle)) //$NON-NLS-1$
return "org.xmind.ui.logic.left"; //$NON-NLS-1$
if ("270".equals(angle)) //$NON-NLS-1$
return "org.xmind.ui.org-chart.up"; //$NON-NLS-1$
}
if (topic.getParent() != null)
return topic.getParent().getStructureClass();
return null;
}
private void loadConnectionStyle(Element styleEle, ITopic topic)
throws InterruptedException {
checkInterrupted();
Element connectionStyleEle = child(styleEle,
"children-connection-style"); //$NON-NLS-1$
if (connectionStyleEle == null)
return;
String type = att(connectionStyleEle, "connection-type"); //$NON-NLS-1$
registerStyle(topic, Styles.LineClass, parseBranchConnection(type));
}
private static String parseBranchConnection(String lineShape) {
return getMapping("branchConnection", lineShape, //$NON-NLS-1$
"org.xmind.branchConnection.curve"); //$NON-NLS-1$
}
private void loadNumbering(Element styleEle, ITopic topic)
throws InterruptedException {
checkInterrupted();
Element numberingEle = child(styleEle,
"children-outline-numbering-style"); //$NON-NLS-1$
if (numberingEle == null)
return;
String depthValue = att(numberingEle, "depth"); //$NON-NLS-1$
if (depthValue == null || "".equals(depthValue)) //$NON-NLS-1$
return;
INumbering numbering = topic.getNumbering();
if ("0".equals(depthValue)) { //$NON-NLS-1$
numbering.setFormat("org.xmind.numbering.none"); //$NON-NLS-1$
return;
}
int depth = Integer.parseInt(depthValue);
depth = depth == -1 ? 10 : depth;
String format = "org.xmind.numbering.arabic"; //$NON-NLS-1$
String separator = "org.xmind.numbering.separator.dot"; //$NON-NLS-1$
String prefix = null;
String suffix = null;
Element formatArrayEle = child(numberingEle, "format-array"); //$NON-NLS-1$
if (formatArrayEle != null) {
Element formatEle = child(formatArrayEle, "outline-format"); //$NON-NLS-1$
if (formatEle != null) {
format = parseNumberFormat(att(formatEle, "style")); //$NON-NLS-1$
separator = parseNumberSeprator(att(formatEle, "separator")); //$NON-NLS-1$
prefix = att(formatEle, "prefix"); //$NON-NLS-1$
suffix = att(formatEle, "suffix"); //$NON-NLS-1$
}
}
numbering.setFormat(format);
numbering.setSeparator(separator);
numbering.setDepth(String.valueOf(depth));
if (prefix != null)
numbering.setPrefix(prefix);
if (suffix != null)
numbering.setSuffix(suffix);
}
private static String parseNumberFormat(String format) {
return getMapping("numberFormat", format, "org.xmind.numbering.arabic"); //$NON-NLS-1$//$NON-NLS-2$
}
private static String parseNumberSeprator(String seprator) {
return getMapping("numberSeprator", seprator, //$NON-NLS-1$
"org.xmind.numbering.separator.dot"); //$NON-NLS-1$
}
private void loadBoundary(Element boundaryEle, ITopic topic)
throws InterruptedException {
checkInterrupted();
if (topic.isRoot())
return;
IBoundary boundary = getTargetWorkbook().createBoundary();
if (topic.isAttached()) {
ITopic parent = topic.getParent();
int index = topic.getIndex();
boundary.setStartIndex(index);
boundary.setEndIndex(index);
parent.addBoundary(boundary);
} else {
boundary.setMasterBoundary(true);
topic.addBoundary(boundary);
}
loadBoundaryStyle(boundaryEle, boundary);
}
private void loadBoundaryStyle(Element boundaryEle, IBoundary boundary)
throws InterruptedException {
checkInterrupted();
Element nodeViewEle = child(boundaryEle, "topic-node-view"); //$NON-NLS-1$
if (nodeViewEle == null)
return;
Element nodeStyleEle = child(nodeViewEle, "topic-node-style"); //$NON-NLS-1$
if (nodeStyleEle == null)
return;
loadFillStyle(nodeStyleEle, boundary, "#fffce0bf"); //$NON-NLS-1$
loadLineStyle(nodeStyleEle, boundary);
loadShapeStyle(nodeStyleEle, boundary);
}
private void loadRelationships(Element relationshipsEle)
throws InterruptedException {
checkInterrupted();
Iterator<Element> relationshipEles = children(relationshipsEle,
"topic-node"); //$NON-NLS-1$
while (relationshipEles.hasNext())
loadRelationship(relationshipEles.next());
}
private void loadRelationship(Element relationshipEle)
throws InterruptedException {
checkInterrupted();
Element relDataEle = child(relationshipEle, "link-line-data"); //$NON-NLS-1$
if (relDataEle == null)
return;
IRelationship rel = getTargetWorkbook().createRelationship();
getTargetSheet().addRelationship(rel);
loadConnections(relDataEle, rel, true);
Element nodeViewEle = child(relationshipEle, "topic-node-view"); //$NON-NLS-1$
if (nodeViewEle == null)
return;
Element styleEle = child(nodeViewEle, "topic-node-style"); //$NON-NLS-1$
if (styleEle == null)
return;
loadLineStyle(styleEle, rel);
}
private void loadConnections(Element relDataEle, IRelationship rel,
boolean autoRouting) throws InterruptedException {
checkInterrupted();
String startOId = att(relDataEle, "start-topic-node-ref"); //$NON-NLS-1$
String endOId = att(relDataEle, "end-topic-node-ref"); //$NON-NLS-1$
String startId = topicIdMap.get(startOId);
String endId = topicIdMap.get(endOId);
if (startId != null && endId != null) {
rel.setEnd1Id(startId);
rel.setEnd2Id(endId);
}
// TODO control point
// String isAuto = att(relDataEle, "is-automatic-link-line"); //$NON-NLS-1$
// if (!Boolean.parseBoolean(isAuto)) {
// Element cpsEle = child(relDataEle, "control-points"); //$NON-NLS-1$
// if (cpsEle != null) {
// Iterator<Element> cpEles = children(cpsEle, "control-point"); //$NON-NLS-1$
// int index = 0;
// while (cpEles.hasNext()) {
// String loc = att(cpEles.next(), "location"); //$NON-NLS-1$
// String[] split = loc.split(","); //$NON-NLS-1$
// Float x = parseFloat(split[0]);
// Float y = parseFloat(split[1]);
// if (x != null && y != null && x.floatValue() != 0
// && y.floatValue() != 0) {
// rel.getControlPoint(index++).setPosition(
// mm2Dots(x.floatValue()),
// mm2Dots(y.floatValue()));
// }
// }
//
// }
// }
Element startStyleEle = child(relDataEle, "start-terminator"); //$NON-NLS-1$
if (startStyleEle != null)
registerStyle(rel, Styles.ArrowBeginClass,
parseRelTerminatorType(att(startStyleEle, "type"))); //$NON-NLS-1$
Element endStyleEle = child(relDataEle, "end-terminator");//$NON-NLS-1$
if (endStyleEle != null)
registerStyle(rel, Styles.ArrowEndClass,
parseRelTerminatorType(att(endStyleEle, "type"))); //$NON-NLS-1$
}
private String parseRelTerminatorType(String type) {
return getMapping("arrowShape", type, null); //$NON-NLS-1$
}
private static String parseTopicShape(String nmShape) {
return getMapping("topicShape", nmShape, null); //$NON-NLS-1$
}
private static String parseCalloutShape(String nmShape) {
return getMapping("calloutShape", nmShape, null); //$NON-NLS-1$
}
private static String parseBoundaryShape(String nmShape) {
return getMapping("boundaryShape", nmShape, //$NON-NLS-1$
"org.xmind.boundaryShape.polygon"); //$NON-NLS-1$
}
private void registerStyle(IStyled styleOwner, String key, String value) {
if (value == null)
return;
IStyle style = styleMap.get(styleOwner);
if (style == null) {
style = getTempStyleSheet().createStyle(styleOwner.getStyleType());
getTempStyleSheet().addStyle(style, IStyleSheet.NORMAL_STYLES);
styleMap.put(styleOwner, style);
}
if (Styles.TextDecoration.equals(key)) {
String oldValue = style.getProperty(key);
if (oldValue != null && !oldValue.contains(value)) {
boolean underline = oldValue
.contains(Styles.TEXT_DECORATION_UNDERLINE)
|| value.contains(Styles.TEXT_DECORATION_UNDERLINE);
boolean strikeout = oldValue
.contains(Styles.TEXT_DECORATION_LINE_THROUGH)
|| value.contains(Styles.TEXT_DECORATION_LINE_THROUGH);
value = StyleUtils.toTextDecoration(underline, strikeout);
}
}
style.setProperty(key, value);
}
private IStyleSheet getTempStyleSheet() {
if (tempStyleSheet == null) {
tempStyleSheet = Core.getStyleSheetBuilder().createStyleSheet();
((StyleSheetImpl) tempStyleSheet)
.setManifest(getTargetWorkbook().getManifest());
}
return tempStyleSheet;
}
private void arrangeStyles() throws InterruptedException {
IStyleSheet targetStyleSheet = getTargetWorkbook().getStyleSheet();
for (Entry<IStyled, IStyle> en : styleMap.entrySet()) {
checkInterrupted();
IStyled styleOwner = en.getKey();
IStyle style = en.getValue();
IStyle importedStyle = targetStyleSheet.importStyle(style);
if (importedStyle != null) {
styleOwner.setStyleId(importedStyle.getId());
}
}
}
private void loadTheme(Element themeEle) throws InterruptedException {
checkInterrupted();
loadSheetStyle(themeEle);
loadTopicTheme(themeEle);
loadRelTheme(themeEle);
loadBoundaryTheme(themeEle);
}
private void loadSheetStyle(Element themeEle) throws InterruptedException {
checkInterrupted();
Element styleEle = child(themeEle, "background-style"); //$NON-NLS-1$
if (styleEle == null)
return;
ISheet sheet = getTargetSheet();
registerStyle(sheet, Styles.LineTapered, Styles.TAPERED);
Element bgFillEle = child(styleEle, "solid-color"); //$NON-NLS-1$
if (bgFillEle != null) {
String nmColor = att(bgFillEle, "color"); //$NON-NLS-1$
if (nmColor != null) {
registerStyle(sheet, Styles.FillColor,
parseColor(realNmColor(nmColor).substring(3)));
}
}
Element bgImageEle = child(styleEle, "texture-image"); //$NON-NLS-1$
if (bgImageEle != null) {
IFileEntry entry = getResourceFileEntry(bgImageEle);
if (entry != null && entry.getSize() > 0) {
registerStyle(sheet, Styles.Background,
HyperlinkUtils.toAttachmentURL(entry.getPath()));
registerStyle(sheet, Styles.Opacity,
att(bgImageEle, "opacity")); //$NON-NLS-1$
}
}
}
private void loadTopicTheme(Element themeEle) throws InterruptedException {
checkInterrupted();
Element rootStyleEle = child(themeEle, "root-topic-style"); //$NON-NLS-1$
if (rootStyleEle != null)
loadTopicTheme(rootStyleEle, Styles.FAMILY_CENTRAL_TOPIC, true);
Element floatStyleEle = child(themeEle, "floating-topic-style"); //$NON-NLS-1$
if (floatStyleEle != null)
loadTopicTheme(floatStyleEle, Styles.FAMILY_FLOATING_TOPIC, false);
Element calloutStyleEle = child(themeEle, "callout-style"); //$NON-NLS-1$
if (calloutStyleEle != null)
loadTopicTheme(calloutStyleEle, Styles.FAMILY_CALLOUT_TOPIC, false);
}
private void loadTopicTheme(Element parentEle, String styleFamily,
boolean withChildren) throws InterruptedException {
checkInterrupted();
loadThemeFill(parentEle, IStyle.TOPIC, styleFamily);
loadThemeLineStyle(parentEle, IStyle.TOPIC, styleFamily);
loadThemeShapeStyle(parentEle, IStyle.TOPIC, styleFamily);
loadThemeTextStyle(parentEle, IStyle.TOPIC, styleFamily);
Element childEle = child(parentEle, "children-default-style"); //$NON-NLS-1$
if (withChildren && childEle != null)
loadTopicTheme(childEle, Styles.FAMILY_SUB_TOPIC, false);
}
private void loadThemeFill(Element parentEle, String type,
String styleFamily) throws InterruptedException {
checkInterrupted();
Element fillStyleEle = child(parentEle, "fill-style"); //$NON-NLS-1$
if (fillStyleEle != null) {
String nmColor = getFillValue(fillStyleEle);
if (nmColor != null) {
nmColor = realNmColor(nmColor);
String fillColor = parseColor(nmColor.substring(3));
registerTheme(type, styleFamily, Styles.FillColor, fillColor);
}
}
}
private void loadThemeTextStyle(Element parentEle, String type,
String styleFamily) throws InterruptedException {
checkInterrupted();
Element textEle = child(parentEle, "text-style"); //$NON-NLS-1$
if (textEle == null)
return;
String nmColor = att(textEle, "font-color"); //$NON-NLS-1$
if (nmColor != null) {
nmColor = realNmColor(nmColor);
registerTheme(type, styleFamily, Styles.TextColor,
parseColor(nmColor.substring(3)));
}
registerTheme(type, styleFamily, Styles.FontSize,
parseFontSize(att(textEle, "font-size"))); //$NON-NLS-1$
registerTheme(type, styleFamily, Styles.FontWeight,
Boolean.parseBoolean(att(textEle, "bold")) //$NON-NLS-1$
? Styles.FONT_WEIGHT_BOLD : null);
registerTheme(type, styleFamily, Styles.FontStyle,
Boolean.parseBoolean(att(textEle, "italic")) //$NON-NLS-1$
? Styles.FONT_STYLE_ITALIC : null);
String textDecoration = StyleUtils.toTextDecoration(
att(textEle, "underline-style") != null, //$NON-NLS-1$
att(textEle, "strikethrough-style") != null); //$NON-NLS-1$
registerTheme(type, styleFamily, Styles.TextDecoration, textDecoration);
String alignment = att(textEle, "alignment"); //$NON-NLS-1$
if (alignment != null)
registerTheme(type, styleFamily, Styles.TextAlign,
alignment.toLowerCase());
String fontName = att(textEle, "mac-font-name"); //$NON-NLS-1$
if (fontName == null)
fontName = att(textEle, "windows-font-name"); //$NON-NLS-1$
if (fontName != null) {
String availableFontName = FontUtils
.getAAvailableFontNameFor(fontName);
fontName = availableFontName != null ? availableFontName : fontName;
registerTheme(type, styleFamily, Styles.FontFamily, fontName);
}
}
private void loadThemeLineStyle(Element parentEle, String type,
String styleFamily) throws InterruptedException {
checkInterrupted();
Element lineStyleEle = child(parentEle, "line-style"); //$NON-NLS-1$
if (lineStyleEle == null)
return;
String nmColor = att(lineStyleEle, "color"); //$NON-NLS-1$
if (nmColor != null) {
nmColor = realNmColor(nmColor);
registerTheme(type, styleFamily, Styles.LineColor, nmColor);
}
String width = parseLineWidth(att(lineStyleEle, "stroke-width")); //$NON-NLS-1$
registerTheme(type, styleFamily, Styles.LineWidth, width);
String stroke = att(lineStyleEle, "draws-stroke"); //$NON-NLS-1$
if (Boolean.parseBoolean(stroke))
registerTheme(type, styleFamily, Styles.BorderLineWidth, "0"); //$NON-NLS-1$
String linePattern = att(lineStyleEle, "dash"); //$NON-NLS-1$
registerTheme(type, styleFamily, Styles.LinePattern, linePattern);
}
private void loadThemeShapeStyle(Element parentEle, String type,
String styleFamily) throws InterruptedException {
checkInterrupted();
Element shapeStyleEle = child(parentEle, "shape-style"); //$NON-NLS-1$
if (shapeStyleEle == null)
return;
if (IStyle.TOPIC.equals(type)) {
Element topicShapeEle = child(shapeStyleEle, "topic-shape-style"); //$NON-NLS-1$
if (topicShapeEle != null) {
String shape = att(topicShapeEle, "type"); //$NON-NLS-1$
if (Styles.FAMILY_CALLOUT_TOPIC.equals(styleFamily))
registerTheme(type, styleFamily, Styles.CalloutShapeClass,
parseCalloutShape(shape));
else
registerTheme(type, styleFamily, Styles.ShapeClass,
parseTopicShape(shape));
}
}
if (IStyle.BOUNDARY.equals(type)) {
Element boundaryShapeEle = child(shapeStyleEle,
"boundary-shape-style"); //$NON-NLS-1$
if (boundaryShapeEle != null)
registerTheme(type, styleFamily, Styles.ShapeClass,
parseBoundaryShape(att(boundaryShapeEle, "type"))); //$NON-NLS-1$
}
}
private void loadRelTheme(Element themeEle) throws InterruptedException {
checkInterrupted();
Element relEle = child(themeEle, "link-link-style"); //$NON-NLS-1$
if (relEle == null)
return;
loadThemeLineStyle(relEle, IStyle.RELATIONSHIP,
Styles.FAMILY_RELATIONSHIP);
}
private void loadBoundaryTheme(Element themeEle)
throws InterruptedException {
checkInterrupted();
Element boundaryEle = child(themeEle, "boundary-style-1"); //$NON-NLS-1$
if (boundaryEle == null)
return;
loadThemeShapeStyle(boundaryEle, IStyle.BOUNDARY,
Styles.FAMILY_BOUNDARY);
loadThemeFill(boundaryEle, IStyle.BOUNDARY, Styles.FAMILY_BOUNDARY);
loadThemeLineStyle(boundaryEle, IStyle.BOUNDARY,
Styles.FAMILY_BOUNDARY);
}
private void registerTheme(String type, String styleFamily, String styleKey,
String styleValue) throws InterruptedException {
checkInterrupted();
if (styleFamily == null || styleKey == null || styleValue == null)
return;
if (theme == null) {
theme = getTempStyleSheet().createStyle(IStyle.THEME);
getTempStyleSheet().addStyle(theme, IStyleSheet.MASTER_STYLES);
}
IStyle defaultStyle = theme.getDefaultStyle(styleFamily);
if (defaultStyle == null) {
defaultStyle = getTempStyleSheet().createStyle(type);
getTempStyleSheet().addStyle(defaultStyle,
IStyleSheet.AUTOMATIC_STYLES);
}
defaultStyle.setProperty(styleKey, styleValue);
}
private void generateTheme() throws InterruptedException {
checkInterrupted();
if (theme != null) {
IStyle importedTheme = getTargetWorkbook().getStyleSheet()
.importStyle(theme);
if (importedTheme != null) {
getTargetSheet().setThemeId(importedTheme.getId());
}
}
}
private void recordTopicLink(String OId, ITopic sourceTopic) {
List<ITopic> topics = topicLinkMap.get(OId);
if (topics == null) {
topics = new ArrayList<ITopic>();
topicLinkMap.put(OId, topics);
}
topics.add(sourceTopic);
}
private void setTopicLinks() {
for (Entry<String, List<ITopic>> en : topicLinkMap.entrySet()) {
String Oid = refIdMap.get(en.getKey());
String id = topicIdMap.get(Oid);
if (id != null) {
for (ITopic topic : en.getValue()) {
topic.setHyperlink(HyperlinkUtils.toInternalURL(id));
}
}
}
}
private String getResourceTitle(Element originEle)
throws InterruptedException {
checkInterrupted();
Element resourceEle = findResourceEle(originEle);
if (resourceEle == null)
return null;
return att(resourceEle, "original-filename"); //$NON-NLS-1$
}
private IFileEntry getResourceFileEntry(Element originEle)
throws InterruptedException {
checkInterrupted();
Element resourceEle = findResourceEle(originEle);
if (resourceEle == null)
return null;
String url = att(resourceEle, "url"); //$NON-NLS-1$
String name = att(resourceEle, "original-filename"); //$NON-NLS-1$
if (url != null && !"".equals(url)) //$NON-NLS-1$
return loadAttachment(RESOURCES_FOLDER + url, name);
return null;
}
private Element findResourceEle(Element originEle)
throws InterruptedException {
checkInterrupted();
if (originEle == null)
return null;
String resourceRef = att(originEle, "resource-ref"); //$NON-NLS-1$
if (resourceRef == null || "".equals(resourceRef)) //$NON-NLS-1$
return null;
Element resourceEle = resourceRefMap.get(resourceRef);
if (resourceEle != null)
return resourceEle;
Element resourcesEle = child(manifest.getDocumentElement(),
"resources"); //$NON-NLS-1$
if (resourcesEle == null)
return null;
Iterator<Element> it = children(resourcesEle, "resource"); //$NON-NLS-1$
while (it.hasNext()) {
Element next = it.next();
if (resourceRef.equals(att(next, "id"))) { //$NON-NLS-1$
resourceRefMap.put(resourceRef, next);
return next;
}
}
return null;
}
@SuppressWarnings({ "deprecation", "resource" })
private IFileEntry loadAttachment(String url, String proposalName)
throws InterruptedException {
checkInterrupted();
if (resourceMap.containsKey(url)) {
String path = resourceMap.get(url);
return path == null ? null
: getTargetWorkbook().getManifest().getFileEntry(path);
}
InputStream nmEntryStream = tempSource.getEntryStream(url);
if (nmEntryStream == null)
return null;
if (proposalName != null) {
if (proposalName.startsWith("*.")) { //$NON-NLS-1$
String ext = proposalName.substring(1);
String oldName = new File(url).getName();
proposalName = FileUtils.getNoExtensionFileName(oldName) + ext;
}
}
MonitoredInputStream in = new MonitoredInputStream(nmEntryStream,
getMonitor());
String path = null;
try {
IFileEntry entry = getTargetWorkbook().getManifest()
.createAttachmentFromStream(in, proposalName);
path = entry.getPath();
} catch (Exception e) {
log(e, "Failed to create attachment from: " + url); //$NON-NLS-1$
} finally {
try {
in.close();
} catch (IOException e) {
}
}
resourceMap.put(url, path);
return getTargetWorkbook().getManifest().getFileEntry(path);
}
private static ITopicExtensionElement ensureTaskContent(ITopic topic,
ITopicExtensionElement taskContent) {
if (taskContent != null)
return taskContent;
ITopicExtension ext = topic.createExtension("org.xmind.ui.taskInfo"); //$NON-NLS-1$
return ext.getContent();
}
private Element findThemeEle(String themeRef) throws InterruptedException {
checkInterrupted();
if (themeRef == null || "".equals(themeRef)) //$NON-NLS-1$
return null;
Element themeEle = themeRefMap.get(themeRef);
if (themeEle != null)
return themeEle;
if (styleSheet == null)
return null;
Element styleSheetEle = styleSheet.getDocumentElement();
if (styleSheetEle == null)
return null;
Element themesEle = child(styleSheetEle, "themes"); //$NON-NLS-1$
if (themesEle == null)
return null;
Iterator<Element> it = children(themesEle, "theme"); //$NON-NLS-1$
while (it.hasNext()) {
Element next = it.next();
if (themeRef.equals(att(next, "id"))) { //$NON-NLS-1$
themeRefMap.put(themeRef, next);
return next;
}
}
return null;
}
private String findAssign(String ref) throws InterruptedException {
checkInterrupted();
if (ref == null || "".equals(ref)) //$NON-NLS-1$
return null;
String assign = assignRefMap.get(ref);
if (assign != null)
return assign;
Element contentEle = content.getDocumentElement();
Element resourcesEle = child(contentEle, "project-resources"); //$NON-NLS-1$
if (resourcesEle == null)
return null;
Iterator<Element> it = children(resourcesEle, "project-resource"); //$NON-NLS-1$
while (it.hasNext()) {
Element next = it.next();
if (ref.equals(att(next, "id"))) { //$NON-NLS-1$
String name = att(next, "name"); //$NON-NLS-1$
assignRefMap.put(ref, name);
return name;
}
}
return null;
}
private static Element child(Element parentEle, String childTag) {
return children(parentEle, childTag).next();
}
private static Iterator<Element> children(final Element parentEle,
final String childTag) {
return new Iterator<Element>() {
String tag = DOMUtils.getLocalName(childTag);
Iterator<Element> it = DOMUtils.childElementIter(parentEle);
Element next = findNext();
public void remove() {
}
private Element findNext() {
while (it.hasNext()) {
Element ele = it.next();
if (DOMUtils.getLocalName(ele.getTagName())
.equalsIgnoreCase(tag)) {
return ele;
}
}
return null;
}
public Element next() {
Element result = next;
next = findNext();
return result;
}
public boolean hasNext() {
return next != null;
}
};
}
private static String att(Element ele, String attName) {
if (ele.hasAttribute(attName))
return ele.getAttribute(attName);
attName = DOMUtils.getLocalName(attName);
NamedNodeMap atts = ele.getAttributes();
for (int i = 0; i < atts.getLength(); i++) {
Node att = atts.item(i);
if (attName.equalsIgnoreCase(
DOMUtils.getLocalName(att.getNodeName()))) {
return att.getNodeValue();
}
}
return null;
}
private static int mm2Dots(float mm) {
return (int) (mm * DPM);
}
private static String getMapping(String type, String sourceId,
String defaultId) {
if (sourceId != null) {
String destination = getMappings().getDestination(type, sourceId);
if (destination != null)
return destination;
}
return defaultId;
}
private static ResourceMappingManager getMappings() {
if (mappings == null)
mappings = createMappings();
return mappings;
}
private static ResourceMappingManager createMappings() {
return NovaMindResourceMappingManager.getInstance();
}
private static DocumentBuilder getDocumentBuilder()
throws ParserConfigurationException {
return DOMUtils.getDefaultDocumentBuilder();
}
public void error(SAXParseException exception) throws SAXException {
log(exception, null);
}
public void fatalError(SAXParseException exception) throws SAXException {
log(exception, null);
}
public void warning(SAXParseException exception) throws SAXException {
log(exception, null);
}
}