Exemple #1
0
def layout_diagram(diag):
    """
    So an attempt to layout (order) the items on a diagram. The items
    should already be placed on the diagram and the items should already be
    connected.

    This function works on the diagram items (hence it does not check relations
    in the datamodel, only the ones drawn on the diagram) to produce a
    decent layout.
    """
    nodes = []
    primary_nodes = []
    relations = []
    other_relations = []

    # Make sure all items are updated
    diag.canvas.update_now()

    # First extract data from the diagram (which ones are the nodes, and
    # the relationships).
    for item in diag.canvas.get_root_items():
        if isinstance(item, (GeneralizationItem, ImplementationItem)):
            # Primary relationships, should be drawn top-down
            try:
                relations.append((item.handles[0].connected_to,
                                  item.handles[-1].connected_to))
                primary_nodes.extend(relations[-1])
            except Exception as e:
                log.error(e)
        elif isinstance(item, DiagramLine):
            # Secondary (associations, dependencies) may be drawn top-down
            # or left-right
            try:
                other_relations.append((item.handles[0].connected_to,
                                        item.handles[-1].connected_to))
                # other_relations.append((item.handles[-1].connected_to,
                #                        item.handles[0].connected_to))
            except Exception as e:
                log.error(e)
        else:
            nodes.append(item)

    # Add some randomness:
    random.shuffle(other_relations)
    primary_nodes = uniq(primary_nodes)

    # Find out our horizontal and vertical sorting
    sorted = toposort.toposort(nodes, relations, 0)
    other_sorted = toposort.toposort(nodes, other_relations, 0)

    if not sorted:
        return

    # Move nodes from the first (generalization) row to the other rows
    # if they are not superclasses for some other class
    # Run the list twice, just to ensure no items are left behind.
    for item in list(sorted[0]) * 2:
        if item not in primary_nodes and item in sorted[0]:
            # Find nodes that do have a relation to this one
            related = find_related_nodes(item, other_relations)
            # Figure out what row(s) they're on
            row = find_row(item, related, sorted[1:])
            if row:
                # print 'moving', item.subject.name, 'to row', sorted.index(row)
                sorted[0].remove(item)
                row.append(item)

    # Order each row based on the sort order of other_sorted
    # (the secondary sort alg.).
    for row in sorted:
        for other_row in other_sorted:
            for other_item in other_row:
                if other_item in row:
                    row.remove(other_item)
                    row.append(other_item)

    # Place the nodes on the diagram.
    y = MARGIN / 2
    for row in sorted:
        x = MARGIN / 2
        maxy = 0
        for item in row:
            if not item:
                continue
            maxy = max(maxy, item.height)
            a = item.matrix
            a = (a[0], a[1], a[2], a[3], x, y)
            item.matrix = a
            item.request_update()
            x += item.width + MARGIN
        y += maxy + MARGIN

    # Reattach the relationships to the nodes, in a way that it looks nice.
    simple_layout_lines(diag)
Exemple #2
0
def layout_diagram(diag):
    """
    So an attempt to layout (order) the items on a diagram. The items
    should already be placed on the diagram and the items should already be
    connected.

    This function works on the diagram items (hence it does not check relations
    in the datamodel, only the ones drawn on the diagram) to produce a
    decent layout.
    """
    nodes = []
    primary_nodes = []
    relations = []
    other_relations = []

    # Make sure all items are updated
    diag.canvas.update_now()

    # First extract data from the diagram (which ones are the nodes, and
    # the relationships).
    for item in diag.canvas.get_root_items():
        if isinstance(item, (items.GeneralizationItem, items.ImplementationItem)):
            # Primary relationships, should be drawn top-down
            try:
                relations.append(
                    (item.handles[0].connected_to, item.handles[-1].connected_to)
                )
                primary_nodes.extend(relations[-1])
            except Exception as e:
                log.error(e)
        elif isinstance(item, items.DiagramLine):
            # Secondary (associations, dependencies) may be drawn top-down
            # or left-right
            try:
                other_relations.append(
                    (item.handles[0].connected_to, item.handles[-1].connected_to)
                )
                # other_relations.append((item.handles[-1].connected_to,
                #                        item.handles[0].connected_to))
            except Exception as e:
                log.error(e)
        else:
            nodes.append(item)

    # Add some randomness:
    random.shuffle(other_relations)
    primary_nodes = uniq(primary_nodes)

    # Find out our horizontal and vertical sorting
    sorted = toposort.toposort(nodes, relations, 0)
    other_sorted = toposort.toposort(nodes, other_relations, 0)

    if not sorted:
        return

    # Move nodes from the first (generalization) row to the other rows
    # if they are not superclasses for some other class
    # Run the list twice, just to ensure no items are left behind.
    for item in list(sorted[0]) * 2:
        if item not in primary_nodes and item in sorted[0]:
            # Find nodes that do have a relation to this one
            related = find_related_nodes(item, other_relations)
            # Figure out what row(s) they're on
            row = find_row(item, related, sorted[1:])
            if row:
                # print 'moving', item.subject.name, 'to row', sorted.index(row)
                sorted[0].remove(item)
                row.append(item)

    # Order each row based on the sort order of other_sorted
    # (the secondary sort alg.).
    for row in sorted:
        for other_row in other_sorted:
            for other_item in other_row:
                if other_item in row:
                    row.remove(other_item)
                    row.append(other_item)

    # Place the nodes on the diagram.
    y = MARGIN / 2
    for row in sorted:
        x = MARGIN / 2
        maxy = 0
        for item in row:
            if not item:
                continue
            maxy = max(maxy, item.height)
            a = item.matrix
            a = (a[0], a[1], a[2], a[3], x, y)
            item.matrix = a
            item.request_update()
            x += item.width + MARGIN
        y += maxy + MARGIN

    # Reattach the relationships to the nodes, in a way that it looks nice.
    simple_layout_lines(diag)