hackedteam/rcs-console

View on GitHub
src/it/ht/rcs/console/entities/view/graph/LinkGraph.mxml

Summary

Maintainability
Test Coverage
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
                 xmlns:s="library://ns.adobe.com/flex/spark"
                 xmlns:mx="library://ns.adobe.com/flex/mx"
                 xmlns:diagrammer="fr.kapit.diagrammer.*"
                 width="100%"
                 height="100%"
                 xmlns:visualizer="fr.kapit.visualizer.*"
                 resize="onResize(event)">
    <fx:Metadata> 
    [Event(name="selectionChange", type="flash.events.Event")] 
    [Event(name="elementDoubleClick", type="flash.events.Event")] 
  </fx:Metadata>


    <fx:Script>
        <![CDATA[
      import fr.kapit.diagrammer.base.uicomponent.DiagramSprite;
      import fr.kapit.layouts.algorithms.balloon.BalloonLayout;
      import fr.kapit.layouts.algorithms.balloon.BalloonLayoutParams;
      import fr.kapit.layouts.algorithms.basic.params.LayoutParams;
      import fr.kapit.layouts.constants.RootSelectionType;
      import fr.kapit.layouts.model.Edge;
      import fr.kapit.visualizer.base.ISprite;
      import fr.kapit.visualizer.base.uicomponent.GenericGroup;
      import fr.kapit.visualizer.base.uicomponent.GenericSprite;
      import fr.kapit.visualizer.events.VisualizerEvent;
      import fr.kapit.visualizer.styles.LinkStyle;
      
      import it.ht.rcs.console.entities.controller.EntityManager;
      import it.ht.rcs.console.entities.model.Entity;
      import it.ht.rcs.console.entities.model.Link;
      import it.ht.rcs.console.entities.view.graph.utils.GraphUtils;
      import it.ht.rcs.console.entities.view.renderers.CustomGroupRenderer;
      import it.ht.rcs.console.entities.view.renderers.CustomLink;
      import it.ht.rcs.console.entities.view.renderers.CustomNodeRenderer;
      import it.ht.rcs.console.search.controller.SearchManager;
      
      import mx.collections.ArrayCollection;
      import mx.events.ResizeEvent;
      
      import spark.collections.Sort;
      import spark.collections.SortField;

            private var sort:Sort;
            private var entities:ArrayCollection;
            private var groups:ArrayCollection;
            private var filterCriteria:Object;

            private var positions_so:SharedObject;

            public var selection:Array;

            protected function onElementDoubleClick(event:VisualizerEvent):void
            {
                dispatchEvent(new Event("elementDoubleClick"))

            }

            protected function onSelectionChange(event:VisualizerEvent):void
            {
                selection=vis.selection
                dispatchEvent(new Event("selectionChange"))
            }

            private function initGraph():void
            {

                trace("GRAPH INIT")
                sort=new Sort();
                sort.fields=[new SortField("type", true), new SortField("name", false)]

                var layout:BalloonLayout=vis.layout as BalloonLayout;
                var params:BalloonLayoutParams=new BalloonLayoutParams(layout);

                //highlightLinksOnSelection="false"
                params.nodesSpacing=50;
                params.loopMargin=50;
                params.loopSpacing=50;
                params.childAngularSector=360;

                params.useEvenAngles=false;
                params.rootAngularSector=180;
                params.rootSelectionPolicy=RootSelectionType.MOST_CLOSED_ROOT_SELECTION; //avoid overlap in a pile
                //params.overlappingAvoidMethod=0;
       // params.packingPolicy=50;
                //params.packingSpacing=50;

                vis.balloonLayout.params=params;

                //vis.reLayout()
                vis.itemsFactory.addOrReplaceClassReference('link', CustomLink);
            }


            private function linkStyleFunction(data:Object):LinkStyle
            {
                var linkStyle:LinkStyle=new LinkStyle();

                linkStyle.arrowWidth=10
                linkStyle.arrowHeight=20
                linkStyle.arrowRadius=10
                linkStyle.thickness=2
                //relevance

                if (data['rel'] == '0')
                    linkStyle.lineColor=0x333333
                else if (data['rel'] == '1')
                    linkStyle.lineColor=0x999999
                else if (data['rel'] == '2')
                    linkStyle.lineColor=0x5DE35F
                else if (data['rel'] == '3')
                    linkStyle.lineColor=0xFFDC42
                else if (data['rel'] == '4')
                    linkStyle.lineColor=0xFF4034


                //direction
                if (data['versus'] == 'in')
                {
                    linkStyle.arrowSourceType=LinkStyle.LINK_ARROW_ARROW_TYPE
                    linkStyle.arrowTargetType=LinkStyle.LINK_ARROW_NONE_TYPE

                }
                else if (data['versus'] == 'out')
                {
                    linkStyle.arrowSourceType=LinkStyle.LINK_ARROW_NONE_TYPE
                    linkStyle.arrowTargetType=LinkStyle.LINK_ARROW_ARROW_TYPE
                }
                else if (data['versus'] == 'both')
                {
                    linkStyle.arrowSourceType=LinkStyle.LINK_ARROW_ARROW_TYPE;
                    linkStyle.arrowTargetType=LinkStyle.LINK_ARROW_ARROW_TYPE;
                }

                //type
                if (data['type'] == 'peer')
                    linkStyle.renderingPolicy=LinkStyle.LINK_RENDERING_SOLID;
                else if (data['type'] == 'know')
                    linkStyle.renderingPolicy=LinkStyle.LINK_RENDERING_DASH;
        
        else if (data['type'] == 'identity')
        {
          linkStyle.patterns=[2,2]
          linkStyle.renderingPolicy=LinkStyle.LINK_RENDERING_DASH;
        }

                return linkStyle;
            }

            private function nodeRendererFunction(data:Object):CustomNodeRenderer
            {
                var renderer:CustomNodeRenderer=new CustomNodeRenderer();
                if (data['type'] == "target")
                    renderer.icon.source=renderer.TargetIcon;
                else if (data['type'] == "person")
                    renderer.icon.source=renderer.PersonIcon;
                else if (data['type'] == "position")
                    renderer.icon.source=renderer.PositionIcon;
                else if (data['type'] == "virtual")
                    renderer.icon.source=renderer.VirtualIcon;

                renderer.label.text=data['name'];

                return renderer
            }

            public function draw(entities:ArrayCollection, filterCriteria:Object=null):void
            {

                positions_so=SharedObject.getLocal("entityPositions");
                positions_so.clear() // uncomment to clean SO for dev/debug purposes

                if (positions_so.data.positions == null)
                {
                    positions_so.data.positions=new Dictionary();
                }
                if (this.entities == entities) //data not changed no need to redraw()
                {
                    //return;
                }

                vis.removeAll()
                vis.clearAll()
                //initGraph()

                this.entities=entities;
                this.filterCriteria=filterCriteria

                if (entities.length == 0 || !entities)
                {
                    vis.visible=false;
                    return;
                }
                trace("Drawing Graph > Entities to show: " + entities.length)

                addEntities()
                addGroups()
                addLinks()
                vis.reLayout()

                dispatchEvent(new Event("selectionChange"))
                //vis.setFocus()
                //vis.invalidateDisplayList()

                setTimeout(collapseAll, 10)
            }

            private function addEntities():void
            {
                var node:GenericSprite;
                var entity:Entity;
                var hasPermission:Boolean;
                var _id:String;
                var child:Entity
                var point:Point
                var includeInGraphLayout:Boolean;

                groups=new ArrayCollection()

                for (var i:int=0; i < entities.length; i++)
                {
                    entity=entities.getItemAt(i) as Entity;

                    if (entity.type != "group")
                    {
            includeInGraphLayout=true
                        /* if (positions_so.data.positions[entity._id].x && positions_so.data.positions[entity._id].y)
                        {
                            point=new Point()
                            point.x=positions_so.data.positions[entity._id].x
                            point.y=positions_so.data.positions[entity._id].y
                            //includeInGraphLayout=false;
              includeInGraphLayout=true;

                        }
                        else
                        {
                            point=null
                            includeInGraphLayout=true;
                        } */

                        node=vis.addNodeElement(entity, null, null, point, entity._id) as GenericSprite
                        node.includeInGraphLayout=includeInGraphLayout
                    }
                    else // is a group
                    {
                        groups.addItem(entity)
                    }

                    if (entity.type == "group" && entity.stand_for) //draw entities from other operations/groups
                    {
                        hasPermission=SearchManager.instance.getItem(entity.stand_for)

                        for each (_id in entity.children)
                        {
                            if (hasPermission)
                                child=EntityManager.instance.getItem(_id)
                            else
                                child=new Entity({_id: _id, type: "person"}); //draw just a fake entity in a closed group
                            if (child)
                            {

             /*    if (positions_so.data.positions[_id].x && positions_so.data.positions[_id].y)
                {
                  point=new Point()
                  point.x=positions_so.data.positions[_id].x
                  point.y=positions_so.data.positions[_id].y
                  includeInGraphLayout=false;
                  includeInGraphLayout=true;
                  
                }
                else
                {
                  point=null
                  includeInGraphLayout=true;
                } */

                includeInGraphLayout=true
                                node=vis.addNodeElement(child, null, null, null, child._id) as GenericSprite
                                node.includeInGraphLayout=includeInGraphLayout;
                                entities.addItem(child)
                            }
                        }
                    }
                }

            }


            private function addGroups():void
            {
                var elements:Array;
                var c:int;
                var entity:Entity
                var group:GenericGroup
                var hasPermission:Boolean;
                var point:Point
                var includeInGraphLayout:Boolean

                for (var i:int=0; i < groups.length; i++)
                {
                    entity=groups.getItemAt(i) as Entity;

                    if (entity.type != "group")
                        continue;

                    trace("GROUP: " + entity.stand_for)
                    elements=new Array();

                    for (c=0; c < entity.children.length; c++)
                    {
                        elements.push(vis.nodesMap[entity.children[c]]);
                    }

                    if (positions_so.data.positions[entity._id])
                    {
                        point=new Point()
                        point.x=positions_so.data.positions[entity._id].x
                        point.y=positions_so.data.positions[entity._id].y
                        //includeInGraphLayout=false;
            includeInGraphLayout=true;

                    }
                    else
                    {
                        point=null
                        includeInGraphLayout=true;
                    }

                    group=vis.groupElements(entity, elements, null, entity._id) as GenericGroup
          
                    /* if(point)
                        group.setPosition(point.x,point.y) */
                    if (group)
                    {
            if(point)
            {
              group.x=point.x;
              group.y=point.y;
            }
            group.includeInGraphLayout=true;
                        //group.includeInGraphLayout=includeInGraphLayout;
                        hasPermission=SearchManager.instance.getItem(entity.stand_for);
                        if (!hasPermission && entity.stand_for)
                        {
                            group.isGroupExpanded=false;
                            group.forceNoExpandGroupButton=true;
                        }
        
                    }
                }


            }


      private function collapseAll():void
      {
        for each (var node:Object in vis.nodesMap)
        {
          if (node is GenericGroup && GenericGroup(node).isGroupExpanded && !GenericGroup(node).forceNoExpandGroupButton)
            GenericGroup(node).isGroupExpanded=false
        }
        //vis.reLayout();
      }


            private function addLinks():void
            {
                var i:int;
                var link:Link;
                var entity:Entity;
                var source:ISprite;
                var target:ISprite;
                var links:Array=new Array();

                for (i=0; i < entities.length; i++)
                {
                    entity=entities.getItemAt(i) as Entity;
                    if (!entity)
                        continue;
                    if (entity.links)
                    {
                        for (var j:int=0; j < entity.links.length; j++)
                        {
                            link=entity.links.getItemAt(j) as Link;

                            if (GraphUtils.alreadyLinked(links, entity._id, link.le))
                                continue;
                            if (filterCriteria.relevance && filterCriteria.relevance.length > 0 && filterCriteria.relevance.indexOf(link.rel) == -1)
                                continue;
              if (filterCriteria.programs && filterCriteria.programs.length > 0 && !matchPrograms(link)) //check programs
                continue;
                            source=vis.nodesMap[entity._id];
                            target=vis.nodesMap[link.le];
                            vis.addLinkElement({type: link.type, rel: link.rel, level: link.level, versus: link.versus, info: link.info, source: entity._id, target: link.le}, source, target);
                            links.push({source: entity._id, target: link.le})

                        }
                    }
                }
                //vis.reLayout();

            }
      
      private function matchPrograms(link:Link):Boolean
      {
        for(var i:int=0;i<filterCriteria.programs.length;i++)
        {
          var program:String=filterCriteria.programs[i];
          if(link.info[program]!=null)
            return true
        }
        return false;
      }
      

            public function highlightLink(from:String, to:String):void
            {

                for (var k:int=0; k < vis.graph.edges.length; k++)
                {
                    var currentEdge:Edge=vis.graph.edges[k] as Edge;
                    var currentRenderer:CustomLink=currentEdge.visualEdge as CustomLink

                    currentRenderer.unHighlight();
                    if (currentRenderer.data.source == from && currentRenderer.data.target == to || currentRenderer.data.source == to && currentRenderer.data.target == from)
                    {
                        currentRenderer.highlight()
                        selection=[currentRenderer]
                        dispatchEvent(new Event("selectionChange"))
                    }
                }
            }

            public function highlightNode(id:String):void
            {

                for (var k:int=0; k < vis.graph.nodes.length; k++)
                {
                    var vn:DiagramSprite=vis.graph.nodes[k].visualNode as DiagramSprite;
                    if (!vn)
                        continue;
                    vn.isSelected=false;

                    if (vis.graph.nodes[k].uid == id)
                    {
                        vn.isSelected=true;
                        selection=[vn]
                        dispatchEvent(new Event("selectionChange"))
                    }

                }
            }

            protected function onResize(event:ResizeEvent):void
            {
                // TODO Auto-generated method stub
                //vis.autoFit();
            }

            private function onDrag(e:VisualizerEvent):void
            {
        
            }
      
      public function zoom(value:Number):void
      {
       vis.zoomContent(value,null,false,false);
      }
      
      protected function onDragEnd(event:VisualizerEvent):void
      {
        savePositions()
      }
      
      private function savePositions():void
      {
        for each (var node:Object in vis.nodesMap)
        {
          if (node is GenericGroup || node is GenericSprite)
          {
            trace("Entity name: "+node.data.name+"(x: "+node.x+", y: "+node.y+")");
            //positions_so.data.positions[node.data._id]=new Point(node.x, node.y);
          }
        }
      
      }
      
    ]]>
    </fx:Script>

    <diagrammer:Diagrammer width="100%"
                                                 height="100%"
                                                 id="vis"
                                                 layout="balloon"
                                                 creationComplete="initGraph()"
                                                 groupLabelField="name"
                                                 linkStyleFunction="{linkStyleFunction}"
                                                 nodeRendererFunction="{nodeRendererFunction}"
                                                 enableAnimation="false"
                                                 enableAutofitOnLayout="true"
                         enableZoomOnMouseWheel="false"
                                                 groupRendererClass="{CustomGroupRenderer}"
                         elementsDragFinished="onDragEnd(event)"
                                                 showNodeExpandCollapseButton="false"
                                                 elementsSelectionChanged="onSelectionChange(event)"
                                                 elementDoubleClicked="onElementDoubleClick(event)"/>
</s:Group>