Example #1
0
 def test_add_nonstring_nodes(self):
     """ Test adding nodes with non-string names.
     """
     g = Graph()
     n = g.add_node(6)
     self.assertEqual(n.ID, "6")
     n = g.add_node(3.14)
     self.assertEqual(n.ID, "3.14")
     self.assertEqual(len(g), 2)
Example #2
0
    def new_model(self, info):
        """ Handles the new Graph action. """

        if info.initialized:
            retval = confirm(parent  = info.ui.control,
                             message = "Replace existing graph?",
                             title   = "New Graph",
                             default = YES)
            if retval == YES:
                self.model = Graph()
Example #3
0
 def test_create(self):
     """ Test creation of a graph.
     """
     g = Graph(name="graph", strict=True, directed=False)
     self.failUnless(g.name == "graph")
     self.assertTrue(g.strict)
     self.assertFalse(g.directed)
Example #4
0
 def init(self, parent):
     """ Finishes initialising the editor by creating the underlying toolkit
         widget.
     """
     self._graph = graph = Graph()
     ui = graph.edit_traits(parent=parent, kind="panel")
     self.control = ui.control
Example #5
0
    def test_add_equal_nodes(self):
        """ Test adding nodes with existing names.
        """
        g = Graph()
        g.add_node("a", label="test1")
        g.add_node("a", fixedsize=True)
        g.add_node("a", label="test2", shape="circle")
        self.assertEqual(len(g), 1)

        n = g.get_node("a")
        self.assertTrue(n.fixedsize)
        self.assertEqual(n.label, "test2")
        self.assertEqual(n.shape, "circle")
Example #6
0
 def test_delete_node(self):
     """ Test removing a node from a graph.
     """
     g = Graph()
     added1 = g.add_node("node1")
     added2 = g.add_node("node2")
     self.assertEqual(len(g.nodes), 2)
     g.delete_node("node1")
     g.delete_node(added2)
     self.assertEqual(len(g.nodes), 0)
Example #7
0
 def test_add_cluster(self):
     """ Test adding clusters to a graph.
     """
     g = Graph()
     cluster = Cluster(ID="cluster0", level=1)
     g.add_cluster(cluster)
     g.add_cluster("cluster1")
     self.assertEqual(len(g.clusters), 2)
Example #8
0
 def test_add_subgraph(self):
     """ Test adding subgraphs to a graph.
     """
     g = Graph()
     subgraph = Subgraph(ID="sub1", level=1)
     g.add_subgraph(subgraph)
     g.add_subgraph("sub2")
     self.assertEqual(len(g.subgraphs), 2)
Example #9
0
 def test_add_node(self):
     """ Test adding nodes to a graph.
     """
     g = Graph()
     g.nodes.append( Node(ID="node1") )
     g.add_node("node2")
     g.add_node( Node("node3") )
     self.assertEqual(len(g), 3)
Example #10
0
    def test_add_edge(self):
        """ Test adding edges to a graph.
        """
        g = Graph()
        n1, n2, n3 = Node("N1"), Node("N2"), Node("N3")
        g.edges.append( Edge(n1, n2) )
        g.add_edge("tail", "head", label="edge1")
        g.add_edge(n2, n3, color="blue")

        self.assertEqual(len(g.edges), 3)
        self.assertEqual(g.edges[1].label, "edge1")
Example #11
0
 def test_create_with_attributes(self):
     """ Test creation of a graph with attributes.
     """
     g = Graph(mode="KK", label="testgraph")
     self.assertEqual(g.mode, "KK")
     self.assertEqual(g.label, "testgraph")
Example #12
0
 def get_content(self, name):
     """ Returns the content for the new resource. Override in subclasses.
     """
     return Graph(name=name)
Example #13
0
class GraphViewModel(ModelView):
    """ Defines a view model for Graphs.  """

    #--------------------------------------------------------------------------
    #  Trait definitions:
    #--------------------------------------------------------------------------

    # File path to to use for saving.
    save_file = File

    # Is the tree view of the network displayed?
    show_tree = Bool(True, desc="that the network tree view is visible")

    # All graphs, subgraphs and clusters.
