com.igormaznitsa.mindmap.plugins.exporters.MindmupExporter.java Source code

Java tutorial

Introduction

Here is the source code for com.igormaznitsa.mindmap.plugins.exporters.MindmupExporter.java

Source

/*
 * Copyright 2015 Igor Maznitsa.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.igormaznitsa.mindmap.plugins.exporters;

import com.igormaznitsa.mindmap.plugins.api.AbstractExporter;
import com.grack.nanojson.JsonStringWriter;
import com.grack.nanojson.JsonWriter;

import com.igormaznitsa.mindmap.model.Extra;
import com.igormaznitsa.mindmap.model.ExtraFile;
import com.igormaznitsa.mindmap.model.ExtraLink;
import com.igormaznitsa.mindmap.model.ExtraNote;
import com.igormaznitsa.mindmap.model.ExtraTopic;
import com.igormaznitsa.mindmap.model.Topic;
import com.igormaznitsa.mindmap.swing.panel.MindMapPanel;
import com.igormaznitsa.mindmap.swing.panel.MindMapPanelConfig;
import com.igormaznitsa.mindmap.swing.panel.ui.AbstractCollapsableElement;
import com.igormaznitsa.mindmap.swing.panel.utils.Utils;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.swing.Icon;
import javax.swing.JComponent;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringEscapeUtils;

import com.igormaznitsa.meta.annotation.MustNotContainNull;
import com.igormaznitsa.mindmap.swing.panel.Texts;
import com.igormaznitsa.mindmap.swing.panel.utils.MindMapUtils;
import com.igormaznitsa.mindmap.swing.services.IconID;
import com.igormaznitsa.mindmap.swing.services.ImageIconServiceProvider;
import static com.igormaznitsa.meta.common.utils.Assertions.assertNotNull;

public class MindmupExporter extends AbstractExporter {

    private static int idCounter = 1;

    private static class TopicData {

        private final int uid;
        private final int id;
        private final Topic topic;

        public TopicData(final int uid, final int id, @Nonnull final Topic topic) {
            this.uid = uid;
            this.id = id;
            this.topic = topic;
        }

        public int getUID() {
            return this.uid;
        }

        public int getID() {
            return id;
        }

        @Nonnull
        public Topic getTopic() {
            return this.topic;
        }
    }

    private static class State {

        private JsonStringWriter json = JsonWriter.string();
        private final Map<String, TopicData> topicsWithId = new HashMap<String, TopicData>();
        private final List<TopicData> topicsContainsJump = new ArrayList<TopicData>();

        public State() {
        }

        public void processTopic(final int uid, final int id, @Nonnull final Topic topic) {
            final String topicUID = getTopicUid(topic);
            if (topicUID != null) {
                topicsWithId.put(topicUID, new TopicData(uid, id, topic));
            }

            final ExtraTopic linkto = (ExtraTopic) topic.getExtras().get(Extra.ExtraType.TOPIC);
            if (linkto != null) {
                this.topicsContainsJump.add(new TopicData(uid, id, topic));
            }
        }

        @Nonnull
        @MustNotContainNull
        public List<TopicData> getTopicsContainingJump() {
            return this.topicsContainsJump;
        }

        @Nullable
        public TopicData findTopic(@Nonnull final ExtraTopic link) {
            return topicsWithId.get(link.getValue());
        }

        @SuppressWarnings("unchecked")
        @Nonnull
        public State startObj(@Nonnull final String key) {
            this.json = this.json.object(key);
            return this;
        }

        @SuppressWarnings("unchecked")
        @Nonnull
        public State startObj() {
            this.json = this.json.object();
            return this;
        }

        @SuppressWarnings("unchecked")
        @Nonnull
        public State startArray(@Nonnull final String key) {
            this.json = this.json.array(key);
            return this;
        }

        @Nonnull
        public State set(@Nonnull final String key, @Nonnull final String value) {
            this.json.value(key, value);
            return this;
        }

        @Nonnull
        public State set(@Nonnull final String key, final int value) {
            this.json.value(key, value);
            return this;
        }

        @SuppressWarnings("unchecked")
        @Nonnull
        public State end() {
            this.json = json.end();
            return this;
        }

        @Override
        @Nonnull
        public String toString() {
            return json.done();
        }
    }

    private static final Icon ICO = ImageIconServiceProvider.findInstance()
            .getIconForId(IconID.POPUP_EXPORT_MINDMUP);

    @Nullable
    private static String getTopicUid(@Nonnull final Topic topic) {
        return topic.getAttribute(ExtraTopic.TOPIC_UID_ATTR);
    }

    private int writeTopic(@Nonnull final State state, int id, @Nonnull final MindMapPanelConfig cfg,
            @Nonnull final Topic topic) {
        state.startObj(Integer.toString(idCounter));

        state.processTopic(idCounter, id, topic);

        idCounter++;

        state.set("title", topic.getText()); //NOI18N
        state.set("id", id); //NOI18N

        id = Math.abs(id);

        state.startObj("ideas"); //NOI18N
        for (final Topic t : topic.getChildren()) {
            id = writeTopic(state, id + 1, cfg, t);
        }
        state.end();

        state.startObj("attr"); //NOI18N
        state.startObj("style")
                .set("background",
                        assertNotNull(Utils.color2html(MindMapUtils.getBackgroundColor(cfg, topic), false)))
                .set("color", assertNotNull(Utils.color2html(MindMapUtils.getTextColor(cfg, topic), false))).end(); //NOI18N

        final String attachment = makeHtmlFromExtras(topic);
        if (attachment != null) {
            state.startObj("attachment"); //NOI18N
            state.set("contentType", "text/html"); //NOI18N
            state.set("content", attachment); //NOI18N
            state.end();
        }

        state.end();
        state.end();

        return id;
    }

    @Nullable
    private static String makeHtmlFromExtras(@Nonnull final Topic topic) {
        final ExtraFile file = (ExtraFile) topic.getExtras().get(Extra.ExtraType.FILE);
        final ExtraNote note = (ExtraNote) topic.getExtras().get(Extra.ExtraType.NOTE);
        final ExtraLink link = (ExtraLink) topic.getExtras().get(Extra.ExtraType.LINK);

        if (file == null && link == null && note == null) {
            return null;
        }

        final StringBuilder result = new StringBuilder();

        if (file != null) {
            final String uri = file.getValue().asString(true, false);
            result.append("FILE: <a href=\"").append(uri).append("\">").append(uri).append("</a><br>"); //NOI18N
        }
        if (link != null) {
            final String uri = link.getValue().asString(true, true);
            result.append("LINK: <a href=\"").append(uri).append("\">").append(uri).append("</a><br>"); //NOI18N
        }
        if (note != null) {
            if (file != null || link != null) {
                result.append("<br>"); //NOI18N
            }
            result.append("<pre>").append(StringEscapeUtils.escapeHtml(note.getValue())).append("</pre>"); //NOI18N
        }
        return result.toString();
    }

    private void writeRoot(@Nonnull final State state, @Nonnull final MindMapPanelConfig cfg,
            @Nullable final Topic root) {
        state.startObj();

        if (root == null) {
            state.set("title", ""); //NOI18N
        } else {
            state.set("title", root.getText()); //NOI18N
        }
        state.set("id", 1); //NOI18N
        state.set("formatVersion", 2); //NOI18N

        final List<Topic> leftChildren = new ArrayList<Topic>();
        final List<Topic> rightChildren = new ArrayList<Topic>();

        if (root != null) {
            for (final Topic t : root.getChildren()) {
                if (AbstractCollapsableElement.isLeftSidedTopic(t)) {
                    leftChildren.add(t);
                } else {
                    rightChildren.add(t);
                }
            }
        }
        state.startObj("ideas"); //NOI18N

        if (root != null) {
            state.processTopic(0, 1, root);
        }

        int id = 2;
        for (final Topic right : rightChildren) {
            id = writeTopic(state, id + 1, cfg, right);
        }

        for (final Topic left : leftChildren) {
            id = writeTopic(state, -(id + 1), cfg, left);
        }

        state.end();

        if (root != null) {
            state.startObj("attr"); //NOI18N
            state.startObj("style")
                    .set("background",
                            assertNotNull(Utils.color2html(MindMapUtils.getBackgroundColor(cfg, root), false)))//NOI18N
                    .set("color", assertNotNull(Utils.color2html(MindMapUtils.getTextColor(cfg, root), false)))//NOI18N
                    .end(); //NOI18N
        }

        final String attachment = root == null ? null : makeHtmlFromExtras(root);
        if (attachment != null) {
            state.startObj("attachment"); //NOI18N
            state.set("contentType", "text/html"); //NOI18N
            state.set("content", attachment); //NOI18N
            state.end();
        }
        state.end();

        final List<TopicData> topicsWithJumps = state.getTopicsContainingJump();
        if (!topicsWithJumps.isEmpty()) {
            state.startArray("links"); //NOI18N
            for (final TopicData src : topicsWithJumps) {
                final TopicData dest = state
                        .findTopic((ExtraTopic) src.getTopic().getExtras().get(Extra.ExtraType.TOPIC));
                if (dest != null) {
                    state.startObj(); //NOI18N
                    state.set("ideaIdFrom", src.getID()); //NOI18N
                    state.set("ideaIdTo", dest.getID()); //NOI18N
                    state.startObj("attr").startObj("style").set("color", "#FF0000").set("lineStyle", "dashed")
                            .end().end(); //NOI18N
                    state.end();
                }
            }
            state.end();
        }

        if (root != null)
            state.end();
    }

    @Override
    public void doExport(@Nonnull final MindMapPanel panel, @Nullable final JComponent options,
            @Nullable final OutputStream out) throws IOException {
        final State state = new State();

        writeRoot(state, panel.getConfiguration(), panel.getModel().getRoot());

        final String text = state.toString();

        File fileToSaveMap = null;
        OutputStream theOut = out;
        if (theOut == null) {
            fileToSaveMap = MindMapUtils.selectFileToSaveForFileFilter(panel,
                    Texts.getString("MindmupExporter.saveDialogTitle"), ".mup",
                    Texts.getString("MindmupExporter.filterDescription"),
                    Texts.getString("MindmupExporter.approveButtonText"));
            fileToSaveMap = MindMapUtils.checkFileAndExtension(panel, fileToSaveMap, ".mup");//NOI18N
            theOut = fileToSaveMap == null ? null
                    : new BufferedOutputStream(new FileOutputStream(fileToSaveMap, false));
        }
        if (theOut != null) {
            try {
                IOUtils.write(text, theOut, "UTF-8");
            } finally {
                if (fileToSaveMap != null) {
                    IOUtils.closeQuietly(theOut);
                }
            }
        }
    }

    @Override
    @Nonnull
    public String getName(@Nonnull final MindMapPanel panel, @Nullable Topic actionTopic,
            @Nonnull @MustNotContainNull Topic[] selectedTopics) {
        return Texts.getString("MindmupExporter.exporterName");
    }

    @Override
    @Nonnull
    public String getReference(@Nonnull final MindMapPanel panel, @Nullable Topic actionTopic,
            @Nonnull @MustNotContainNull Topic[] selectedTopics) {
        return Texts.getString("MindmupExporter.exporterReference");
    }

    @Override
    @Nonnull
    public Icon getIcon(@Nonnull final MindMapPanel panel, @Nullable Topic actionTopic,
            @Nonnull @MustNotContainNull Topic[] selectedTopics) {
        return ICO;
    }

    @Override
    public int getOrder() {
        return 2;
    }

}