Author: clopes
Date: 2011-10-12 14:53:07 -0700 (Wed, 12 Oct 2011)
New Revision: 27146

Modified:
   cytoscapeweb/branches/compound/html-template/js/compound.js
   cytoscapeweb/branches/compound/html-template/js/cytoscapeweb.js
   cytoscapeweb/branches/compound/html-template/sample.html
   cytoscapeweb/branches/compound/src/org/cytoscapeweb/model/GraphProxy.as
   
cytoscapeweb/branches/compound/src/org/cytoscapeweb/model/converters/XGMMLConverter.as
   cytoscapeweb/branches/compound/src/org/cytoscapeweb/util/CompoundNodes.as
   cytoscapeweb/branches/compound/src/org/cytoscapeweb/view/ExternalMediator.as
   cytoscapeweb/branches/compound/src/org/cytoscapeweb/view/GraphMediator.as
   
cytoscapeweb/branches/compound/src/org/cytoscapeweb/vis/data/CompoundNodeSprite.as
Log:
Added verification for circular references between child and parent nodes when 
adding new elements.
JS API: Removed parentId parameter from addNode()--using data.parent instead.
Auto initializing compound node when adding a child, if it is not already 
initialized.
GraphMediator no longer initializes a compound node when updating it, in order 
to prevent event listeners from being added twice (a compound node is 
initialized as a regular node before being updated as compound anyway).

