How to change a NodeView to show a custom view for a node? I (MarcioSilva) have only a part of the answer. :-)

Here some discussions about my experiences with this and the problems I found. Feel free to add more information to this page.

I started my hack using as a base, the PetalNode from the MDNodes plugin.

Then I started to make my modifications in the drawNodeView() method. I tried to use the PPath class, but I could not find a way to draw arcs of circles with it. Then I overrrided the paint() method from PPath, like this:

   1 PPath n = new PPath() {
   2     public void paint(PPaintContext aPaintContext) {
   3 
   4         Arc2D.Double arc = new Arc2D.Double();
   5         arc.setArcByCenter(0,0,40,0,300,Arc2D.PIE);
   6         Graphics2D g2 = aPaintContext.getGraphics();
   7 
   8         g2.setPaint(Color.red);
   9         g2.fill(arc);
  10     }
  11 };
  12 

Then I had trouble selecting nodes that have the new shape. This was fixed with this modification in the selected() method:

   1 public void select() {
   2     selected = true;
   3     nodeView.setSelected(true); // added by mrsva
   4     drawSelected();
   5 }
   6 

and with the use of setPathToEllipse() and setBounds() in the drawNodeView() method.

also the context menu doesn't work in the nodes with the changed shape. I tried to change:

   1 view.addContextMethod( "class phoebe.PNodeView",                      // <-- changed line
   2                        "csplugins.mrsva.metadata.MDMenus",
   3                        "getMetaDataMenu",
   4                         new Object[] { view } ,
   5                         CytoscapeInit.getClassLoader() );
   6 

to:

   1 view.addContextMethod( "class csplugins.mrsva.metadata.PieChartNode", // <-- changed line
   2                        "csplugins.mrsva.metadata.MDMenus",
   3                        "getMetaDataMenu",
   4                         new Object[] { view } ,
   5                         CytoscapeInit.getClassLoader() ); 
   6 

but this didn't helped.

Another problem, which affects the use of custom node views with the MetaNodes plugin, is that Cytoscape raises an exception when one tries to remove a node with the custom node view.

When I tried to remove such nodes (with custom view), I received the following exception:

 java.lang.ClassCastException
        at phoebe.PGraphView.removeNodeView(PGraphView.java:1166)
        at cytoscape.view.BasicGraphViewHandler.removeGraphViewNodes(BasicGraphViewHandler.java:388)
        at cytoscape.view.BasicGraphViewHandler.handleGraphPerspectiveEvent(BasicGraphViewHandler.java:76)
        at cytoscape.view.GraphViewController.graphPerspectiveChanged(GraphViewController.java:403)
        at fing.model.GraphPerspectiveChangeListenerChain.graphPerspectiveChanged(GraphPerspectiveChangeListenerChain.java:38)
        at fing.model.FGraphPerspective$GraphWeeder.hideNode(FGraphPerspective.java:1180)
        at fing.model.FGraphPerspective$GraphWeeder.access$300(FGraphPerspective.java:1133)
        at fing.model.FGraphPerspective.hideNode(FGraphPerspective.java:230)
        at metaNodeViewer.model.AbstractMetaNodeModeler.undoModel(AbstractMetaNodeModeler.java:600)
        at metaNodeViewer.MetaNodeUtils.uncollapseNodes(MetaNodeUtils.java:196)
        at metaNodeViewer.actions.UncollapseSelectedNodesAction.uncollapseSelectedNodes(UncollapseSelectedNodesAction.java:126)
        at metaNodeViewer.actions.UncollapseSelectedNodesAction.actionPerformed(UncollapseSelectedNodesAction.java:88)
        at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1786)
        at javax.swing.AbstractButton$ForwardActionEvents.actionPerformed(AbstractButton.java:1839)
        at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:420)
        at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:258)
        at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:245)
        at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:231)
        at java.awt.Component.processMouseEvent(Component.java:5100)
        at java.awt.Component.processEvent(Component.java:4897)
        at java.awt.Container.processEvent(Container.java:1569)
        at java.awt.Component.dispatchEventImpl(Component.java:3615)
        at java.awt.Container.dispatchEventImpl(Container.java:1627)
        at java.awt.Component.dispatchEvent(Component.java:3477)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:3483)
        at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3198)
        at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3128)
        at java.awt.Container.dispatchEventImpl(Container.java:1613)
        at java.awt.Window.dispatchEventImpl(Window.java:1606)
        at java.awt.Component.dispatchEvent(Component.java:3477)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:456)
        at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:201)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:145)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:137)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:100)

I am not sure what that means, but looking at the method on the top of the list (phoebe.PGraphView.removeNodeView) I found that there is a cast to (PNodeView):

PNodeView node_view = ( PNodeView )getNodeView( node );

Shouldn't this be

NodeView node_view = ( NodeView )getNodeView( node );

as NodeView is the interface implemented by PNodeView (and by my PieChartNode)? Shouldn't we use the interface in such cases? If PNodeView is right here, how one can define other node views and remove them?

Then, in the case that the correct cast is NodeView, NodeView should have the interface for removeFromParent(). Here the complete code of phoebe.PGraphView.removeNodeView to explain why:

   1 public NodeView removeNodeView ( int node ) {
   2     PNodeView node_view = ( PNodeView )getNodeView( node );
   3     try {
   4       node_view.removeFromParent();
   5     } catch ( Exception e ) {
   6       System.out.println( "GINY at PGraphView.removeNodeView(int): Parent was most likely null for: "+node);
   7       return null;
   8     }
   9     nodeViewMap.removeKey( perspective.getRootGraphNodeIndex( node_view.getGraphPerspectiveIndex() ) );
  10     ensureNodeSelectionCapacity();
  11     nodeSelectionList.setQuick( node_view.getGraphPerspectiveIndex(), 0 );
  12     return node_view;
  13   }
  14 

so, node_view should have the method removeFromParent().

Here is the signature of my class (I didn't changed it from the PetalNode class):

   1 public class PieChartNode extends PPath
   2                           implements NodeView,
   3                                      PropertyChangeListener {
   4 

and PPath extends PNode.

Then I tried to modify phoebe and NodeView to test my theory. But when I load the sources of phoebe some methods are not recognized well. For example in the file phoebe.PGraphView, there is a call to edu.umd.cs.piccolo.PNode.firePropertyChange() but seems to be a difference in the signature of this method in PGraphView and in Piccolo. My guess is that a different version of Piccolo was used in the development of Phoebe and I got the version 1.1 of Piccolo website. Which version of Piccolo was used in the development of Phoebe?

Here the error I receive:

"The method firePropertyChange(int, String, Object, Object) in the type
  PNode is not applicable for the arguments (String, null, List)"

in this line:

   1 if ( firePiccoloEvents )
   2     firePropertyChange(PROPERTY_CHILDREN, null, getChildrenReference() ); 
   3 

Any ideas/discussion? Please, add your experience to this page.

MarcioSilva

ChangingNodeView (last edited 2009-02-12 01:03:51 by localhost)

MoinMoin Appliance - Powered by TurnKey Linux