Source

moin-2.0 / MoinMoin / converter / freemind_in.py

# Copyright: 2010 MoinMoin:BerndStolle
# License: GNU GPL v2 (or any later version), see LICENSE.txt for details.

"""
MoinMoin - Freemind converter
Converts a Freemind mindmap into an internal Document tree.
"""

from emeraldtree import ElementTree as ET

from MoinMoin.util.tree import moin_page, xlink, xml, html

from MoinMoin import log
logging = log.getLogger(__name__)

class NameSpaceError(Exception):
    pass

class Converter(object):
    """
    Convert a mindmap to internal representation.
    """

    @classmethod
    def _factory(cls, input, output, **kw):
        return cls()

    def __call__(self, content, aruments=None):
        self.section_depth = 0
        self.heading_level = 0
        self.is_section = False

        self.standard_attribute = {}

        mm_str = u''.join(content)
        logging.debug(mm_str)
        try:
            tree = ET.XML(mm_str.encode('utf-8'))
        except ET.ParseError as detail:
            return self.error(str(detail))

        try:
            result = self.start_dom_tree(tree, 0)
            result.write(logging.info)
            return result
        except NameSpaceError as detail:
            return self.error(str(detail))

    def visit(self, element, depth):
        """
        Function called at each element, to process it.

        It will just determine the namespace of our element,
        then call a dedicated function to handle conversion
        for the given namespace.
        """
        name = element.tag
        if name is not None:
            method_name = 'visit_' + name
            method = getattr(self, method_name, None)
            if method is not None:
                return method(element, depth)

        # We did not recognize the namespace, we stop the conversion.
        raise NameSpaceError("Unknown namespace")

    def visit_map(self, element, depth):
        children = []
        for child in element:
            c = self.visit(child, depth + 1)
            if c:
                if isinstance(c, list):
                    children.extend(c)
                else:
                    children.append(c)
        return children

    def visit_node(self, element, depth):
        text = element.get("TEXT")
        children = []
        body_tag = None
        if text:
            self.is_section = True
            if depth <= 2:
                attrib = {moin_page('outline-level'): depth}
                children.append(self.new(moin_page.h, attrib, children=[text]))
            else:
                body_tag = self.new(moin_page('list-item-body'),
                           attrib={}, children=[text])
                children.append(self.new(moin_page('list-item'), {}, children=[body_tag]))
        listitems = []
        for child in element:
            c = self.visit(child, depth+1)
            if c:
                if isinstance(c, list):
                    listitems.extend(c)
                else:
                    listitems.append(c)
        if len(listitems) > 0:
            if body_tag:
                body_tag.append(self.new(moin_page.list, {moin_page('item-label-generate'): 'unordered'}, children=listitems))
            elif depth+1 > 2:
                children.append(self.new(moin_page.list, {moin_page('item-label-generate'): 'unordered'}, children=listitems))
            else:
                children.extend(listitems)
        return children

    def visit_icon(self, element, depth):
        pass

    def visit_edge(self, element, depth):
        pass

    def visit_font(self, element, depth):
        pass

    def visit_richcontent(self, element, depth):
        pass

    def visit_hook(self, element, depth):
        pass

    def new(self, tag, attrib, children):
        """
        Return a new element for the DocBook Tree.
        """
        if self.standard_attribute:
            attrib.update(self.standard_attribute)
            self.standard_attribute = {}
        return ET.Element(tag, attrib=attrib, children=children)

    def error(self, message):
        """
        Return a DOM Tree containing an error message.
        """
        error = self.new(moin_page('error'), attrib={}, children=[message])
        part = self.new(moin_page('part'), attrib={}, children=[error])
        body = self.new(moin_page('body'), attrib={}, children=[part])
        return self.new(moin_page('page'), attrib={}, children=[body])

    def start_dom_tree(self, element, depth):
        """
        Return the root element of the DOM tree, with all the children.

        We also add a <table-of-content> element if needed.
        """
        attrib = {}
        if self.standard_attribute:
            attrib.update(self.standard_attribute)
            self.standard_attribute = {}
        children = []
        children.extend(self.visit(element, depth))
        # We show the table of content only if it is not empty
        if self.is_section:
            children.insert(0, self.new(moin_page('table-of-content'),
                                    attrib={}, children={}))
        body = self.new(moin_page.body, attrib={}, children=children)
        return self.new(moin_page.page, attrib=attrib, children=[body])


from . import default_registry
from MoinMoin.util.mime import Type, type_moin_document
default_registry.register(Converter._factory, Type('application/x-freemind'), type_moin_document)