#    all_graphs = Property(List(Instance(HasTraits)))
    all_graphs = Delegate("model")

    # Select graph when adding to the graph?
    select_graph = Bool(True)

    # Working graph instance.
    selected_graph = Instance(BaseGraph, allow_none=False)

    # Exit confirmation.
    prompt_on_exit = Bool(False, desc="exit confirmation request")

    # Representation of the graph in the Dot language.
    dot_code = Code

    # Parse the dot_code and replace the existing model.
    parse_dot_code = Button("Parse", desc="dot code parsing action that "
        "replaces the existing model.")

    #--------------------------------------------------------------------------
    #  Views:
    #--------------------------------------------------------------------------

    # Default model view.
    traits_view = View(
        HGroup(
            Item(
                name="model", editor=graph_tree_editor,
                show_label=False, id=".tree_editor",
                visible_when="show_tree==True", width=.14
            ),
            Item("model", show_label=False),
        ),
        id="graph_view_model.graph_view", title="Godot", icon=frame_icon,
        resizable=True, style="custom", width=.81, height=.81, kind="live",
        buttons=NoButtons, menubar=menubar,
#        toolbar=toolbar,
        dock="vertical",
#        statusbar=[StatusItem(name="status", width=0.5),
#            StatusItem(name="versions", width=200)]
    )

    # File selection view.
#    file_view = View(
#        Item(name="file", id="file"),#, editor=FileEditor(entries=6)),
#        id="graph_view_model.file_view", title="Select a file",
#        icon=frame_icon, resizable=True, width=.3, kind="livemodal",
#        buttons=OKCancelButtons
#    )

    # Graph selection view.
    all_graphs_view = View(
        Item(name   = "selected_graph",
             editor = InstanceEditor( name     = "all_graphs",
                                      editable = False),
             label  = "Graph"),
        Item("select_graph", label="Always ask?"),
        icon = frame_icon, kind = "livemodal", title = "Select a graph",
        buttons = OKCancelButtons, close_result = False
    )

    # Model view options view.
    options_view = View(
        Item("prompt_on_exit"),
        "_",
        Item("select_graph"),
        Item("selected_graph",
             enabled_when = "not select_graph",
             editor       = InstanceEditor( name     = "all_graphs",
                                            editable = False ),
             label        = "Graph" ),
        icon = frame_icon, kind = "livemodal", title = "Options",
        buttons = OKCancelButtons, close_result = True
    )

    # Text representation of the graph viewed in a text editor
    dot_code_view = View(
        Item("dot_code", show_label=False, style="custom"),
        Item("parse_dot_code", show_label=False),
        id="godot.view_model.dot_code",
        icon = frame_icon, kind = "livemodal",
        title = "Dot Code", resizable = True,
        buttons = [], height = .3, width = .3
    )

    #--------------------------------------------------------------------------
    #  Trait intialisers:
    #--------------------------------------------------------------------------

    def _selected_graph_default(self):
        """ Trait intialiser.
        """
        return self.model


    def _parse_dot_code_fired(self):
        """ Parses the dot_code string and replaces the existing model.
        """
        parser = GodotDataParser()
        graph  = parser.parse_dot_data(self.dot_code)
        if graph is not None:
            self.model = graph

    #--------------------------------------------------------------------------
    #  Event handlers:
    #--------------------------------------------------------------------------

    def _model_changed(self, old, new):
        """ Handles the model changing.
        """
        self.selected_graph = new

    #--------------------------------------------------------------------------
    #  Action handlers:
    #--------------------------------------------------------------------------

    def new_model(self, info):
        """ Handles the new Graph action. """

        if info.initialized:
            retval = confirm(parent  = info.ui.control,
                             message = "Replace existing graph?",
                             title   = "New Graph",
                             default = YES)
            if retval == YES:
                self.model = Graph()


    def open_file(self, info):
        """ Handles the open action. """

        if not info.initialized: return # Escape.

