def order_graph(self, ordernodes, unordernodes, request, 
                    pagename, orderby, ordershape=''):
        # Ordering the nodes into ranks. 
        orderkeys = ordernodes.keys()
        orderkeys.sort()

        if orderby != 'gwikicategory':
            orderURL = get_url_ns(request, pagename, orderby)

        prev_ordernode = ''
        # New subgraphs, nodes to help ranking
        for key in orderkeys:
            # Get accurate representation of the key
            label = ''.join(unicode(x) for x in ordervalue(key))

            cur_ordernode = 'orderkey: ' + label
            sg = self.graphviz.subg.add(cur_ordernode, rank='same')

            kw = dict()
            if ordershape:
                if ordershape == 'none':
                    label = ''
                    orderURL = ''
                    kw = {'style': 'invis', 'shape': 'point'}
                else:
                    kw = {'shape': ordershape}

            if orderby != 'gwikicategory':
                sg.nodes.add(cur_ordernode, label=label, URL=orderURL, **kw)
            else:
                sg.nodes.add(cur_ordernode, label=label, 
                             URL=get_url_ns(request, pagename, label), **kw)

            for node in ordernodes[key]:
                sg.nodes.add(node)

            if prev_ordernode:
                self.graphviz.edges.add((prev_ordernode, cur_ordernode),
                                 dir='none', style='invis',
                                 minlen='1', weight='10')
            prev_ordernode = cur_ordernode

        # Unordered nodes to their own rank
        sg = self.graphviz.subg.add('unordered nodes', rank='same')
        sg.nodes.add('unordered nodes', style='invis')
        for node in unordernodes:
            sg.nodes.add(node)
        if prev_ordernode:
            self.graphviz.edges.add((prev_ordernode, 'unordered nodes'),
                                  dir='none', style='invis',
                                  minlen='1', weight='10')

        # Edge minimum lengths
        for edge in self.graph.edges:
            tail, head = edge
            edge = self.graphviz.edges.get(edge)
            taily = getattr(self.graphviz.nodes.get(head), 'order', ('', ''))
            heady = getattr(self.graphviz.nodes.get(tail), 'order', ('', ''))

            # Some values get special treatment
            heady = ordervalue(heady)
            taily = ordervalue(taily)

            # The order attribute is owned by neither, one or
            # both of the end nodes of the edge
            if heady == ('', '') and taily == ('', ''):
                minlen = 0
            elif heady == ('', ''):
                minlen = orderkeys.index(taily) - len(orderkeys)
            elif taily == ('', ''):
                minlen = len(orderkeys) - orderkeys.index(heady)
            else:
                minlen = orderkeys.index(taily) - orderkeys.index(heady)

            # Redraw edge if it goes reverse wrt hierarcy
            if minlen >= 0:
                edge.set(minlen=str(minlen))
            else:
                # If there already is an edge going reverse direction,
                # update it instead of drawing a new edge.
                backedge = self.graphviz.edges.get((head, tail))
                if backedge:
                    backedge.set(minlen=str(-minlen))
                    edge.set(constraint='false')
                else:
                    backedge = self.graphviz.edges.add((head, tail))
                    backedge.set(**dict(edge.__iter__()))
                    backedge.set(**{'dir': 'back', 'minlen': str(-minlen)})
                    edge.delete()
def construct_table(macro,
                    pagelist,
                    metakeys,
                    legend='',
                    checkAccess=True,
                    styles=dict(),
                    addpagename=False):
    request = macro.request
    request.page.formatter = request.formatter
    out = str()

    row = 0

    entryfmt = {'class': 'metamatrix_entry'}

    # Start table
    out += macro.formatter.linebreak() + u'<div class="metamatrix">' + \
        macro.formatter.table(1)

    # Give a class to headers to make it customisable
    out += macro.formatter.table_row(1, {'rowclass': 'meta_head'})
    # Upper left cell is empty or has the desired legend
    out += t_cell(macro, [legend])

    x_key, y_key = metakeys[:2]

    x_values, y_values = set(), set()

    page_vals = dict()

    for page in pagelist:
        page_vals[page] = get_metas(request,
                                    page,
                                    metakeys,
                                    checkAccess=False,
                                    formatLinks=True)

        x_val = page_vals[page].get(x_key, set())
        y_val = page_vals[page].get(y_key, set())
        x_values.update([(page, x) for x in x_val])
        y_values.update([(page, y) for y in y_val])

    metakeys = metakeys[2:]

    header_cells = list()
    # Make header row
    for oval, value, page in sorted(
        (ordervalue(y), y, page) for page, y in y_values):

        style = styles.get(y_key, dict())

        # Styles can modify key naming
        name = style.get('gwikiname', '').strip('"')

        # We don't want stuff like bullet lists in out header
        headerstyle = dict()
        for st in style:
            if not st.startswith('gwiki'):
                headerstyle[st] = style[st]

        if name:
            if not (value, name) in header_cells:
                header_cells.append((value, name))
        else:
            showvalue = metas_to_abs_links(request, page, [value])
            if not (value, showvalue[0]) in header_cells:
                header_cells.append((value, showvalue[0]))

    for value, showvalue in header_cells:
        out += t_cell(macro, [showvalue], style=headerstyle)

    out += macro.formatter.table_row(0)

    tmp_page = request.page

    f = macro.formatter

    # Table
    row_cells = list()
    row_values = list()
    for oval, x_value, page in sorted(
        (ordervalue(x), x, page) for page, x in x_values):
        if not (oval, x_value) in row_values:
            row_cells.append((oval, x_value, page))
            row_values.append((oval, x_value))

    for oval, x_value, page in row_cells:
        row = row + 1

        if row % 2:
            out += f.table_row(1, {'rowclass': 'metamatrix-odd-row'})
        else:
            out += f.table_row(1, {'rowclass': 'metamatrix-even-row'})
        value = metas_to_abs_links(request, page, [x_value])
        out += t_cell(macro, value)

        for y_value, showvalue in header_cells:
            style = styles.get(y_value, dict())

            if not 'class' in style:
                style['class'] = 'meta_cell'

            out += f.table_cell(1, attrs=style)

            for page in pagelist:
                pageobj = Page(request, page)

                if (x_value in page_vals[page].get(x_key, set())
                        and y_value in page_vals[page].get(y_key, set())):

                    result = ''

                    args = {'class': 'metamatrix_link'}

                    for key in metakeys:
                        for val in page_vals[page].get(key, list()):

                            # Strip ugly brackets from bracketed links
                            val = val.lstrip('[').strip(']')

                            result += f.listitem(1, **entryfmt)

                            result += pageobj.link_to(request,
                                                      text=val,
                                                      **args)
                            result += f.listitem(0)

                    if addpagename:
                        result += f.listitem(1, **entryfmt)
                        result += pageobj.link_to(request, **args)
                        result += f.listitem(0)

                    out += result

        out += macro.formatter.table_row(0)

    request.page = tmp_page
    request.formatter.page = tmp_page

    out += macro.formatter.table(0)
    out += u'</div>'

    return out
