package org.archstudio.utils.bna.gexf; import java.awt.geom.Point2D; import java.io.File; import java.io.IOException; import java.math.BigInteger; import java.util.Map; import org.archstudio.bna.IBNAModel; import org.archstudio.bna.IBNAView; import org.archstudio.bna.IBNAWorld; import org.archstudio.bna.ICoordinate; import org.archstudio.bna.IThing; import org.archstudio.bna.facets.IHasBoundingBox; import org.archstudio.bna.facets.IHasColor; import org.archstudio.bna.facets.IHasMutableAnchorPoint; import org.archstudio.bna.facets.IHasMutableBoundingBox; import org.archstudio.bna.facets.IHasMutableReferencePoint; import org.archstudio.bna.facets.IHasText; import org.archstudio.bna.facets.IHasToolTip; import org.archstudio.bna.logics.AbstractThingLogic; import org.archstudio.bna.ui.IBNAMenuListener2; import org.archstudio.bna.utils.Assemblies; import org.archstudio.bna.utils.BNAAction; import org.archstudio.bna.utils.BNAUtils; import org.archstudio.bna.utils.BNAUtils2.ThingsAtLocation; import org.archstudio.swtutils.SWTWidgetUtils; import org.archstudio.sysutils.SystemUtils; import org.archstudio.utils.bna.dot.Edge; import org.archstudio.utils.bna.dot.Node; import org.archstudio.xarchadt.IXArchADT; import org.archstudio.xarchadt.ObjRef; import org.archstudio.xarchadt.XArchADTProxy; import org.archstudio.xarchadt.core.XArchADTImpl; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.URI; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.FileDialog; import org.xml.sax.SAXException; import com.google.common.collect.Maps; import com.google.common.io.Files; import net.gexf_1_2.gexf.DocumentRoot; import net.gexf_1_2.gexf.EdgeContent; import net.gexf_1_2.gexf.EdgesContent; import net.gexf_1_2.gexf.GexfContent; import net.gexf_1_2.gexf.GexfPackage; import net.gexf_1_2.gexf.GraphContent; import net.gexf_1_2.gexf.NodeContent; import net.gexf_1_2.gexf.NodesContent; import net.gexf_1_2.viz.ColorContent; import net.gexf_1_2.viz.PositionContent; import net.gexf_1_2.viz.SizeContent; import net.gexf_1_2.viz.VizPackage; public class ExportImportGexf extends AbstractThingLogic implements IBNAMenuListener2 { public ExportImportGexf(IBNAWorld world) { super(world); } @Override public void fillMenu(final IBNAView view, ICoordinate location, ThingsAtLocation thingsAtLocation, IMenuManager menuManager) { BNAUtils.checkLock(); if (thingsAtLocation.getViewAtLocation() != null) { menuManager.add(new BNAAction("Export GEXF") { @Override public void runWithLock() { try { exportGexf(view); } catch (Exception e) { e.printStackTrace(); MessageDialog.openError(view.getBNAUI().getComposite().getShell(), "Error", e.getMessage()); } } }); menuManager.add(new BNAAction("Import GEXF") { @Override public void runWithLock() { try { importGexf(view); } catch (Exception e) { e.printStackTrace(); MessageDialog.openError(view.getBNAUI().getComposite().getShell(), "Error", e.getMessage()); } } }); } else { menuManager.add(SWTWidgetUtils.createNoAction("Export GEXF")); menuManager.add(SWTWidgetUtils.createNoAction("Import GEXF")); } } protected void exportGexf(IBNAView view) throws IOException { FileDialog fd = new FileDialog(view.getBNAUI().getComposite().getShell(), SWT.SAVE); fd.setFilterExtensions(new String[] {"*.gexf"}); String filepath = fd.open(); if (filepath != null) { exportGexf(view, new File(filepath)); } } protected void exportGexf(IBNAView view, File file) throws IOException { if (!file.getParentFile().exists() && !file.getParentFile().mkdirs()) { throw new IOException("Cannot create folder: " + file.getParentFile().toString()); } IXArchADT xarch = new XArchADTImpl(); ObjRef documentRef = xarch.createDocument(URI.createURI(file.toURI().toString()), GexfPackage.eINSTANCE.getNsURI()); DocumentRoot document = XArchADTProxy.proxy(xarch, documentRef); GexfContent gexf = XArchADTProxy.create(xarch, GexfPackage.Literals.GEXF_CONTENT); document.setGexf(gexf); GraphContent graph = XArchADTProxy.create(xarch, GexfPackage.Literals.GRAPH_CONTENT); gexf.setGraph(graph); Map<String, Node> nodes = Node.scanForNodes(world, model.getAllThings(), 1); Map<String, Edge> edges = Edge.scanForEdges(world, model.getAllThings(), nodes); NodesContent nodesc = XArchADTProxy.create(xarch, GexfPackage.Literals.NODES_CONTENT); graph.getNodes().add(nodesc); EList<NodeContent> xadlNodes = nodesc.getNode(); for (Node node : Edge.filterNodesByEdges(nodes.values(), edges.values())) { IThing t = node.getThing(); NodeContent xadlNode = XArchADTProxy.create(xarch, GexfPackage.Literals.NODE_CONTENT); xadlNode.setId(Node.getUniqueId(node.getThing())); xadlNode.setLabel(getText(model, t)); Point2D p = BNAUtils.getCentralPoint(t); PositionContent position = XArchADTProxy.create(xarch, VizPackage.Literals.POSITION_CONTENT); position.setX((float) p.getX()); position.setY((float) -p.getY()); xadlNode.getPosition().add(position); if (t instanceof IHasBoundingBox) { Rectangle r = ((IHasBoundingBox) t).getBoundingBox(); SizeContent size = XArchADTProxy.create(xarch, VizPackage.Literals.SIZE_CONTENT); size.setValue((float) Math.sqrt(r.width * r.width / 4 + r.height * r.height / 4)); xadlNode.getSize().add(size); } RGB rgb = t.get(IHasColor.COLOR_KEY); if (rgb != null) { ColorContent color = XArchADTProxy.create(xarch, VizPackage.Literals.COLOR_CONTENT); color.setR(BigInteger.valueOf(rgb.red)); color.setG(BigInteger.valueOf(rgb.green)); color.setB(BigInteger.valueOf(rgb.blue)); xadlNode.getColor().add(color); } xadlNodes.add(xadlNode); } EdgesContent edgesc = XArchADTProxy.create(xarch, GexfPackage.Literals.EDGES_CONTENT); graph.getEdges().add(edgesc); EList<EdgeContent> xadlEdges = edgesc.getEdge(); for (Edge edge : edges.values()) { IThing t = edge.getThing(); Node fromNode = edge.getFromEndpoint().getNode(); Node toNode = edge.getToEndpoint().getNode(); int weight = 1; EdgeContent xadlEdge = XArchADTProxy.create(xarch, GexfPackage.Literals.EDGE_CONTENT); xadlEdge.setId(Node.getUniqueId(t)); xadlEdge.setSource(Node.getUniqueId(fromNode.getThing())); xadlEdge.setTarget(Node.getUniqueId(toNode.getThing())); xadlEdge.setWeight(weight); xadlEdge.setLabel(getText(model, t)); xadlEdges.add(xadlEdge); } Files.write(xarch.serialize(URI.createURI(file.toURI().toString())), file); } private String getText(IBNAModel model, IThing t) { IHasText textThing = Assemblies.getThingOfType(model, t, IHasText.class); if (textThing != null) { return textThing.getText(); } IThing tooltipThing = Assemblies.getThingWithProperty(model, t, IHasToolTip.TOOL_TIP_KEY); if (tooltipThing != null) { return tooltipThing.get(IHasToolTip.TOOL_TIP_KEY); } return "[undefined]"; } protected void importGexf(IBNAView view) throws SAXException, IOException { FileDialog fd = new FileDialog(view.getBNAUI().getComposite().getShell(), SWT.OPEN); fd.setFilterExtensions(new String[] {"*.gexf"}); String filepath = fd.open(); if (filepath != null) { importGexf(view, new File(filepath)); } } protected void importGexf(IBNAView view, File file) throws SAXException, IOException { String contents = new String(Files.toByteArray(file)); contents = contents.replaceAll("viz:", ""); contents = contents.replaceAll("http://www.gexf.net/1.1draft", "http://www.gexf.net/1.2draft"); contents = contents.replaceAll("version=\"1.1\"", "version=\"1.2\""); IXArchADT xarch = new XArchADTImpl(); ObjRef documentRef = xarch.load(URI.createURI(file.toURI().toString()), contents.getBytes()); DocumentRoot document = XArchADTProxy.proxy(xarch, documentRef); // Extract node locations. Map<String, Point> positions = Maps.newHashMap(); float factor = 1f; for (NodesContent xadlNodes : document.getGexf().getGraph().getNodes()) { for (NodeContent xadlNode : xadlNodes.getNode()) { for (PositionContent position : xadlNode.getPosition()) { Point p = new Point(SystemUtils.round(factor * position.getX()), -SystemUtils.round(factor * position.getY())); positions.put(xadlNode.getId().toString(), p); } } } // Update BNA model. for (IThing t : view.getBNAWorld().getBNAModel().getAllThings()) { Point p = positions.get(Node.getUniqueId(t)); if (p != null) { if (t instanceof IHasMutableBoundingBox) { Rectangle r = ((IHasMutableBoundingBox) t).getBoundingBox(); r.x = p.x - r.width / 2; r.y = p.y - r.height / 2; ((IHasMutableBoundingBox) t).setBoundingBox(r); } else if (t instanceof IHasMutableAnchorPoint) { ((IHasMutableAnchorPoint) t).setAnchorPoint(BNAUtils.toPoint2D(p)); } else if (t instanceof IHasMutableReferencePoint) { ((IHasMutableReferencePoint) t).setReferencePoint(p); } } } } }