#        retval = self.edit_traits(parent=info.ui.control, view="file_view")

        dlg = FileDialog( action = "open",
            wildcard = "Graphviz Files (*.dot, *.xdot, *.txt)|"
                "*.dot;*.xdot;*.txt|Dot Files (*.dot)|*.dot|"
                "All Files (*.*)|*.*|")

        if dlg.open() == OK:
            parser = GodotDataParser()
            model = parser.parse_dot_file(dlg.path)
            if model is not None:
                self.model = model
            else:
                print "error parsing: %s" % dlg.path

            self.save_file = dlg.path

        del dlg

#            fd = None
#            try:
#                fd = open(self.file, "rb")
#                parser = DotParser()
#                self.model = parser.parse_dot_file(self.file)
##            except:
##                error(parent=info.ui.control, title="Load Error",
##                    message="An error was encountered when loading\nfrom %s"
##                    % self.file)
#            finally:
#                if fd is not None:
#                    fd.close()


    def save(self, info):
        """ Handles saving the current model to the last file.
        """
        save_file = self.save_file

        if not isfile(save_file):
            self.save_as(info)
        else:
            fd = None
            try:
                fd = open(save_file, "wb")
                dot_code = str(self.model)
                fd.write(dot_code)
            finally:
                if fd is not None:
                    fd.close()


    def save_as(self, info):
        """ Handles saving the current model to file.
        """
        if not info.initialized:
            return

#        retval = self.edit_traits(parent=info.ui.control, view="file_view")

        dlg = FileDialog( action = "save as",
            wildcard = "Graphviz Files (*.dot, *.xdot, *.txt)|" \
                "*.dot;*.xdot;*.txt|Dot Files (*.dot)|*.dot|" \
                "All Files (*.*)|*.*|")

        if dlg.open() == OK:
            fd = None
            try:
                fd = open(dlg.path, "wb")
                dot_code = str(self.model)
                fd.write(dot_code)

                self.save_file = dlg.path

            except:
                error(parent=info.ui.control, title="Save Error",
                      message="An error was encountered when saving\nto %s"
                      % self.file)

            finally:
                if fd is not None:
                    fd.close()

        del dlg


    def configure_graph(self, info):
        """ Handles display of the graph dot traits.
        """
        if info.initialized:
            self.model.edit_traits(parent=info.ui.control,
                kind="live", view=attr_view)


    def configure_nodes(self, info):
        """ Handles display of the nodes editor.
        """
        if info.initialized:
            self.model.edit_traits(parent=info.ui.control,
                kind="live", view=nodes_view)


    def configure_edges(self, info):
        """ Handles display of the edges editor.
        """
        if info.initialized:
            self.model.edit_traits(parent=info.ui.control,
                kind="live", view=edges_view)


    def about_godot(self, info):
        """ Handles displaying a view about Godot.
        """
        if info.initialized:
            self.edit_traits(parent=info.ui.control,
                kind="livemodal", view=about_view)


    def add_node(self, info):
        """ Handles adding a Node to the graph.
        """
        if not info.initialized:
            return

        graph = self._request_graph(info.ui.control)

        if graph is None:
            return

        IDs = [v.ID for v in graph.nodes]
        node = Node(ID=make_unique_name("node", IDs))
        graph.nodes.append(node)

        retval = node.edit_traits(parent=info.ui.control, kind="livemodal")

        if not retval.result:
            graph.nodes.remove(node)


    def add_edge(self, info):
        """ Handles adding an Edge to the graph.
        """
        if not info.initialized:
            return

        graph = self._request_graph(info.ui.control)

        if graph is None:
            return

        n_nodes = len(graph.nodes)
        IDs = [v.ID for v in graph.nodes]

        if n_nodes == 0:
            tail_node = Node(ID=make_unique_name("node", IDs))
            head_name = make_unique_name("node", IDs + [tail_node.ID])
            head_node = Node(ID=head_name)
        elif n_nodes == 1:
            tail_node = graph.nodes[0]
            head_node = Node(ID=make_unique_name("node", IDs))
        else:
            tail_node = graph.nodes[0]
            head_node = graph.nodes[1]

        edge = Edge(tail_node, head_node, _nodes=graph.nodes)

        retval = edge.edit_traits(parent=info.ui.control, kind="livemodal")

        if retval.result:
            graph.edges.append(edge)


    def add_subgraph(self, info):
        """ Handles adding a Subgraph to the main graph.
        """
        if not info.initialized:
            return

        graph = self._request_graph(info.ui.control)

        if graph is not None:
            subgraph = Subgraph()#root=graph, parent=graph)
            retval = subgraph.edit_traits(parent = info.ui.control,
                                          kind   = "livemodal")
            if retval.result:
                graph.subgraphs.append(subgraph)


    def add_cluster(self, info):
        """ Handles adding a Cluster to the main graph. """

        if not info.initialized:
            return

        graph = self._request_graph(info.ui.control)

        if graph is not None:
            cluster = Cluster()#root=graph, parent=graph)
            retval = cluster.edit_traits(parent = info.ui.control,
                                         kind   = "livemodal")
            if retval.result:
                graph.clusters.append(cluster)


    def _request_graph(self, parent=None):
        """ Displays a dialog for graph selection if more than one exists.
            Returns None if the dialog is canceled.
        """

        if (len(self.all_graphs) > 1) and (self.select_graph):
            retval = self.edit_traits(parent = parent,
                                      view   = "all_graphs_view")
            if not retval.result:
                return None

        if self.selected_graph is not None:
            return self.selected_graph
        else:
            return self.model


    def toggle_tree(self, info):
        """ Handles displaying the tree view """

        if info.initialized:
            self.show_tree = not self.show_tree


    def godot_options(self, info):
        """ Handles display of the options menu. """

        if info.initialized:
            self.edit_traits( parent = info.ui.control,
                              kind   = "livemodal",
                              view   = "options_view" )


    def configure_dot_code(self, info):
        """ Handles display of the dot code in a text editor.
        """
        if not info.initialized:
            return

        self.dot_code = str(self.model)
        retval = self.edit_traits( parent = info.ui.control,
                                   kind   = "livemodal",
                                   view   = "dot_code_view" )
