Mercurial > hg > ccmieditor
diff java/src/uk/ac/qmul/eecs/ccmi/simpletemplate/SimpleShapeEdge.java @ 0:9418ab7b7f3f
Initial import
author | Fiore Martin <fiore@eecs.qmul.ac.uk> |
---|---|
date | Fri, 16 Dec 2011 17:35:51 +0000 |
parents | |
children | 9e67171477bc |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/java/src/uk/ac/qmul/eecs/ccmi/simpletemplate/SimpleShapeEdge.java Fri Dec 16 17:35:51 2011 +0000 @@ -0,0 +1,321 @@ +/* + CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool + + Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package uk.ac.qmul.eecs.ccmi.simpletemplate; + +import java.awt.Graphics2D; +import java.awt.Stroke; +import java.awt.geom.Line2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import uk.ac.qmul.eecs.ccmi.diagrammodel.DiagramNode; +import uk.ac.qmul.eecs.ccmi.gui.Edge; +import uk.ac.qmul.eecs.ccmi.gui.GraphElement; +import uk.ac.qmul.eecs.ccmi.gui.LineStyle; +import uk.ac.qmul.eecs.ccmi.gui.Node; +import uk.ac.qmul.eecs.ccmi.gui.persistence.PersistenceManager; +import uk.ac.qmul.eecs.ccmi.sound.SoundFactory; + +@SuppressWarnings("serial") +public class SimpleShapeEdge extends Edge { + + public SimpleShapeEdge(String type, LineStyle style, ArrowHead[] heads, String[] availableEndDescriptions, int minAttachedNodes, int maxAttachedNodes) { + super(type,availableEndDescriptions,minAttachedNodes,maxAttachedNodes,style); + this.heads = heads; + currentHeads = new HashMap<Node,ArrowHead>(); + } + + @Override + public boolean removeNode(DiagramNode n){ + currentHeads.remove(n); + return super.removeNode(n); + } + + @Override + public void draw(Graphics2D g2) { + Stroke oldStroke = g2.getStroke(); + g2.setStroke(getStyle().getStroke()); + + /* straight line */ + if(points.isEmpty()){ + Line2D line = getSegment(getNodeAt(0),getNodeAt(1)); + g2.draw(line); + + /* draw arrow heads if any */ + ArrowHead h = currentHeads.get(getNodeAt(0)); + if( h != null && h != ArrowHead.TAIL){ + Line2D revLine = getSegment(getNodeAt(1),getNodeAt(0)); + h.draw(g2, revLine.getP1(), revLine.getP2()); + } + h = currentHeads.get(getNodeAt(1)); + if( h != null && h != ArrowHead.TAIL){ + h.draw(g2, line.getP1(), line.getP2()); + } + + /* draw labels if any */ + String label; + if((label = getEndLabel(getNodeAt(0))) != null){ + EdgeDrawSupport.drawString(g2, line.getP2(), line.getP1(), currentHeads.get(getNodeAt(0)), label, false); + } + if((label = getEndLabel(getNodeAt(1))) != null){ + EdgeDrawSupport.drawString(g2, line.getP1(), line.getP2(), currentHeads.get(getNodeAt(1)), label, false); + } + + /* draw name if any */ + if(!getName().isEmpty()){ + EdgeDrawSupport.drawString(g2, line.getP2(), line.getP1(), null, getName(), true); + } + if(!"".equals(getNotes())) + EdgeDrawSupport.drawMarker(g2,line.getP1(),line.getP2()); + }else{ + /* edge with inner points: it can be a multiended(eventually bended) edge or a straight bended edge */ + + /* arrow and labels are drawn in the same way in either case */ + for(InnerPoint p : points){ + for(GraphElement ge : p.getNeighbours()){ + g2.draw(getSegment(p,ge)); + if(ge instanceof Node){ // this is the inner point which is connected to a Node + /* draw arrow if any */ + ArrowHead h = currentHeads.get((Node)ge); + if(h != null && h != ArrowHead.TAIL){ + Line2D line = getSegment(p,ge); + h.draw(g2, line.getP1() , line.getP2()); + } + + /* draw label if any */ + String label = getEndLabel((Node)ge); + if(label != null){ + Line2D line = getSegment(p,ge); + EdgeDrawSupport.drawString(g2, line.getP1(), line.getP2(), currentHeads.get((Node)ge), label, false); + } + } + } + p.draw(g2); + } + /* name is drawn differently : + * for multiended edges name is drawn on the master inner point + * for two ends bended name is drawn in (about) the middle point of the edge + */ + + if(masterInnerPoint != null){/* multiended edge */ + Rectangle2D bounds = masterInnerPoint.getBounds(); + Point2D p = new Point2D.Double(bounds.getCenterX() - 1,bounds.getCenterY()); + Point2D q = new Point2D.Double(bounds.getCenterX() + 1,bounds.getCenterY()); + if(!getName().isEmpty()) + EdgeDrawSupport.drawString(g2, p, q, null, getName(), true); + if(!"".equals(getNotes())) + EdgeDrawSupport.drawMarker(g2,p,q); + }else{ + /* straight edge which has been bended */ + GraphElement ge1 = getNodeAt(0); + GraphElement ge2 = getNodeAt(1); + InnerPoint c1 = null; + InnerPoint c2 = null; + + for(InnerPoint innp : points){ + if(innp.getNeighbours().contains(ge1)){ + c1 = innp; + } + if(innp.getNeighbours().contains(ge2)){ + c2 = innp; + } + } + + /* draw name if any */ + if(!getName().isEmpty()){ + /* we only have two nodes but the edge has been bended */ + while((c1 != c2)&&(!c2.getNeighbours().contains(c1))){ + if(c1.getNeighbours().get(0) == ge1){ + ge1 = c1; + c1 = (InnerPoint)c1.getNeighbours().get(1); + } + else{ + ge1 = c1; + c1 = (InnerPoint)c1.getNeighbours().get(0); + } + if(c2.getNeighbours().get(0) == ge2){ + ge2 = c2; + c2 = (InnerPoint)c2.getNeighbours().get(1); + } + else{ + ge2 = c2; + c2 = (InnerPoint)c2.getNeighbours().get(0); + } + } + + Point2D p = new Point2D.Double(); + Point2D q = new Point2D.Double(); + if(c1 == c2){ + Rectangle2D bounds = c1.getBounds(); + p.setLocation( bounds.getCenterX() - 1,bounds.getCenterY()); + q.setLocation( bounds.getCenterX() + 1,bounds.getCenterY()); + }else{ + Rectangle2D bounds = c1.getBounds(); + p.setLocation( bounds.getCenterX(),bounds.getCenterY()); + bounds = c2.getBounds(); + q.setLocation(bounds.getCenterX(),bounds.getCenterY()); + + } + if(!getName().isEmpty()) + EdgeDrawSupport.drawString(g2, p, q, null, getName(), true); + if(!"".equals(getNotes())) + EdgeDrawSupport.drawMarker(g2,p,q); + } + } + } + g2.setStroke(oldStroke); + } + + public Rectangle2D getBounds() { + if(points.isEmpty()){ + return getSegment(getNodeAt(0), getNodeAt(1)).getBounds2D(); + }else{ + Rectangle2D bounds = points.get(0).getBounds(); + for(InnerPoint p : points){ + for(GraphElement ge : p.getNeighbours()) + bounds.add(getSegment(p,ge).getBounds2D()); + } + return bounds; + } + } + + public ArrowHead[] getHeads() { + return heads; + } + + @Override + public InputStream getSound(){ + switch(getStyle()){ + case Dashed : return dashedSound; + case Dotted : return dottedSound; + default : return straightSound; + } + } + + @Override + public void setEndDescription(DiagramNode diagramNode, int index){ + Node n = (Node)diagramNode; + if(index == NO_END_DESCRIPTION_INDEX){ + currentHeads.remove(n); + super.setEndDescription(n, index); + }else{ + ArrowHead h = heads[index]; + currentHeads.put(n, h); + super.setEndDescription(n, index); + } + } + + @Override + public void encode(Document doc, Element parent, List<Node> nodes){ + super.encode(doc, parent, nodes); + /* add the head attribute to the NODE tag */ + NodeList nodeTagList = parent.getElementsByTagName(PersistenceManager.NODE); + for(int i = 0 ; i< nodeTagList.getLength(); i++){ + Element nodeTag = (Element)nodeTagList.item(i); + String nodeIdAsString = nodeTag.getAttribute(PersistenceManager.ID); + long nodeId = Long.parseLong(nodeIdAsString); + Node node = null; + /* find the node with the id of the tag */ + for(Node n : nodes) + if(n.getId() == nodeId){ + node = n; + break; + } + String head = (currentHeads.get(node) == null) ? "" : currentHeads.get(node).toString(); + nodeTag.setAttribute(SimpleShapePrototypePersistenceDelegate.HEAD, head ); + } + } + + @Override + public void decode(Document doc, Element edgeTag, Map<String,Node> nodesId) throws IOException{ + super.decode(doc, edgeTag, nodesId); + NodeList nodeList = edgeTag.getElementsByTagName(PersistenceManager.NODE); + for(int i=0; i<nodeList.getLength(); i++){ + Element nodeTag = (Element)nodeList.item(i); + String id = nodeTag.getAttribute(PersistenceManager.ID); + if(id.isEmpty()) + throw new IOException(); + String head = nodeTag.getAttribute(SimpleShapePrototypePersistenceDelegate.HEAD); + if(!head.isEmpty()){ + ArrowHead headShape = null; + try{ + headShape = ArrowHead.getArrowHeadFromString(head); + }catch(IOException e){ + throw e; + } + currentHeads.put(nodesId.get(id), headShape); + int headDescriptionIndex = Edge.NO_END_DESCRIPTION_INDEX; + for(int j=0; j<heads.length;j++){ + if(heads[j].equals(headShape)){ + headDescriptionIndex = j; + break; + } + } + setEndDescription(nodesId.get(id),headDescriptionIndex); + } + } + } + + @Override + public int getStipplePattern(){ + int result = 0; + switch(getStyle()){ + case Solid : result = 0xFFFF; + break; + case Dashed : result = 0xF0F0; + break; + case Dotted : result = 0xAAAA ; + break; + } + return result; + } + + @Override + public Object clone(){ + return new SimpleShapeEdge(getType(), getStyle(), heads, getAvailableEndDescriptions(), getMinAttachedNodes(), getMaxAttachedNodes() ); + } + + + + private ArrowHead[] heads; + private Map<Node,ArrowHead> currentHeads; + private static InputStream straightSound; + private static InputStream dottedSound; + private static InputStream dashedSound; + + static{ + Class<SimpleShapeEdge> c = SimpleShapeEdge.class; + straightSound = c.getResourceAsStream("audio/straightLine.mp3"); + dottedSound = c.getResourceAsStream("audio/dashedLine.mp3"); + dashedSound = c.getResourceAsStream("audio/dottedLine.mp3"); + SoundFactory.getInstance().loadSound(straightSound); + SoundFactory.getInstance().loadSound(dottedSound); + SoundFactory.getInstance().loadSound(dashedSound); + } +}