Mercurial > hg > ccmieditor
view java/src/uk/ac/qmul/eecs/ccmi/simpletemplate/SimpleShapeEdge.java @ 8:ea7885bd9bff tip
fixed bug : render solid line as dotted/dashed when moving the stylus from dotted/dashed to solid
author | ccmi-guest |
---|---|
date | Thu, 03 Jul 2014 16:12:20 +0100 |
parents | d66dd5880081 |
children |
line wrap: on
line source
/* 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.DiagramEventSource; 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; /** * An edge rendered as a straight, dotted or dashed line. The edge can have an arrow head * at each end. Possible arrow heads are : * <ul> * <li> Triangle * <li> Black Triangle * <li> V * <li> Half V * <li> Diamond * <li> Black Diamond * <li> Tail * </ul> * */ @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, Object source){ currentHeads.remove(n); return super.removeNode(n,source); } @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, Object source){ Node n = (Node)diagramNode; if(index == NO_END_DESCRIPTION_INDEX){ currentHeads.remove(n); super.setEndDescription(n, index,source); }else{ ArrowHead h = heads[index]; currentHeads.put(n, h); super.setEndDescription(n, index,source); } } @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,DiagramEventSource.PERS); } } } @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); } }