#        if retval.result:
#            parser = DotParser()
#            graph  = parser.parse_dot_data(self.dot_code)
#            if graph is not None:
#                self.model = graph

    #---------------------------------------------------------------------------
    #  Handle the user attempting to exit Godot:
    #---------------------------------------------------------------------------

    def on_exit(self, info):
        """ Handles the user attempting to exit Godot.
        """
        if self.prompt_on_exit:# and (not is_ok):
            retval = confirm(parent  = info.ui.control,
                             message = "Exit Godot?",
                             title   = "Confirm exit",
                             default = YES)
            if retval == YES:
                self._on_close( info )
        else:
            self._on_close( info )
Example #14
0
            if retval == YES:
                self._on_close( info )
        else:
            self._on_close( info )

#------------------------------------------------------------------------------
#  Stand-alone call:
#------------------------------------------------------------------------------

if __name__ == "__main__":
    import sys
    logger = logging.getLogger()
    logger.addHandler(logging.StreamHandler(sys.stdout))
    logger.setLevel(logging.DEBUG)

    graph = Graph(ID="G")
#    sg1 = Subgraph(ID="SG1")
#    graph.subgraphs.append(sg1)
#    sg2 = Subgraph(ID="SG2")
#    sg1.subgraphs.append(sg2)
#
#    n1 = Node(ID="N1")
#    sg2.nodes = [n1]

    graph.add_node("node1")
    graph.add_node("node2")

    view_model = GraphViewModel(model=graph)
    view_model.configure_traits()

# EOF -------------------------------------------------------------------------