Modified: cytoscapeweb/branches/compound/html-template/js/compound.js
===================================================================
--- cytoscapeweb/branches/compound/html-template/js/compound.js 2011-10-12 
21:17:32 UTC (rev 27145)
+++ cytoscapeweb/branches/compound/html-template/js/compound.js 2011-10-12 
21:53:07 UTC (rev 27146)
@@ -55,8 +55,8 @@
         nodes: {
                // regular nodes
                size: 40,
-               color: "#8a1b0b",
-               image: "http://www.cs.bilkent.edu.tr/~ssumer/cw/cw-logo.png";,
+               color: "#dafbab",
+               //image: "http://www.cs.bilkent.edu.tr/~ssumer/cw/cw-logo.png";,
                // compound nodes
                /*
                compoundPaddingLeft: 20,
@@ -68,7 +68,7 @@
                compoundLabelFontSize: 15,
                compoundLabelVerticalAnchor: "bottom"
                */
-               compoundImage: 
"http://www.cs.bilkent.edu.tr/~ivis/images/ivis-logo.png";,
+               //compoundImage: 
"http://www.cs.bilkent.edu.tr/~ivis/images/ivis-logo.png";,
                compoundPaddingLeft: 10,
                compoundPaddingRight: 10,
                compoundPaddingTop: 10,

Modified: cytoscapeweb/branches/compound/html-template/js/cytoscapeweb.js
===================================================================
--- cytoscapeweb/branches/compound/html-template/js/cytoscapeweb.js     
2011-10-12 21:17:32 UTC (rev 27145)
+++ cytoscapeweb/branches/compound/html-template/js/cytoscapeweb.js     
2011-10-12 21:53:07 UTC (rev 27146)
@@ -704,6 +704,7 @@
         
         /**
          * <p>Create a new node and add it to the network view.<p>
+         * <p>You can also add a node as a child of another node, by setting 
the parent node ID to the "parent" data attribute.<p>
          * <p>If the node <code>id</code> is not specified, Cytoscape Web 
creates a new one automatically.</p>
          * <p>If the data contains attributes that have not been previously 
defined in the {@link org.cytoscapeweb.DataSchema},
          * Cytoscape Web will throw an error. To prevent that, you simply add 
the new fields to the schema first, 
@@ -711,16 +712,19 @@
          * <p>Keep in mind that {@link 
org.cytoscapeweb.Visualization#addElements} is much faster if you have to
          * add more than one element at once.</p>
          * @example
+         * // 1. Add a new node to the network (here we assume that the data 
fields for
+         * // "label" and "weight" already exists in the node schema):
          * var data = { id: "n4",
          *              label: "MYO2 (Yeast)",
          *              weight: 0.54 };
+         * var node1 = vis.addNode(240, 360, data, true);
          * 
-         * var node = vis.addNode(240, 360, data, true);
-         * 
+         * // 2. Add a new node as a child of another (compound) node:
+         * var node2 = vis.addNode(node1.x, node1.y, { parent: "n4" }, true);
+         *
          * @param {Object} x The horizontal coordinate of the node.
          * @param {Object} y The vertical coordinate of the node.
          * @param {Object} [data] The object that contains the node attributes.
-         * @param {Object} [parentId] Optional parent node's ID. 
          * @param {Boolean} [updateVisualMappers] It tells Cytoscape Web to 
update and reapply the visual mappers
          *                                        to the network view after 
adding the node.
          *                                        The default value is 
<code>false</code>.
@@ -729,7 +733,7 @@
          * @see org.cytoscapeweb.Visualization#addElements
          * @see org.cytoscapeweb.Visualization#removeElements
          */
-        addNode: function (x, y/*, data, parentId, updateVisualMappers*/) {
+        addNode: function (x, y/*, data, updateVisualMappers*/) {
             var data;
             var updateVisualMappers = false;
             var parentId = null;
@@ -737,12 +741,10 @@
             if (arguments.length > i && (typeof arguments[i] === "object" || 
arguments[i] == null)) {
                data = arguments[i++];
             }
-            if (arguments.length > i && (typeof arguments[i] === "string" || 
arguments[i] == null)) {
-               parentId = arguments[i++];
+            if (arguments.length > i && typeof arguments[i] === "boolean") {
+               updateVisualMappers = arguments[i++];
             }
-            if (arguments.length > i && typeof arguments[i] === "boolean") { 
updateVisualMappers = arguments[i++]; }
-            
-            var n = this.swf().addNode(x, y, data, parentId, 
updateVisualMappers);
+            var n = this.swf().addNode(x, y, data, updateVisualMappers);
             return this._parseJSON(n);
         },
          
@@ -2481,7 +2483,8 @@
      *     <li><code>Circle</code></li>
      *     <li><code>Radial</code></li>
      *     <li><code>Tree</code></li>
-     *     <li><code>Preset</code></li></ul>
+     *     <li><code>Preset</code></li>
+     *     <li><code>CompoundSpringEmbedder</code>: use this option when the 
network is a compound graph</li></ul>
      * @property
      * @name name
      * @type String

Modified: cytoscapeweb/branches/compound/html-template/sample.html
===================================================================
--- cytoscapeweb/branches/compound/html-template/sample.html    2011-10-12 
21:17:32 UTC (rev 27145)
+++ cytoscapeweb/branches/compound/html-template/sample.html    2011-10-12 
21:53:07 UTC (rev 27146)
@@ -34,7 +34,7 @@
                         //size: "auto",//{ defaultValue: 20, continuousMapper: 
{ attrName: "weight",  minValue: 20, maxValue: 40 } },
                         borderWidth: 2,
                         borderColor: "#707070",
-                        //image: 
"http://chart.apis.google.com/chart?chs=300x300&cht=p&chd=e0:U-gh..bR";,
+                        image: 
"http://chart.apis.google.com/chart?chs=300x300&cht=p&chd=e0:U-gh..bR";,
                         //compoundImage: 
"http://chart.apis.google.com/chart?chxr=0,0,160&chxt=x&chbh=a&chs=440x220&cht=bhs&chco=4D89F9,C6D9FD&chd=s:GflxYlS,fl9YSYS";,
                         labelFontSize: { defaultValue: 12, continuousMapper: { 
attrName: "weight",  minValue: 10, maxValue: 24 } },
                         tooltipText: { customMapper: { functionName: 
"onNodeTooltip" } },
@@ -116,6 +116,7 @@
                 
                 vis.ready(function() {
                     showElapsedTime();
+
                     var layout = vis.layout();
                     $("#layouts").val(layout.name);
                     $("input, select").attr("disabled", false);
@@ -141,7 +142,7 @@
                             x += Math.random() * (evt.target.width/2) * 
(Math.round(x)%2==0 ? 1 : -1);
                             y += Math.random() * (evt.target.height/2) * 
(Math.round(y)%2==0 ? 1 : -1);
                         }
-                        var n = vis.addNode(x, y, { weight: Math.random(), 
label: "NEW" }, parentId, true);
+                        var n = vis.addNode(x, y, { weight: Math.random(), 
label: "NEW", parent: parentId }, true);
                     })
                     .addContextMenuItem("Add new edge", "nodes", function(evt) 
{
                        _srcId = evt.target.data.id;

Modified: 
cytoscapeweb/branches/compound/src/org/cytoscapeweb/model/GraphProxy.as
===================================================================
--- cytoscapeweb/branches/compound/src/org/cytoscapeweb/model/GraphProxy.as     
2011-10-12 21:17:32 UTC (rev 27145)
+++ cytoscapeweb/branches/compound/src/org/cytoscapeweb/model/GraphProxy.as     
2011-10-12 21:53:07 UTC (rev 27146)
@@ -59,9 +59,9 @@
        import org.cytoscapeweb.model.data.InteractionVO;
        import org.cytoscapeweb.model.data.VisualStyleVO;
        import org.cytoscapeweb.model.error.CWError;
+       import org.cytoscapeweb.util.CompoundNodes;
        import org.cytoscapeweb.util.ErrorCodes;
        import org.cytoscapeweb.util.GraphUtils;
-       import org.cytoscapeweb.util.CompoundNodes;
        import org.cytoscapeweb.util.Groups;
        import org.cytoscapeweb.util.Layouts;
        import org.cytoscapeweb.vis.data.CompoundNodeSprite;
@@ -676,17 +676,10 @@
                        }
                        
                        normalizeData(data, Groups.NODES);
+            var cns:CompoundNodeSprite = new CompoundNodeSprite();
                        
-                       // create a new CompoundNodeSprite
-                       var cns:CompoundNodeSprite = new CompoundNodeSprite();
-                       
                        if (data != null) {
                                cns.data = data;
-                               
-                               // init the CompoundNodeSprite if it has a 
network field
-                               if (data.network != null) {
-                                       cns.initialize();
-                               }
                        }
                                                
                        // and newly created CompoundNodeSprite to the graph 
data, but do
@@ -702,6 +695,22 @@
                        return cns;
                }
                
+               public function addToParent(ns:NodeSprite, 
parent:CompoundNodeSprite):void {
+              var group:DataList = this.graphData.group(Groups.COMPOUND_NODES);
+            
+            // initialize the compound node if it is not initialized,
+            // yet. Also, add the compound to the compound node data group
+            if (!parent.isInitialized()) {
+                // initialize child node list
+                parent.initialize();
+                // add to the data group
+                group.add(parent);
+            }
+            
+            // add node into the target compound node
+            parent.addNode(ns);
+               }
+               
                /**
                 * Resets the missing children array in order to enable 
re-calculation
                 * of missing child nodes in the getter method of 
missingChildren.

Modified: 
cytoscapeweb/branches/compound/src/org/cytoscapeweb/model/converters/XGMMLConverter.as
===================================================================
--- 
cytoscapeweb/branches/compound/src/org/cytoscapeweb/model/converters/XGMMLConverter.as
      2011-10-12 21:17:32 UTC (rev 27145)
+++ 
cytoscapeweb/branches/compound/src/org/cytoscapeweb/model/converters/XGMMLConverter.as
      2011-10-12 21:53:07 UTC (rev 27146)
@@ -523,23 +523,24 @@
         private function parseData(tag:XML, schema:DataSchema):Object {
             var data:Object = {};
             var name:String, field:DataField, value:Object;
+            var i:int, att:XML;
             
             // set default values
-            for (var i:int = 0; i < schema.numFields; ++i) {
+            for (i = 0; i < schema.numFields; ++i) {
                 field = schema.getFieldAt(i);
                 data[field.name] = field.defaultValue;
             }
             
             // get attribute values
-            for each (var attribute:XML in tag.@*) {
-                name = attribute.name().toString();
+            for each (att in tag.@*) {
+                name = att.name().toString();
                 field = schema.getFieldByName(name);
                 if (field != null)
-                    data[name] = parseAttValue(attribute[0].toString(), 
field.type);
+                    data[name] = parseAttValue(att[0].toString(), field.type);
             }
             
             // get "att" tags:
-            for each (var att:XML in tag.att) {
+            for each (att in tag.att) {
                parseAtt(att, schema, data);
             }
             

Modified: 
cytoscapeweb/branches/compound/src/org/cytoscapeweb/util/CompoundNodes.as
===================================================================
--- cytoscapeweb/branches/compound/src/org/cytoscapeweb/util/CompoundNodes.as   
2011-10-12 21:17:32 UTC (rev 27145)
+++ cytoscapeweb/branches/compound/src/org/cytoscapeweb/util/CompoundNodes.as   
2011-10-12 21:53:07 UTC (rev 27146)
@@ -400,7 +400,6 @@
                        if (ns != null) {
                                parentId = ns.data.parent;
                                
-                               //for each (var ns:NodeSprite in cns.getNodes())
                                while (parentId != null) {
                                        // get parent
                                        parent = graphProxy.getNode(parentId);
@@ -424,8 +423,12 @@
                                                parents.push(parent);
                                        }
                                        
-                                       // advance to next node
-                                       parentId = parent.data.parent;
+                                       // advance to next node (avoid circular 
dependencies)
+                                       if (parent.data.parent !== ns.data.id) {
+                        parentId = parent.data.parent;
+                                       } else {
+                                           parentId = null;
+                                       }
                                }
                        }
                        

Modified: 
cytoscapeweb/branches/compound/src/org/cytoscapeweb/view/ExternalMediator.as
===================================================================
--- 
cytoscapeweb/branches/compound/src/org/cytoscapeweb/view/ExternalMediator.as    
    2011-10-12 21:17:32 UTC (rev 27145)
+++ 
cytoscapeweb/branches/compound/src/org/cytoscapeweb/view/ExternalMediator.as    
    2011-10-12 21:53:07 UTC (rev 27146)
@@ -400,11 +400,10 @@
                                                newElement.y = p.y;
                                                
                                                // check if current node will 
be added into a compound
-                                               if (o.parent != null) {
+                                               if (o.data != null && 
o.data.parent) {
                                                        // hold a reference for 
the new created sprite
                                                        // for fast access 
during compound node update
                                                        o.sprite = newElement;
-                                                       
                                                        // add to the list of 
child nodes to be added 
                                                        childrenToAdd.push(o);
                                                }
@@ -425,16 +424,20 @@
                                        newAll.push(newElement);
                                }
                                
+                               // process child nodes to add, and update 
corresponding parent compound nodes
+                               for each (o in childrenToAdd) {
+                                       parent = 
this.graphProxy.getNode(o.data.parent);
+                                       this.graphProxy.addToParent(o.sprite, 
parent);
+                               }
+                               
                                // Set listeners, styles, etc:
-                               graphMediator.initialize(Groups.NODES, 
newNodes);
-                               graphMediator.initialize(Groups.EDGES, 
newEdges);
+                graphMediator.initialize(Groups.NODES, newNodes);
+                graphMediator.initialize(Groups.EDGES, newEdges);
                                
-                               // process child nodes to add, and update 
corresponding parent
-                               // compound nodes
                                for each (o in childrenToAdd) {
-                                       parent = 
this.graphProxy.getNode(o.parent);
-                                       
this.graphMediator.updateCompoundNode(parent, o.sprite);
-                               }
+                    parent = this.graphProxy.getNode(o.data.parent);
+                    this.graphMediator.updateCompoundNode(parent, o.sprite);
+                }
                                
                                // Do it before converting the Nodes/Edges to 
plain objects,
                                // in order to get the rendered visual 
properties:
@@ -459,9 +462,12 @@
                        return JSON.encode(ret);
                }
                
-               private function addNode(x:Number, y:Number, data:Object,
-                                        parentId:String=null, 
updateVisualMappers:Boolean=false):String {
+               private function addNode(x:Number,
+                                        y:Number,
+                                        data:Object,
+                                        
updateVisualMappers:Boolean=false):String {
                        var extObj:Object = null;
+                       var parentId:String = data != null ? data.parent : null;
                        
                        try {
                                // create node (always create a CompoundNode 
instance)
@@ -476,8 +482,8 @@
                                
                                // set listeners, styles, etc.
                                if (ns.isInitialized()) {
-                                       // initialize the node as a compound 
node
-                                       
this.graphMediator.initialize(Groups.COMPOUND_NODES, [ns]);
+//                                     // initialize the node as a compound 
node
+//                                     
this.graphMediator.initialize(Groups.COMPOUND_NODES, [ns]);
                                } else {
                                        // initialize the node as a 
non-compound node
                                        
this.graphMediator.initialize(Groups.NODES, [ns]);
@@ -485,6 +491,7 @@
                                
                                // update parent compound node if adding a node 
to another one
                                if (parent != null) {
+                                   this.graphProxy.addToParent(ns, parent);
                                    
this.graphMediator.updateCompoundNode(parent, ns);
                                }
                                

Modified: 
cytoscapeweb/branches/compound/src/org/cytoscapeweb/view/GraphMediator.as
===================================================================
--- cytoscapeweb/branches/compound/src/org/cytoscapeweb/view/GraphMediator.as   
2011-10-12 21:17:32 UTC (rev 27145)
+++ cytoscapeweb/branches/compound/src/org/cytoscapeweb/view/GraphMediator.as   
2011-10-12 21:53:07 UTC (rev 27146)
@@ -30,7 +30,6 @@
 package org.cytoscapeweb.view {
     import flare.animate.Parallel;
     import flare.display.DirtySprite;
-    import flare.display.TextSprite;
     import flare.util.Arrays;
     import flare.vis.data.Data;
     import flare.vis.data.DataList;
@@ -297,7 +296,11 @@
         }
         
         public function initialize(gr:String, items:Array):void {
-                       // Set properties:
+            addListeners(items);
+            updateDataSprites(gr, items)
+        }
+        
+        public function updateDataSprites(gr:String, items:Array):void {
             var props:Object; 
                        
                        if (gr === Groups.NODES) {
@@ -313,7 +316,6 @@
             }
             
             vis.updateLabels(gr);
-            addListeners(items);
             separateDisconnected();
         }
         
@@ -360,22 +362,9 @@
                 */
                public function updateCompoundNode(parent:CompoundNodeSprite, 
ns:NodeSprite):void {
                        if (parent != null) {
-                               var group:DataList = 
this.graphProxy.graphData.group(Groups.COMPOUND_NODES);
+                // initialize visual properties
+                this.updateDataSprites(Groups.COMPOUND_NODES, [parent]);
                                
-                               // initialize the compound node if it is not 
initialized,
-                               // yet. Also, add the compound to the compound 
node data group
-                               if (!parent.isInitialized()) {
-                                       // initialize visual properties
-                                       this.initialize(Groups.COMPOUND_NODES, 
[parent]);
-                                       // initialize child node list
-                                       parent.initialize();
-                                       // add to the data group
-                                       group.add(parent);
-                               }
-                               
-                               // add node into the target compound node
-                               parent.addNode(ns);
-                               
                                // update bounds of the target compound node up 
to  the root
                                while (parent != null) {
                                        // update the bounds of the compound 
node

Modified: 
cytoscapeweb/branches/compound/src/org/cytoscapeweb/vis/data/CompoundNodeSprite.as
===================================================================
--- 
cytoscapeweb/branches/compound/src/org/cytoscapeweb/vis/data/CompoundNodeSprite.as
  2011-10-12 21:17:32 UTC (rev 27145)
+++ 
cytoscapeweb/branches/compound/src/org/cytoscapeweb/vis/data/CompoundNodeSprite.as
  2011-10-12 21:53:07 UTC (rev 27146)
@@ -32,6 +32,7 @@
        
        import flash.geom.Rectangle;
        
+       import org.cytoscapeweb.model.error.CWError;
        import org.cytoscapeweb.util.Nodes;
 
        /**
@@ -158,14 +159,31 @@
                 * @param ns    child node sprite to be added
                 */
                public function addNode(ns:NodeSprite):void {
-                       // check if the node is initialized
-                       if (this._nodesMap != null) {
-                               // add the node to the child node list of this 
node
-                               this._nodesMap[ns.data.id] = ns;
-                               // set the parent id of the added node
-                               ns.data.parent = this.data.id;
-                               _nodesCount++;
-                       }
+                   var descendent:CompoundNodeSprite = ns as 
CompoundNodeSprite;
+                   var stack:Array = [descendent];
+                   var id:String = ns.data.id;
+                   
+                   // check for circular dependencies:
+                   do {
+                descendent = stack.pop();
+                
+                if (descendent.data.id === this.data.parent) {
+                    throw new CWError("Cannot add child node '"+ns.data.id+"' 
to node '" + this.data.id + 
+                                      "', because it would create a circular 
dependency.");
+                }
+                
+                for each (descendent in descendent.getNodes()) {
+                    stack.push(descendent);
+                }
+                       } while (stack.length > 0);
+                   
+                   if (!isInitialized()) initialize();
+                   
+                       // add the node to the child node list of this node
+                       this._nodesMap[ns.data.id] = ns;
+                       // set the parent id of the added node
+                       ns.data.parent = this.data.id;
+                       _nodesCount++;
                }
                
                /**

-- 
You received this message because you are subscribed to the Google Groups 
"cytoscape-cvs" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/cytoscape-cvs?hl=en.

Reply via email to