def construct_table(macro, pagelist, metakeys,
                    legend='', checkAccess=True, styles=dict(),
                    addpagename=False):
    request = macro.request
    request.page.formatter = request.formatter
    out = str()

    row = 0

    entryfmt = {'class': 'metamatrix_entry'}

    # Start table
    out += macro.formatter.linebreak() + u'<div class="metamatrix">' + \
        macro.formatter.table(1)

    # Give a class to headers to make it customisable
    out += macro.formatter.table_row(1, {'rowclass': 'meta_head'})
    # Upper left cell is empty or has the desired legend
    out += t_cell(macro, [legend])

    x_key, y_key = metakeys[:2]

    x_values, y_values = set(), set()

    page_vals = dict()

    for page in pagelist:
        page_vals[page] = get_metas(request, page, metakeys,
                                    checkAccess=False, formatLinks=True)

        x_val = page_vals[page].get(x_key, set())
        y_val = page_vals[page].get(y_key, set())
        x_values.update([(page, x) for x in x_val])
        y_values.update([(page, y) for y in y_val])

    metakeys = metakeys[2:]

    header_cells = list()
    # Make header row
    for oval, value, page in sorted((ordervalue(y), y, page)
                                    for page, y in y_values):

        style = styles.get(y_key, dict())

        # Styles can modify key naming
        name = style.get('gwikiname', '').strip('"')

        # We don't want stuff like bullet lists in out header
        headerstyle = dict()
        for st in style:
            if not st.startswith('gwiki'):
                headerstyle[st] = style[st]

        if name:
            if not (value, name) in header_cells:
                header_cells.append((value, name))
        else:
            showvalue = metas_to_abs_links(request, page, [value])
            if not (value, showvalue[0]) in header_cells:
                header_cells.append((value, showvalue[0]))

    for value, showvalue in header_cells:
        out += t_cell(macro, [showvalue], style=headerstyle)

    out += macro.formatter.table_row(0)

    tmp_page = request.page

    f = macro.formatter

    # Table
    row_cells = list()
    row_values = list()
    for oval, x_value, page in sorted((ordervalue(x), x, page)
                                      for page, x in x_values):
        if not (oval, x_value) in row_values:
            row_cells.append((oval, x_value, page))
            row_values.append((oval, x_value))

    for oval, x_value, page in row_cells:
        row = row + 1

        if row % 2:
            out += f.table_row(1, {'rowclass': 'metamatrix-odd-row'})
        else:
            out += f.table_row(1, {'rowclass': 'metamatrix-even-row'})
        value = metas_to_abs_links(request, page, [x_value])
        out += t_cell(macro, value)

        for y_value, showvalue in header_cells:
            style = styles.get(y_value, dict())

            if not 'class' in style:
                style['class'] = 'meta_cell'

            out += f.table_cell(1, attrs=style)

            for page in pagelist:
                pageobj = Page(request, page)

                if (x_value in page_vals[page].get(x_key, set()) and
                        y_value in page_vals[page].get(y_key, set())):

                    result = ''

                    args = {'class': 'metamatrix_link'}

                    for key in metakeys:
                        for val in page_vals[page].get(key, list()):

                            # Strip ugly brackets from bracketed links
                            val = val.lstrip('[').strip(']')

                            result += f.listitem(1, **entryfmt)

                            result += pageobj.link_to(request,
                                                      text=val, **args)
                            result += f.listitem(0)

                    if addpagename:
                        result += f.listitem(1, **entryfmt)
                        result += pageobj.link_to(request, **args)
                        result += f.listitem(0)

                    out += result

        out += macro.formatter.table_row(0)

    request.page = tmp_page
    request.formatter.page = tmp_page

    out += macro.formatter.table(0)
    out += u'</div>'

    return out