Author: scooter
Date: 2012-01-26 10:27:23 -0800 (Thu, 26 Jan 2012)
New Revision: 28115

Added:
   
core3/impl/trunk/core-task-impl/src/main/java/org/cytoscape/task/internal/group/
   
core3/impl/trunk/core-task-impl/src/main/java/org/cytoscape/task/internal/group/CollapseGroupTask.java
   
core3/impl/trunk/core-task-impl/src/main/java/org/cytoscape/task/internal/group/GroupNodeContextTaskFactory.java
   
core3/impl/trunk/core-task-impl/src/main/java/org/cytoscape/task/internal/group/GroupNodesTask.java
   
core3/impl/trunk/core-task-impl/src/main/java/org/cytoscape/task/internal/group/GroupNodesTaskFactory.java
   core3/impl/trunk/group-view-impl/
   core3/impl/trunk/group-view-impl/pom.xml
   core3/impl/trunk/group-view-impl/src/
   core3/impl/trunk/group-view-impl/src/main/
   core3/impl/trunk/group-view-impl/src/main/java/
   core3/impl/trunk/group-view-impl/src/main/java/org/
   core3/impl/trunk/group-view-impl/src/main/java/org/cytoscape/
   core3/impl/trunk/group-view-impl/src/main/java/org/cytoscape/group/
   core3/impl/trunk/group-view-impl/src/main/java/org/cytoscape/group/view/
   
core3/impl/trunk/group-view-impl/src/main/java/org/cytoscape/group/view/internal/
   
core3/impl/trunk/group-view-impl/src/main/java/org/cytoscape/group/view/internal/CyActivator.java
   
core3/impl/trunk/group-view-impl/src/main/java/org/cytoscape/group/view/internal/GroupViewCollapseHandler.java
Modified:
   core3/impl/trunk/core-task-impl/pom.xml
   
core3/impl/trunk/core-task-impl/src/main/java/org/cytoscape/task/internal/CyActivator.java
   
core3/impl/trunk/group-impl/src/main/java/org/cytoscape/group/internal/CyGroupImpl.java
   
core3/impl/trunk/group-impl/src/test/java/org/cytoscape/group/TestCyGroupFactory.java
Log:
Next round of group changes.  Not ready for prime-time, yet.


Modified: core3/impl/trunk/core-task-impl/pom.xml
===================================================================
--- core3/impl/trunk/core-task-impl/pom.xml     2012-01-26 18:27:21 UTC (rev 
28114)
+++ core3/impl/trunk/core-task-impl/pom.xml     2012-01-26 18:27:23 UTC (rev 
28115)
@@ -90,6 +90,10 @@
                        <groupId>org.cytoscape</groupId>
                        <artifactId>io-api</artifactId>
                </dependency>
+               <dependency>
+                       <groupId>org.cytoscape</groupId>
+                       <artifactId>group-api</artifactId>
+               </dependency>
                
                <dependency>
                        <groupId>org.cytoscape</groupId>

Modified: 
core3/impl/trunk/core-task-impl/src/main/java/org/cytoscape/task/internal/CyActivator.java
===================================================================
--- 
core3/impl/trunk/core-task-impl/src/main/java/org/cytoscape/task/internal/CyActivator.java
  2012-01-26 18:27:21 UTC (rev 28114)
+++ 
core3/impl/trunk/core-task-impl/src/main/java/org/cytoscape/task/internal/CyActivator.java
  2012-01-26 18:27:23 UTC (rev 28115)
@@ -7,6 +7,8 @@
 import org.cytoscape.application.CyApplicationManager;
 import org.cytoscape.datasource.DataSourceManager;
 import org.cytoscape.event.CyEventHelper;
+import org.cytoscape.group.CyGroupFactory;
+import org.cytoscape.group.CyGroupManager;
 import org.cytoscape.io.read.CyNetworkReaderManager;
 import org.cytoscape.io.read.CySessionReaderManager;
 import org.cytoscape.io.read.CyTableReaderManager;
@@ -51,6 +53,8 @@
 import org.cytoscape.task.internal.export.table.ExportEdgeTableTaskFactory;
 import org.cytoscape.task.internal.export.table.ExportNodeTableTaskFactory;
 import org.cytoscape.task.internal.export.vizmap.ExportVizmapTaskFactory;
+import org.cytoscape.task.internal.group.GroupNodesTaskFactory;
+import org.cytoscape.task.internal.group.GroupNodeContextTaskFactory;
 import org.cytoscape.task.internal.hide.HideSelectedEdgesTaskFactory;
 import org.cytoscape.task.internal.hide.HideSelectedNodesTaskFactory;
 import org.cytoscape.task.internal.hide.HideSelectedTaskFactory;
@@ -156,6 +160,9 @@
                
                LoadAttributesFileTaskFactoryImpl loadAttrsFileTaskFactory = 
new LoadAttributesFileTaskFactoryImpl(cyDataTableReaderManagerServiceRef);
                LoadAttributesURLTaskFactoryImpl loadAttrsURLTaskFactory = new 
LoadAttributesURLTaskFactoryImpl(cyDataTableReaderManagerServiceRef);
+
+               CyGroupManager cyGroupManager = getService(bc, 
CyGroupManager.class);
+               CyGroupFactory cyGroupFactory = getService(bc, 
CyGroupFactory.class);
                
                LoadVizmapFileTaskFactoryImpl loadVizmapFileTaskFactory = new 
LoadVizmapFileTaskFactoryImpl(vizmapReaderManagerServiceRef,visualMappingManagerServiceRef,synchronousTaskManagerServiceRef);
 
@@ -221,6 +228,10 @@
 
                BioGridPreprocessor bioGridPreprocessor = new 
BioGridPreprocessor(cyPropertyServiceRef,cyApplicationConfigurationServiceRef);
                ConnectSelectedNodesTaskFactory connectSelectedNodesTaskFactory 
= new 
ConnectSelectedNodesTaskFactory(undoSupportServiceRef,cyApplicationManagerServiceRef,cyEventHelperRef);
+
+               GroupNodesTaskFactory groupNodesTaskFactory = new 
GroupNodesTaskFactory(cyGroupManager, cyGroupFactory);
+               GroupNodeContextTaskFactory collapseGroupTaskFactory = new 
GroupNodeContextTaskFactory(cyGroupManager, true);
+               GroupNodeContextTaskFactory expandGroupTaskFactory = new 
GroupNodeContextTaskFactory(cyGroupManager, false);
                
                
                Properties loadNetworkFileTaskFactoryProps = new Properties();
@@ -690,6 +701,25 @@
                
registerServiceListener(bc,subnetworkBuilderUtil,"addProcessor","removeProcessor",InteractionFilePreprocessor.class);
                
registerServiceListener(bc,subnetworkBuilderUtil,"addFactory","removeFactory",VisualMappingFunctionFactory.class);
 
+
+               Properties groupNodesTaskFactoryProps = new Properties();
+               groupNodesTaskFactoryProps.setProperty("title","Group Nodes");
+               groupNodesTaskFactoryProps.setProperty("tooltip","Group 
Selected Nodes Together");
+               groupNodesTaskFactoryProps.setProperty("preferredAction", 
"NEW");
+               
registerService(bc,groupNodesTaskFactory,NetworkViewTaskFactory.class, 
groupNodesTaskFactoryProps);
+
+               Properties collapseGroupTaskFactoryProps = new Properties();
+               collapseGroupTaskFactoryProps.setProperty("title","Collapse 
Group");
+               collapseGroupTaskFactoryProps.setProperty("tooltip","Collapse 
Grouped Nodes");
+               collapseGroupTaskFactoryProps.setProperty("preferredAction", 
"NEW");
+               
registerService(bc,collapseGroupTaskFactory,NodeViewTaskFactory.class, 
collapseGroupTaskFactoryProps);
+
+               Properties expandGroupTaskFactoryProps = new Properties();
+               expandGroupTaskFactoryProps.setProperty("title","Expand Group");
+               expandGroupTaskFactoryProps.setProperty("tooltip","Expand 
Group");
+               expandGroupTaskFactoryProps.setProperty("preferredAction", 
"NEW");
+               
registerService(bc,expandGroupTaskFactory,NodeViewTaskFactory.class, 
expandGroupTaskFactoryProps);
+
                //ShowWelcomeScreenTask ws = new ShowWelcomeScreenTask();
                //registerAllServices(bc, ws, new Properties());
                

Added: 
core3/impl/trunk/core-task-impl/src/main/java/org/cytoscape/task/internal/group/CollapseGroupTask.java
===================================================================
--- 
core3/impl/trunk/core-task-impl/src/main/java/org/cytoscape/task/internal/group/CollapseGroupTask.java
                              (rev 0)
+++ 
core3/impl/trunk/core-task-impl/src/main/java/org/cytoscape/task/internal/group/CollapseGroupTask.java
      2012-01-26 18:27:23 UTC (rev 28115)
@@ -0,0 +1,72 @@
+/*
+ File: SelectFirstNeighborsNodeViewTask.java
+
+ Copyright (c) 2006, 2010, The Cytoscape Consortium (www.cytoscape.org)
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of the License, or
+ any later version.
+
+ This library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  The software and
+ documentation provided hereunder is on an "as is" basis, and the
+ Institute for Systems Biology and the Whitehead Institute
+ have no obligations to provide maintenance, support,
+ updates, enhancements or modifications.  In no event shall the
+ Institute for Systems Biology and the Whitehead Institute
+ be liable to any party for direct, indirect, special,
+ incidental or consequential damages, including lost profits, arising
+ out of the use of this software and its documentation, even if the
+ Institute for Systems Biology and the Whitehead Institute
+ have been advised of the possibility of such damage.  See
+ the GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+package org.cytoscape.task.internal.group;
+
+import java.util.List;
+
+import org.cytoscape.group.CyGroup;
+import org.cytoscape.group.CyGroupFactory;
+import org.cytoscape.group.CyGroupManager;
+
+import org.cytoscape.model.CyNetwork;
+import org.cytoscape.model.CyNode;
+import org.cytoscape.model.CyTableUtil;
+
+import org.cytoscape.view.model.CyNetworkView;
+
+import org.cytoscape.work.AbstractTask;
+import org.cytoscape.work.TaskMonitor;
+
+public class CollapseGroupTask extends AbstractTask {
+       private CyNetwork net;
+       private CyGroupManager mgr;
+       private CyGroup group;
+       private boolean collapse;
+
+       public CollapseGroupTask(CyNetwork net, CyGroup group, CyGroupManager 
manager, boolean collapse) {
+               if (net == null)
+                       throw new NullPointerException("network is null");
+               if (group == null)
+                       throw new NullPointerException("group is null");
+               this.net = net;
+               this.mgr = manager;
+               this.group = group;
+               this.collapse = collapse;
+       }
+
+       public void run(TaskMonitor tm) throws Exception {
+               tm.setProgress(0.0);
+               if (collapse)
+                       group.collapse(net);
+               else
+                       group.expand(net);
+               tm.setProgress(1.0d);
+       }
+}

Added: 
core3/impl/trunk/core-task-impl/src/main/java/org/cytoscape/task/internal/group/GroupNodeContextTaskFactory.java
===================================================================
--- 
core3/impl/trunk/core-task-impl/src/main/java/org/cytoscape/task/internal/group/GroupNodeContextTaskFactory.java
                            (rev 0)
+++ 
core3/impl/trunk/core-task-impl/src/main/java/org/cytoscape/task/internal/group/GroupNodeContextTaskFactory.java
    2012-01-26 18:27:23 UTC (rev 28115)
@@ -0,0 +1,87 @@
+/*
+ File: SelectFirstNeighborsNodeViewTaskFactory.java
+
+ Copyright (c) 2006, 2010, The Cytoscape Consortium (www.cytoscape.org)
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of the License, or
+ any later version.
+
+ This library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  The software and
+ documentation provided hereunder is on an "as is" basis, and the
+ Institute for Systems Biology and the Whitehead Institute
+ have no obligations to provide maintenance, support,
+ updates, enhancements or modifications.  In no event shall the
+ Institute for Systems Biology and the Whitehead Institute
+ be liable to any party for direct, indirect, special,
+ incidental or consequential damages, including lost profits, arising
+ out of the use of this software and its documentation, even if the
+ Institute for Systems Biology and the Whitehead Institute
+ have been advised of the possibility of such damage.  See
+ the GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+package org.cytoscape.task.internal.group;
+
+import org.cytoscape.group.CyGroupManager;
+import org.cytoscape.group.CyGroup;
+import org.cytoscape.task.AbstractNodeViewTaskFactory;
+import org.cytoscape.work.TaskFactoryPredicate;
+import org.cytoscape.work.TaskIterator;
+
+import java.util.List;
+
+public class GroupNodeContextTaskFactory extends AbstractNodeViewTaskFactory 
implements TaskFactoryPredicate {
+       private CyGroupManager mgr;
+       private boolean collapse;
+
+       public GroupNodeContextTaskFactory(CyGroupManager mgr, boolean 
collapse) {
+               super();
+               this.mgr = mgr;
+               this.collapse = collapse;
+       }
+
+       public boolean isReady() {
+               if (collapse) {
+                       // We're ready to collapse if the node view is in a 
group
+                       if (getExpandedGroupForNode() != null)
+                               return true;
+               } else {
+                       // We're ready to expand if the node view is a group
+                       CyGroup group = mgr.getGroup(nodeView.getModel(), 
netView.getModel());
+                       if (group != null && 
group.isCollapsed(netView.getModel()))
+                               return true;
+               }
+               return false;
+       }
+
+       public TaskIterator createTaskIterator() {
+               CyGroup group;
+               if (collapse)
+                       group = getExpandedGroupForNode();
+               else 
+                       group = mgr.getGroup(nodeView.getModel(), 
netView.getModel());
+
+               return new TaskIterator(new 
CollapseGroupTask(netView.getModel(), group, mgr, collapse));
+       }
+
+       private CyGroup getExpandedGroupForNode() {
+               List<CyGroup> groups = 
mgr.getGroupsForNode(nodeView.getModel());
+               if (groups == null || groups.size() == 0)
+                       return null;
+
+               // Return the first uncollapsed group in this network
+               for (CyGroup group: groups) {
+                       if (group.isInNetwork(netView.getModel()) && 
+                           !group.isCollapsed(netView.getModel()))
+                               return group;
+               }
+               return null;
+       }
+}

Added: 
core3/impl/trunk/core-task-impl/src/main/java/org/cytoscape/task/internal/group/GroupNodesTask.java
===================================================================
--- 
core3/impl/trunk/core-task-impl/src/main/java/org/cytoscape/task/internal/group/GroupNodesTask.java
                         (rev 0)
+++ 
core3/impl/trunk/core-task-impl/src/main/java/org/cytoscape/task/internal/group/GroupNodesTask.java
 2012-01-26 18:27:23 UTC (rev 28115)
@@ -0,0 +1,71 @@
+/*
+ File: SelectFirstNeighborsNodeViewTask.java
+
+ Copyright (c) 2006, 2010, The Cytoscape Consortium (www.cytoscape.org)
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of the License, or
+ any later version.
+
+ This library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  The software and
+ documentation provided hereunder is on an "as is" basis, and the
+ Institute for Systems Biology and the Whitehead Institute
+ have no obligations to provide maintenance, support,
+ updates, enhancements or modifications.  In no event shall the
+ Institute for Systems Biology and the Whitehead Institute
+ be liable to any party for direct, indirect, special,
+ incidental or consequential damages, including lost profits, arising
+ out of the use of this software and its documentation, even if the
+ Institute for Systems Biology and the Whitehead Institute
+ have been advised of the possibility of such damage.  See
+ the GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+package org.cytoscape.task.internal.group;
+
+import java.util.List;
+
+import org.cytoscape.group.CyGroup;
+import org.cytoscape.group.CyGroupFactory;
+import org.cytoscape.group.CyGroupManager;
+
+import org.cytoscape.model.CyNetwork;
+import org.cytoscape.model.CyNode;
+import org.cytoscape.model.CyTableUtil;
+
+import org.cytoscape.view.model.CyNetworkView;
+
+import org.cytoscape.work.AbstractTask;
+import org.cytoscape.work.TaskMonitor;
+
+public class GroupNodesTask extends AbstractTask {
+       private CyNetwork net;
+       private CyGroupManager mgr;
+       private CyGroupFactory factory;
+
+       public GroupNodesTask(CyNetworkView netView, CyGroupManager mgr, 
CyGroupFactory factory) {
+               if (netView == null)
+                       throw new NullPointerException("network view is null");
+               this.net = netView.getModel();
+               this.mgr = mgr;
+               this.factory = factory;
+       }
+
+       public void run(TaskMonitor tm) throws Exception {
+               tm.setProgress(0.0);
+
+               // Get all of the selected nodes
+               final List<CyNode> selNodes = CyTableUtil.getNodesInState(net, 
CyNetwork.SELECTED, true);
+
+               // At some point, we'll want to seriously think about only 
adding those edges that are also
+               // selected, but for now....
+               CyGroup group = factory.createGroup(net, selNodes, null);
+               tm.setProgress(1.0d);
+       }
+}

Added: 
core3/impl/trunk/core-task-impl/src/main/java/org/cytoscape/task/internal/group/GroupNodesTaskFactory.java
===================================================================
--- 
core3/impl/trunk/core-task-impl/src/main/java/org/cytoscape/task/internal/group/GroupNodesTaskFactory.java
                          (rev 0)
+++ 
core3/impl/trunk/core-task-impl/src/main/java/org/cytoscape/task/internal/group/GroupNodesTaskFactory.java
  2012-01-26 18:27:23 UTC (rev 28115)
@@ -0,0 +1,50 @@
+/*
+ File: SelectFirstNeighborsNodeViewTaskFactory.java
+
+ Copyright (c) 2006, 2010, The Cytoscape Consortium (www.cytoscape.org)
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of the License, or
+ any later version.
+
+ This library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  The software and
+ documentation provided hereunder is on an "as is" basis, and the
+ Institute for Systems Biology and the Whitehead Institute
+ have no obligations to provide maintenance, support,
+ updates, enhancements or modifications.  In no event shall the
+ Institute for Systems Biology and the Whitehead Institute
+ be liable to any party for direct, indirect, special,
+ incidental or consequential damages, including lost profits, arising
+ out of the use of this software and its documentation, even if the
+ Institute for Systems Biology and the Whitehead Institute
+ have been advised of the possibility of such damage.  See
+ the GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+package org.cytoscape.task.internal.group;
+
+import org.cytoscape.group.CyGroupFactory;
+import org.cytoscape.group.CyGroupManager;
+import org.cytoscape.task.AbstractNetworkViewTaskFactory;
+import org.cytoscape.work.TaskIterator;
+
+public class GroupNodesTaskFactory extends AbstractNetworkViewTaskFactory {
+       private CyGroupManager mgr;
+       private CyGroupFactory groupFactory;
+
+       public GroupNodesTaskFactory(CyGroupManager mgr, CyGroupFactory 
groupFactory) {
+               super();
+               this.mgr = mgr;
+               this.groupFactory = groupFactory;
+       }
+
+       public TaskIterator createTaskIterator() {
+               return new TaskIterator(new GroupNodesTask(view, mgr, 
groupFactory));
+       }
+}

Modified: 
core3/impl/trunk/group-impl/src/main/java/org/cytoscape/group/internal/CyGroupImpl.java
===================================================================
--- 
core3/impl/trunk/group-impl/src/main/java/org/cytoscape/group/internal/CyGroupImpl.java
     2012-01-26 18:27:21 UTC (rev 28114)
+++ 
core3/impl/trunk/group-impl/src/main/java/org/cytoscape/group/internal/CyGroupImpl.java
     2012-01-26 18:27:23 UTC (rev 28115)
@@ -33,6 +33,7 @@
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
 import java.util.Set;
 
@@ -43,16 +44,25 @@
 import org.cytoscape.group.events.GroupAddedToNetworkEvent;
 import org.cytoscape.group.events.GroupChangedEvent;
 import org.cytoscape.group.events.GroupCollapsedEvent;
+import org.cytoscape.group.events.GroupAboutToCollapseEvent;
 
 import org.cytoscape.model.CyEdge;
 import org.cytoscape.model.CyNetwork;
 import org.cytoscape.model.CyNode;
 import org.cytoscape.model.CyTable;
+import org.cytoscape.model.CyTableEntry;
 import org.cytoscape.model.subnetwork.CyRootNetwork;
 import org.cytoscape.model.subnetwork.CySubNetwork;
 
 
+// TODO: Update attributes
+
 class CyGroupImpl implements CyGroup {
+       final private static String CHILDREN_ATTR = "NumChildren";
+       final private static String DESCENDENTS_ATTR = "NumDescendents";
+       final private static String GROUP_STATE_ATTR = "__groupState";
+       final private static String ISMETA_EDGE_ATTR = "__isMetaEdge";
+
        final private CyEventHelper cyEventHelper;
        final private CyGroupManager mgr;
 
@@ -119,14 +129,6 @@
                                                // This is an external edge, 
which means that we need to create
                                                // a corresponding meta-edge
                                                externalEdges.add(e);
-                                               CyNode source = e.getSource();
-                                               CyNode target = e.getTarget();
-                                               boolean directed = 
e.isDirected();
-                                               if (nodeMap.contains(source))
-                                                       source = groupNode;
-                                               else
-                                                       target = groupNode;
-                                               
metaEdges.add(rootNetwork.addEdge(source, target, directed));
                                        }
                                }
                        }
@@ -134,6 +136,13 @@
 
                // Create the subnetwork
                groupNet = rootNetwork.addSubNetwork(nodes, edges);
+
+               // Update our meta-edges
+               updateMetaEdges(true);
+
+               // Initialize our attributes
+               // TODO: updateCountAttributes();
+               // TODO: setGroupStateAttribute(false);
        }
 
        /**
@@ -153,18 +162,18 @@
        }
 
        /**
-        * @see org.cytoscape.group.CyGroup#getContainedEdgeList()
+        * @see org.cytoscape.group.CyGroup#getInternalEdgeList()
         */
        @Override
-       public List<CyEdge> getInteriorEdgeList() {
+       public List<CyEdge> getInternalEdgeList() {
                return groupNet.getEdgeList();
        }
 
        /**
-        * @see org.cytoscape.group.CyGroup#getExteriorEdgeList()
+        * @see org.cytoscape.group.CyGroup#getExternalEdgeList()
         */
        @Override
-       public Set<CyEdge> getExteriorEdgeList() {
+       public Set<CyEdge> getExternalEdgeList() {
                return externalEdges;
        }
 
@@ -184,7 +193,12 @@
                if (!rootNetwork.containsNode(node))
                        throwIllegalArgumentException("Can only add a node in 
the same network tree");
                groupNet.addNode(node);
-               cyEventHelper.fireEvent(new GroupChangedEvent(CyGroupImpl.this, 
node, GroupChangedEvent.ChangeType.NODE_ADDED));
+
+               if (!batchUpdate) {
+                       updateMetaEdges(false);
+                       // TODO: updateCountAttributes();
+                       cyEventHelper.fireEvent(new 
GroupChangedEvent(CyGroupImpl.this, node, 
GroupChangedEvent.ChangeType.NODE_ADDED));
+               }
        }
 
        /**
@@ -234,6 +248,8 @@
                                addExternalEdge(e);
                        }
                }
+               updateMetaEdges(false);
+               // TODO: updateCountAttributes();
                batchUpdate = false;
                cyEventHelper.fireEvent(new GroupChangedEvent(CyGroupImpl.this, 
nodes, GroupChangedEvent.ChangeType.NODES_ADDED));
        }
@@ -277,6 +293,8 @@
                        groupNet.removeEdges(netEdges);
                groupNet.removeNodes(nodes);
                batchUpdate = false;
+               updateMetaEdges(false);
+               // TODO: updateCountAttributes();
                cyEventHelper.fireEvent(new GroupChangedEvent(CyGroupImpl.this, 
nodes, GroupChangedEvent.ChangeType.NODES_REMOVED));
        }
 
@@ -361,28 +379,38 @@
                if (!networkSet.contains(net))
                        return; // We're not in that network
 
+               System.out.println("Collapsing -- firing");
+               cyEventHelper.fireEvent(new 
GroupAboutToCollapseEvent(CyGroupImpl.this, net, true));
+
                CySubNetwork subnet = (CySubNetwork) net;
 
                // Collapse it.
                // Remove all of the nodes from the target network
+               System.out.println("Collapsing -- removing 
"+getNodeList().size()+" nodes from "+subnet);
                subnet.removeNodes(getNodeList());
 
+               System.out.println("Collapsing -- adding group node");
                subnet.addNode(groupNode);
 
                // Add the group node and it's edges
                List<CyEdge> groupNodeEdges = 
rootNetwork.getAdjacentEdgeList(groupNode, CyEdge.Type.ANY);
+               System.out.println("Collapsing -- adding 
"+groupNodeEdges.size()+" edges");
                for (CyEdge e: groupNodeEdges)
                        subnet.addEdge(e);
 
                Set<CyNode> memberNodes = new HashSet<CyNode>(getNodeList());
 
+               System.out.println("Collapsing -- adding 
"+getMetaEdgeList().size()+" MetaEdges");
                // Add the meta-edges
                for (CyEdge e: getMetaEdgeList()) {
                        subnet.addEdge(e);
                }
 
                collapseSet.add(net);
+               System.out.println("Collapsed -- firing");
                cyEventHelper.fireEvent(new 
GroupCollapsedEvent(CyGroupImpl.this, net, true));
+               // Update attributes?
+               // TODO: setGroupStateAttribute(net, true);
        }
 
        /**
@@ -396,6 +424,8 @@
                if (!networkSet.contains(net))
                        return; // We're not in that network
 
+               cyEventHelper.fireEvent(new 
GroupAboutToCollapseEvent(CyGroupImpl.this, net, false));
+
                CySubNetwork subnet = (CySubNetwork) net;
 
                // Expand it.
@@ -407,11 +437,11 @@
                        subnet.addNode(n);
 
                // Add all of the interior edges in
-               for (CyEdge e: getInteriorEdgeList())
+               for (CyEdge e: getInternalEdgeList())
                        subnet.addEdge(e);
 
                // Add all of the exterior edges in
-               for (CyEdge e: getExteriorEdgeList()) {
+               for (CyEdge e: getExternalEdgeList()) {
                        // We need to be careful to only add the edge in
                        // if both the edge and the target are available
                        // since the target node might have been part of a
@@ -422,6 +452,8 @@
 
                collapseSet.remove(net);
                cyEventHelper.fireEvent(new 
GroupCollapsedEvent(CyGroupImpl.this, net, false));
+               // Update attributes?
+               // TODO: setGroupStateAttribute(net, false);
        }
 
        /**
@@ -487,4 +519,188 @@
                batchUpdate = false;
                throw new IllegalArgumentException(message);
        }
+
+  /**
+        * This method is the central method for the creation and maintenance 
of a
+        * meta-node.  Essentially, it is responsible for creating all of the 
meta-edges
+        * that connect this meta-node to external nodes.
+        *
+        * Basic approach:
+        *  for each external edge:
+        *    add a meta-edge to the parter
+        *    if the partner is a group and the group is in our network:
+        *      add ourselves to the group's outer edges list (recursively)
+        *      add ourselves to the partner's meta edge list
+        *    if the partner is in a group:
+        *      add ourselves to the group's meta edge list
+        */
+       private void updateMetaEdges(boolean ignoreMetaEdges) {
+               metaEdges = new HashSet<CyEdge>();
+
+               // We need to use a list iterator because we might need to add 
new
+               // edges to our outer edge list and we want to add them to the
+               // iterator to re-examine them
+               ListIterator<CyEdge> iterator = (new 
ArrayList<CyEdge>(externalEdges)).listIterator();
+               while (iterator.hasNext()) {
+                       CyEdge edge = iterator.next();
+                       CyNode node = getPartner(edge);
+
+                       if (ignoreMetaEdges && isMeta(edge)) {
+                               this.addMetaEdge(edge);
+                               continue;
+                       }
+
+                       // If the edge is already on our group node, don't 
create a metaedge for it
+                       if (edge.getSource() == groupNode || edge.getTarget() 
== groupNode)
+                               continue;
+
+                       // Create the meta-edge to the external node, but 
maintain the directionality
+                       // of the original edge
+                       CyEdge metaEdge = createMetaEdge(edge, node, groupNode);
+
+                       for (CyNetwork net: networkSet) {
+                               CyGroup metaPartner = mgr.getGroup(node, net);
+                               if (metaPartner != null) {
+                                       // Recursively add links to the 
appropriate children
+                                       addPartnerEdges(metaPartner, net);
+                                       
((CyGroupImpl)metaPartner).addMetaEdge(metaEdge);
+                               }
+
+                               // Now, handle the case where the partner is a 
member of one or more groups
+                               List<CyGroup> nodeGroups = 
mgr.getGroupsForNode(node);
+                               if (nodeGroups != null && nodeGroups.size() > 
0) {
+                                       addPartnerMetaEdges(net, edge, node, 
metaEdge);
+                               }
+                       }
+               }
+       }
+
+       protected int getDescendents(CyNetwork net) {
+               int nDescendents = groupNet.getNodeCount();
+               for (CyNode node: groupNet.getNodeList()) {
+                       CyGroup group = mgr.getGroup(node, net);
+                       if (group != null)
+                               nDescendents += 
((CyGroupImpl)group).getDescendents(net);
+               }
+               return nDescendents;
+       }
+
+       // Find the edge in our partner that links to us
+       protected void addPartnerEdges(CyGroup metaPartner, CyNetwork net) {
+               Set<CyEdge> partnerEdges = metaPartner.getExternalEdgeList();
+               Set<CyEdge> newEdges = new HashSet<CyEdge>();
+               for (CyEdge edge: partnerEdges) {
+                       CyNode source = edge.getSource();
+                       CyNode target = edge.getTarget();
+                       CyNode partner = null;
+                       boolean directed = edge.isDirected();
+                       if (groupNet.containsNode(target)) {
+                               source = groupNode;
+                               partner = target;
+                       } else if (groupNet.containsNode(source)) {
+                               target = groupNode;
+                               partner = source;
+                       } else {
+                               continue;
+                       }
+
+                       // Create a new edge
+                       CyEdge newEdge = rootNetwork.addEdge(source, target, 
directed);
+                       newEdges.add(newEdge);
+
+                       externalEdges.add(edge);
+
+                       CyGroup partnerMeta = mgr.getGroup(partner, net);
+                       if (partnerMeta != null)
+                               addPartnerEdges(partnerMeta, net);
+
+                       metaEdges.add(newEdge);
+               }
+
+               for (CyEdge edge: newEdges) { 
metaPartner.addExternalEdge(edge); }
+       }
+
+       private CyEdge createMetaEdge(CyEdge edge, CyNode node, CyNode 
groupNode) {
+               CyEdge metaEdge = null;
+               if (isIncoming(edge))
+                       metaEdge = rootNetwork.addEdge(node, groupNode, 
edge.isDirected());
+               else
+                       metaEdge = rootNetwork.addEdge(groupNode, node, 
edge.isDirected());
+
+               // Add the name and mark this as a meta-edge
+               String edgeName = rootNetwork.getRow(edge).get(CyNetwork.NAME, 
String.class);
+               rootNetwork.getRow(metaEdge).set(CyNetwork.NAME, 
"meta-"+edgeName);
+               createIfNecessary(metaEdge, CyNetwork.HIDDEN_ATTRS, 
ISMETA_EDGE_ATTR, Boolean.class);
+               rootNetwork.getRow(metaEdge, 
CyNetwork.HIDDEN_ATTRS).set(ISMETA_EDGE_ATTR, Boolean.TRUE);
+
+               return metaEdge;
+       }
+
+       private void addPartnerMetaEdges(CyNetwork net, CyEdge connectingEdge, 
+                                        CyNode partnerNode, CyEdge metaEdge) {
+               for (CyGroup partnerGroup: mgr.getGroupsForNode(partnerNode)) {
+                       // Are we partners in this network?
+                       if (!partnerGroup.getNetworkSet().contains(net))
+                               continue;
+
+                       CyEdge metaMetaEdge = null;
+                       CyGroupImpl partner = (CyGroupImpl)partnerGroup;
+                       if (isIncoming(connectingEdge)) {
+                               metaMetaEdge = createMetaEdge(connectingEdge, 
partnerGroup.getGroupNode(), this.groupNode);
+                       } else {
+                               metaMetaEdge = createMetaEdge(connectingEdge, 
this.groupNode, partnerGroup.getGroupNode());
+                       }
+
+                       partner.addMetaEdge(metaMetaEdge);
+                       partner.addMetaEdge(metaEdge);
+
+                       // Now, get our partner's metaEdges and add any that 
point to our children
+                       for (CyEdge outerEdge: partner.getMetaEdgeList()) {
+                               if (isConnectingEdge(outerEdge))
+                                       addExternalEdge(outerEdge);
+                       }
+                       
+               }
+       }
+
+       private boolean isMeta(CyEdge edge) {
+               Boolean meta = rootNetwork.getRow(edge, CyNetwork.HIDDEN_ATTRS).
+                                       get(ISMETA_EDGE_ATTR, Boolean.class, 
Boolean.FALSE);
+
+               return meta.booleanValue();
+       }
+
+       private boolean isConnectingEdge(CyEdge edge) {
+               CyNode source = edge.getSource();
+               CyNode target = edge.getTarget();
+               if (groupNet.containsNode(source) || 
groupNet.containsNode(target))
+                       return true;
+               return false;
+       }
+
+       private boolean isIncoming(CyEdge edge) {
+               CyNode source = edge.getSource();
+               CyNode target = edge.getTarget();
+               if (source.equals(groupNode) || groupNet.containsNode(source))
+                       return false;
+               return true;
+       }
+
+       private CyNode getPartner(CyEdge edge) {
+               CyNode source = edge.getSource();
+               CyNode target = edge.getTarget();
+               if (source.equals(groupNode) || groupNet.containsNode(source))
+                       return target;
+               return source;
+       }
+
+       private void createIfNecessary(CyTableEntry entry, String tableName, 
+                                      String attribute, Class type) {
+               CyTable table = rootNetwork.getRow(entry, tableName).getTable();
+               if (table.getColumn(attribute) == null)
+                       table.createColumn(attribute, type, false);
+
+               return;
+       }
+
 }

Modified: 
core3/impl/trunk/group-impl/src/test/java/org/cytoscape/group/TestCyGroupFactory.java
===================================================================
--- 
core3/impl/trunk/group-impl/src/test/java/org/cytoscape/group/TestCyGroupFactory.java
       2012-01-26 18:27:21 UTC (rev 28114)
+++ 
core3/impl/trunk/group-impl/src/test/java/org/cytoscape/group/TestCyGroupFactory.java
       2012-01-26 18:27:23 UTC (rev 28115)
@@ -93,18 +93,18 @@
                CyGroup group1 = factory.createGroup(network, groupNodes, null);
                assertNotNull(group1);
                assertTrue("group1 node count = 3", group1.getNodeList().size() 
== 3);
-               assertTrue("group1 internal edge count = 2", 
group1.getInteriorEdgeList().size() == 2);
-               assertTrue("group1 external edge count = 3", 
group1.getExteriorEdgeList().size() == 3);
+               assertTrue("group1 internal edge count = 2", 
group1.getInternalEdgeList().size() == 2);
+               assertTrue("group1 external edge count = 3", 
group1.getExternalEdgeList().size() == 3);
                CyGroup group2 = factory.createGroup(network, groupNodes, new 
ArrayList<CyEdge>());
                assertNotNull(group2);
                assertTrue("group2 node count = 3", group2.getNodeList().size() 
== 3);
-               assertTrue("group2 internal edge count = 0", 
group2.getInteriorEdgeList().size() == 0);
-               assertTrue("group2 external edge count = 0", 
group2.getExteriorEdgeList().size() == 0);
+               assertTrue("group2 internal edge count = 0", 
group2.getInternalEdgeList().size() == 0);
+               assertTrue("group2 external edge count = 0", 
group2.getExternalEdgeList().size() == 0);
                CyGroup group3 = factory.createGroup(network, groupNodes, 
groupEdges);
                assertNotNull(group3);
                assertTrue("group3 node count = 3", group3.getNodeList().size() 
== 3);
-               assertTrue("group3 internal edge count = 2", 
group3.getInteriorEdgeList().size() == 2);
-               assertTrue("group3 external edge count = 2", 
group3.getExteriorEdgeList().size() == 2);
+               assertTrue("group3 internal edge count = 2", 
group3.getInternalEdgeList().size() == 2);
+               assertTrue("group3 external edge count = 2", 
group3.getExternalEdgeList().size() == 2);
        }
 
 }

Added: core3/impl/trunk/group-view-impl/pom.xml
===================================================================
--- core3/impl/trunk/group-view-impl/pom.xml                            (rev 0)
+++ core3/impl/trunk/group-view-impl/pom.xml    2012-01-26 18:27:23 UTC (rev 
28115)
@@ -0,0 +1,138 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+       <parent>
+               <groupId>org.cytoscape</groupId>
+               <artifactId>impl-parent</artifactId>
+               <version>3.0.0-alpha8-SNAPSHOT</version>
+       </parent>
+
+  <properties>
+    <bundle.symbolicName>org.cytoscape.group-view-impl</bundle.symbolicName>
+    <bundle.namespace>org.cytoscape.group.view.internal</bundle.namespace>
+  </properties>
+
+       <modelVersion>4.0.0</modelVersion>
+  <groupId>org.cytoscape</groupId>
+  <artifactId>group-view-impl</artifactId>
+
+       <name>${bundle.symbolicName} [${bundle.namespace}]</name>
+
+  <packaging>bundle</packaging>
+
+       <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <version>${maven-surefire-plugin.version}</version>
+        <configuration>
+          <redirectTestOutputToFile>true</redirectTestOutputToFile>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>${maven-bundle-plugin.version}</version>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-SymbolicName>${bundle.symbolicName}</Bundle-SymbolicName>
+            <Bundle-Version>${project.version}</Bundle-Version>
+                        <Export-Package>!${bundle.namespace}.*</Export-Package>
+                        
<Private-Package>${bundle.namespace}.*</Private-Package>
+                        
<Bundle-Activator>${bundle.namespace}.CyActivator</Bundle-Activator>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+       </build>
+
+       <repositories>
+               <repository>
+                       <id>cytoscape_snapshots</id>
+                       <snapshots>
+                               <enabled>true</enabled>
+                       </snapshots>
+                       <releases>
+                               <enabled>false</enabled>
+                       </releases>
+                       <name>Cytoscape Snapshots</name>
+                       
<url>http://code.cytoscape.org/nexus/content/repositories/snapshots/</url>
+               </repository>
+               <repository>
+                       <id>cytoscape_releases</id>
+                       <snapshots>
+                               <enabled>false</enabled>
+                       </snapshots>
+                       <releases>
+                               <enabled>true</enabled>
+                       </releases>
+                       <name>Cytoscape Releases</name>
+                       
<url>http://code.cytoscape.org/nexus/content/repositories/releases/</url>
+               </repository>
+       </repositories>
+
+       <dependencies>
+               <dependency>
+                       <groupId>org.cytoscape</groupId>
+                       <artifactId>group-api</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.cytoscape</groupId>
+                       <artifactId>group-api</artifactId>
+                       <scope>test</scope>
+                       <type>test-jar</type>
+               </dependency>
+               <dependency>
+                       <groupId>org.cytoscape</groupId>
+                       <artifactId>model-impl</artifactId>
+                       <scope>test</scope>
+                       <version>${project.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.cytoscape</groupId>
+                       <artifactId>model-impl</artifactId>
+                       <scope>test</scope>
+                       <type>test-jar</type>
+                       <version>${project.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.cytoscape</groupId>
+                       <artifactId>event-api</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.cytoscape</groupId>
+                       <artifactId>model-api</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.cytoscape</groupId>
+                       <artifactId>viewmodel-api</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.cytoscape</groupId>
+                       <artifactId>presentation-api</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.cytoscape</groupId>
+                       <artifactId>vizmap-api</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>junit</groupId>
+                       <artifactId>junit</artifactId>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.cytoscape</groupId>
+                       <artifactId>service-api</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.mockito</groupId>
+                       <artifactId>mockito-all</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>com.googlecode.guava-osgi</groupId>
+                       <artifactId>guava-osgi</artifactId>
+                       <version>9.0.0</version>
+               </dependency>
+       </dependencies>
+</project>
+

Added: 
core3/impl/trunk/group-view-impl/src/main/java/org/cytoscape/group/view/internal/CyActivator.java
===================================================================
--- 
core3/impl/trunk/group-view-impl/src/main/java/org/cytoscape/group/view/internal/CyActivator.java
                           (rev 0)
+++ 
core3/impl/trunk/group-view-impl/src/main/java/org/cytoscape/group/view/internal/CyActivator.java
   2012-01-26 18:27:23 UTC (rev 28115)
@@ -0,0 +1,40 @@
+
+package org.cytoscape.group.view.internal;
+
+import org.cytoscape.event.CyEventHelper;
+import org.cytoscape.service.util.CyServiceRegistrar;
+
+import org.osgi.framework.BundleContext;
+
+import org.cytoscape.group.CyGroupManager;
+import org.cytoscape.group.events.GroupAboutToCollapseListener;
+import org.cytoscape.group.events.GroupCollapsedListener;
+import org.cytoscape.view.model.CyNetworkViewManager;
+import org.cytoscape.view.vizmap.VisualMappingManager;
+
+
+import org.cytoscape.service.util.AbstractCyActivator;
+
+import java.util.Properties;
+
+
+public class CyActivator extends AbstractCyActivator {
+       public CyActivator() {
+               super();
+       }
+
+       public void start(BundleContext bc) {
+               CyEventHelper cyEventHelperServiceRef = 
getService(bc,CyEventHelper.class);
+               CyServiceRegistrar cyServiceRegistrarServiceRef = 
getService(bc,CyServiceRegistrar.class);
+               CyGroupManager cyGroupManager = 
getService(bc,CyGroupManager.class);
+               CyNetworkViewManager cyNetworkViewManager = 
getService(bc,CyNetworkViewManager.class);
+               VisualMappingManager styleManager = 
getService(bc,VisualMappingManager.class);
+
+               GroupViewCollapseHandler gvcHandler = 
+                       new GroupViewCollapseHandler(cyGroupManager, 
cyNetworkViewManager, styleManager);
+
+               
registerService(bc,gvcHandler,GroupAboutToCollapseListener.class, new 
Properties());
+               registerService(bc,gvcHandler,GroupCollapsedListener.class, new 
Properties());
+       }
+}
+

Added: 
core3/impl/trunk/group-view-impl/src/main/java/org/cytoscape/group/view/internal/GroupViewCollapseHandler.java
===================================================================
--- 
core3/impl/trunk/group-view-impl/src/main/java/org/cytoscape/group/view/internal/GroupViewCollapseHandler.java
                              (rev 0)
+++ 
core3/impl/trunk/group-view-impl/src/main/java/org/cytoscape/group/view/internal/GroupViewCollapseHandler.java
      2012-01-26 18:27:23 UTC (rev 28115)
@@ -0,0 +1,227 @@
+/*
+ File: GroupViewCollapseHandler.java
+
+ Copyright (c) 2006, 2010, The Cytoscape Consortium (www.cytoscape.org)
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of the License, or
+ any later version.
+
+ This library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  The software and
+ documentation provided hereunder is on an "as is" basis, and the
+ Institute for Systems Biology and the Whitehead Institute
+ have no obligations to provide maintenance, support,
+ updates, enhancements or modifications.  In no event shall the
+ Institute for Systems Biology and the Whitehead Institute
+ be liable to any party for direct, indirect, special,
+ incidental or consequential damages, including lost profits, arising
+ out of the use of this software and its documentation, even if the
+ Institute for Systems Biology and the Whitehead Institute
+ have been advised of the possibility of such damage.  See
+ the GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+package org.cytoscape.group.view.internal;
+
+import java.awt.Dimension;
+import java.util.List;
+
+import org.cytoscape.group.CyGroup;
+import org.cytoscape.group.CyGroupManager;
+import org.cytoscape.group.events.GroupAboutToCollapseEvent;
+import org.cytoscape.group.events.GroupAboutToCollapseListener;
+import org.cytoscape.group.events.GroupCollapsedEvent;
+import org.cytoscape.group.events.GroupCollapsedListener;
+
+import org.cytoscape.model.CyNetwork;
+import org.cytoscape.model.CyNode;
+import org.cytoscape.model.CyRow;
+import org.cytoscape.model.CyTable;
+import org.cytoscape.model.subnetwork.CyRootNetwork;
+
+import org.cytoscape.view.model.CyNetworkView;
+import org.cytoscape.view.model.CyNetworkViewManager;
+import org.cytoscape.view.model.View;
+import org.cytoscape.view.model.VisualProperty;
+import org.cytoscape.view.presentation.property.MinimalVisualLexicon;
+import org.cytoscape.view.vizmap.VisualMappingManager;
+import org.cytoscape.view.vizmap.VisualStyle;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Handle the view portion of group collapse/expand
+ */
+public class GroupViewCollapseHandler implements GroupAboutToCollapseListener,
+                                                 GroupCollapsedListener
+{
+
+       private final CyGroupManager cyGroupManager;
+       private final CyNetworkViewManager cyNetworkViewManager;
+       private final VisualMappingManager cyStyleManager;
+       private static final Logger logger = 
LoggerFactory.getLogger(GroupViewCollapseHandler.class);
+       private static final VisualProperty<Double> xLoc = 
MinimalVisualLexicon.NODE_X_LOCATION;
+       private static final VisualProperty<Double> yLoc = 
MinimalVisualLexicon.NODE_Y_LOCATION;
+
+       private static final String X_OFFSET_ATTR = "__xOffset";
+       private static final String Y_OFFSET_ATTR = "__yOffset";
+       private static final String X_LOCATION_ATTR = "__xLocation";
+       private static final String Y_LOCATION_ATTR = "__yLocation";
+
+       /**
+        * 
+        * @param cyEventHelper
+        */
+       public GroupViewCollapseHandler(final CyGroupManager groupManager,
+                                       final CyNetworkViewManager viewManager,
+                                       final VisualMappingManager 
styleManager) {
+               this.cyGroupManager = groupManager;
+               this.cyNetworkViewManager = viewManager;
+               this.cyStyleManager = styleManager;
+       }
+
+       public void handleEvent(GroupAboutToCollapseEvent e) {
+               CyNetwork network = e.getNetwork();
+               CyGroup group = e.getSource();
+               CyRootNetwork rootNetwork = group.getRootNetwork();
+               CyNetworkView view = 
cyNetworkViewManager.getNetworkView(network);
+
+               if (e.collapsing()) {
+                       System.out.println("Collapsing");
+                       // Calculate the center position of all of the
+                       // member nodes
+                       Dimension center = calculateCenter(view, 
group.getNodeList());
+
+                       System.out.println("Center: "+center);
+
+                       // Save it in the groupNode attribute
+                       updateGroupLocation(rootNetwork, group.getGroupNode(), 
center);
+
+                       // For each member node,
+                       //      calculate the offset for each member node from 
the center
+                       //      save it in the node's attribute
+                       for (CyNode node: group.getNodeList()) {
+                               Dimension offset = calculateOffset(center, 
view, node);
+                               updateNodeOffset(rootNetwork, node, offset);
+                       }
+               } else {
+                       System.out.println("Expanding");
+                       // Get the current position of the groupNode
+                       View<CyNode>nView = 
view.getNodeView(group.getGroupNode());
+                       double x = nView.getVisualProperty(xLoc);
+                       double y = nView.getVisualProperty(yLoc);
+                       // Save it in the groupNode attribute
+                       updateGroupLocation(rootNetwork, group.getGroupNode(), 
getDim(x,y));
+               }
+       }
+
+       public void handleEvent(GroupCollapsedEvent e) {
+               CyNetwork network = e.getNetwork();
+               CyGroup group = e.getSource();
+               CyNetworkView view = 
cyNetworkViewManager.getNetworkView(network);
+               CyRootNetwork rootNetwork = group.getRootNetwork();
+               VisualStyle viewStyle = cyStyleManager.getVisualStyle(view);
+
+               if (e.collapsed()) {
+                       System.out.println("Collapsed");
+                       // Get the location to move the group node to
+                       Dimension d = getLocation(rootNetwork, 
group.getGroupNode());
+                       // Move it.
+                       moveNode(view, group.getGroupNode(), d);
+                       System.out.println("Done");
+               } else {
+                       System.out.println("Expanded");
+                       // Get the location of the group node before it went 
away
+                       Dimension center = getLocation(rootNetwork, 
group.getGroupNode());
+                       // Now, get the offsets for each of the member nodes 
and move them
+                       for (CyNode node: group.getNodeList()) {
+                               Dimension location = 
getOffsetLocation(rootNetwork, node, center);
+                               moveNode(view, node, location);
+                       }
+                       System.out.println("Done");
+               }
+               // viewStyle.apply(view);
+       }
+
+       private Dimension calculateCenter(CyNetworkView view, List<CyNode> 
nodeList) {
+               double xCenter = 0.0d;
+               double yCenter = 0.0d;
+
+               for (CyNode node: nodeList) {
+                       View<CyNode>nView = view.getNodeView(node);
+                       xCenter += (nView.getVisualProperty(xLoc)) / 
nodeList.size();
+                       yCenter += (nView.getVisualProperty(yLoc)) / 
nodeList.size();
+               }
+               return getDim(xCenter, yCenter);
+       }
+
+       private Dimension calculateOffset(Dimension center, CyNetworkView view, 
CyNode node) {
+               View<CyNode>nView = view.getNodeView(node);
+               double xOffset = nView.getVisualProperty(xLoc) - 
center.getWidth();
+               double yOffset = nView.getVisualProperty(yLoc) - 
center.getHeight();
+               return getDim(xOffset, yOffset);
+       }
+
+       private Dimension getLocation(CyNetwork network, CyNode node) {
+               CyRow nodeRow = network.getRow(node, CyNetwork.HIDDEN_ATTRS);
+               double x = nodeRow.get(X_LOCATION_ATTR, Double.class);
+               double y = nodeRow.get(Y_LOCATION_ATTR, Double.class);
+               return getDim(x,y);
+       }
+
+       private Dimension getOffsetLocation(CyNetwork network, CyNode node, 
Dimension center) {
+               CyRow nodeRow = network.getRow(node, CyNetwork.HIDDEN_ATTRS);
+               double xLocation = nodeRow.get(X_OFFSET_ATTR, Double.class) + 
center.getWidth();
+               double yLocation = nodeRow.get(Y_OFFSET_ATTR, Double.class) + 
center.getHeight();
+               return getDim(xLocation, yLocation);
+       }
+
+       private void updateNodeOffset(CyNetwork network, CyNode node, Dimension 
offset) {
+               CyRow nodeRow = network.getRow(node, CyNetwork.HIDDEN_ATTRS);
+               createColumnIfNeeded(nodeRow.getTable(), X_OFFSET_ATTR, 
Double.class);
+               createColumnIfNeeded(nodeRow.getTable(), Y_OFFSET_ATTR, 
Double.class);
+               nodeRow.set(X_OFFSET_ATTR, new Double(offset.getWidth()));
+               nodeRow.set(Y_OFFSET_ATTR, new Double(offset.getHeight()));
+               System.out.println("Location for "+node+" is "+
+                                  nodeRow.get(X_OFFSET_ATTR, Double.class)+","+
+                                  nodeRow.get(Y_OFFSET_ATTR, Double.class));
+       }
+
+       private void updateGroupLocation(CyNetwork network, CyNode node, 
Dimension offset) {
+               CyRow nodeRow = network.getRow(node, CyNetwork.HIDDEN_ATTRS);
+               createColumnIfNeeded(nodeRow.getTable(), X_LOCATION_ATTR, 
Double.class);
+               createColumnIfNeeded(nodeRow.getTable(), Y_LOCATION_ATTR, 
Double.class);
+               nodeRow.set(X_LOCATION_ATTR, new Double(offset.getWidth()));
+               nodeRow.set(Y_LOCATION_ATTR, new Double(offset.getHeight()));
+               System.out.println("Location for "+node+" is "+
+                                  nodeRow.get(X_LOCATION_ATTR, 
Double.class)+","+
+                                  nodeRow.get(Y_LOCATION_ATTR, Double.class));
+       }
+
+       private void moveNode(CyNetworkView view, CyNode node, Dimension 
location) {
+               View<CyNode>nView = view.getNodeView(node);
+               nView.setVisualProperty(xLoc, location.getWidth());
+               nView.setVisualProperty(yLoc, location.getHeight());
+               System.out.println("Moving node "+node+" to "+
+                                  location.getWidth()+","+
+                                  location.getHeight());
+       }
+
+       private void createColumnIfNeeded(CyTable table, String name, Class 
type) {
+               if (table.getColumn(name) == null)
+                       table.createColumn(name, type, false);
+       }
+
+       private Dimension getDim(double x, double y) {
+               Dimension d = new Dimension();
+               d.setSize(x, y);
+               return d;
+       }
+}

-- 
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