Mercurial > hg > ccmieditor
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:9418ab7b7f3f |
---|---|
1 /* | |
2 CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool | |
3 | |
4 Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/) | |
5 | |
6 This program is free software: you can redistribute it and/or modify | |
7 it under the terms of the GNU General Public License as published by | |
8 the Free Software Foundation, either version 3 of the License, or | |
9 (at your option) any later version. | |
10 | |
11 This program is distributed in the hope that it will be useful, | |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 GNU General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 */ | |
19 | |
20 package uk.ac.qmul.eecs.ccmi.simpletemplate; | |
21 | |
22 import java.awt.Graphics2D; | |
23 import java.awt.Stroke; | |
24 import java.awt.geom.Line2D; | |
25 import java.awt.geom.Point2D; | |
26 import java.awt.geom.Rectangle2D; | |
27 import java.io.IOException; | |
28 import java.io.InputStream; | |
29 import java.util.HashMap; | |
30 import java.util.List; | |
31 import java.util.Map; | |
32 | |
33 import org.w3c.dom.Document; | |
34 import org.w3c.dom.Element; | |
35 import org.w3c.dom.NodeList; | |
36 | |
37 import uk.ac.qmul.eecs.ccmi.diagrammodel.DiagramNode; | |
38 import uk.ac.qmul.eecs.ccmi.gui.Edge; | |
39 import uk.ac.qmul.eecs.ccmi.gui.GraphElement; | |
40 import uk.ac.qmul.eecs.ccmi.gui.LineStyle; | |
41 import uk.ac.qmul.eecs.ccmi.gui.Node; | |
42 import uk.ac.qmul.eecs.ccmi.gui.persistence.PersistenceManager; | |
43 import uk.ac.qmul.eecs.ccmi.sound.SoundFactory; | |
44 | |
45 @SuppressWarnings("serial") | |
46 public class SimpleShapeEdge extends Edge { | |
47 | |
48 public SimpleShapeEdge(String type, LineStyle style, ArrowHead[] heads, String[] availableEndDescriptions, int minAttachedNodes, int maxAttachedNodes) { | |
49 super(type,availableEndDescriptions,minAttachedNodes,maxAttachedNodes,style); | |
50 this.heads = heads; | |
51 currentHeads = new HashMap<Node,ArrowHead>(); | |
52 } | |
53 | |
54 @Override | |
55 public boolean removeNode(DiagramNode n){ | |
56 currentHeads.remove(n); | |
57 return super.removeNode(n); | |
58 } | |
59 | |
60 @Override | |
61 public void draw(Graphics2D g2) { | |
62 Stroke oldStroke = g2.getStroke(); | |
63 g2.setStroke(getStyle().getStroke()); | |
64 | |
65 /* straight line */ | |
66 if(points.isEmpty()){ | |
67 Line2D line = getSegment(getNodeAt(0),getNodeAt(1)); | |
68 g2.draw(line); | |
69 | |
70 /* draw arrow heads if any */ | |
71 ArrowHead h = currentHeads.get(getNodeAt(0)); | |
72 if( h != null && h != ArrowHead.TAIL){ | |
73 Line2D revLine = getSegment(getNodeAt(1),getNodeAt(0)); | |
74 h.draw(g2, revLine.getP1(), revLine.getP2()); | |
75 } | |
76 h = currentHeads.get(getNodeAt(1)); | |
77 if( h != null && h != ArrowHead.TAIL){ | |
78 h.draw(g2, line.getP1(), line.getP2()); | |
79 } | |
80 | |
81 /* draw labels if any */ | |
82 String label; | |
83 if((label = getEndLabel(getNodeAt(0))) != null){ | |
84 EdgeDrawSupport.drawString(g2, line.getP2(), line.getP1(), currentHeads.get(getNodeAt(0)), label, false); | |
85 } | |
86 if((label = getEndLabel(getNodeAt(1))) != null){ | |
87 EdgeDrawSupport.drawString(g2, line.getP1(), line.getP2(), currentHeads.get(getNodeAt(1)), label, false); | |
88 } | |
89 | |
90 /* draw name if any */ | |
91 if(!getName().isEmpty()){ | |
92 EdgeDrawSupport.drawString(g2, line.getP2(), line.getP1(), null, getName(), true); | |
93 } | |
94 if(!"".equals(getNotes())) | |
95 EdgeDrawSupport.drawMarker(g2,line.getP1(),line.getP2()); | |
96 }else{ | |
97 /* edge with inner points: it can be a multiended(eventually bended) edge or a straight bended edge */ | |
98 | |
99 /* arrow and labels are drawn in the same way in either case */ | |
100 for(InnerPoint p : points){ | |
101 for(GraphElement ge : p.getNeighbours()){ | |
102 g2.draw(getSegment(p,ge)); | |
103 if(ge instanceof Node){ // this is the inner point which is connected to a Node | |
104 /* draw arrow if any */ | |
105 ArrowHead h = currentHeads.get((Node)ge); | |
106 if(h != null && h != ArrowHead.TAIL){ | |
107 Line2D line = getSegment(p,ge); | |
108 h.draw(g2, line.getP1() , line.getP2()); | |
109 } | |
110 | |
111 /* draw label if any */ | |
112 String label = getEndLabel((Node)ge); | |
113 if(label != null){ | |
114 Line2D line = getSegment(p,ge); | |
115 EdgeDrawSupport.drawString(g2, line.getP1(), line.getP2(), currentHeads.get((Node)ge), label, false); | |
116 } | |
117 } | |
118 } | |
119 p.draw(g2); | |
120 } | |
121 /* name is drawn differently : | |
122 * for multiended edges name is drawn on the master inner point | |
123 * for two ends bended name is drawn in (about) the middle point of the edge | |
124 */ | |
125 | |
126 if(masterInnerPoint != null){/* multiended edge */ | |
127 Rectangle2D bounds = masterInnerPoint.getBounds(); | |
128 Point2D p = new Point2D.Double(bounds.getCenterX() - 1,bounds.getCenterY()); | |
129 Point2D q = new Point2D.Double(bounds.getCenterX() + 1,bounds.getCenterY()); | |
130 if(!getName().isEmpty()) | |
131 EdgeDrawSupport.drawString(g2, p, q, null, getName(), true); | |
132 if(!"".equals(getNotes())) | |
133 EdgeDrawSupport.drawMarker(g2,p,q); | |
134 }else{ | |
135 /* straight edge which has been bended */ | |
136 GraphElement ge1 = getNodeAt(0); | |
137 GraphElement ge2 = getNodeAt(1); | |
138 InnerPoint c1 = null; | |
139 InnerPoint c2 = null; | |
140 | |
141 for(InnerPoint innp : points){ | |
142 if(innp.getNeighbours().contains(ge1)){ | |
143 c1 = innp; | |
144 } | |
145 if(innp.getNeighbours().contains(ge2)){ | |
146 c2 = innp; | |
147 } | |
148 } | |
149 | |
150 /* draw name if any */ | |
151 if(!getName().isEmpty()){ | |
152 /* we only have two nodes but the edge has been bended */ | |
153 while((c1 != c2)&&(!c2.getNeighbours().contains(c1))){ | |
154 if(c1.getNeighbours().get(0) == ge1){ | |
155 ge1 = c1; | |
156 c1 = (InnerPoint)c1.getNeighbours().get(1); | |
157 } | |
158 else{ | |
159 ge1 = c1; | |
160 c1 = (InnerPoint)c1.getNeighbours().get(0); | |
161 } | |
162 if(c2.getNeighbours().get(0) == ge2){ | |
163 ge2 = c2; | |
164 c2 = (InnerPoint)c2.getNeighbours().get(1); | |
165 } | |
166 else{ | |
167 ge2 = c2; | |
168 c2 = (InnerPoint)c2.getNeighbours().get(0); | |
169 } | |
170 } | |
171 | |
172 Point2D p = new Point2D.Double(); | |
173 Point2D q = new Point2D.Double(); | |
174 if(c1 == c2){ | |
175 Rectangle2D bounds = c1.getBounds(); | |
176 p.setLocation( bounds.getCenterX() - 1,bounds.getCenterY()); | |
177 q.setLocation( bounds.getCenterX() + 1,bounds.getCenterY()); | |
178 }else{ | |
179 Rectangle2D bounds = c1.getBounds(); | |
180 p.setLocation( bounds.getCenterX(),bounds.getCenterY()); | |
181 bounds = c2.getBounds(); | |
182 q.setLocation(bounds.getCenterX(),bounds.getCenterY()); | |
183 | |
184 } | |
185 if(!getName().isEmpty()) | |
186 EdgeDrawSupport.drawString(g2, p, q, null, getName(), true); | |
187 if(!"".equals(getNotes())) | |
188 EdgeDrawSupport.drawMarker(g2,p,q); | |
189 } | |
190 } | |
191 } | |
192 g2.setStroke(oldStroke); | |
193 } | |
194 | |
195 public Rectangle2D getBounds() { | |
196 if(points.isEmpty()){ | |
197 return getSegment(getNodeAt(0), getNodeAt(1)).getBounds2D(); | |
198 }else{ | |
199 Rectangle2D bounds = points.get(0).getBounds(); | |
200 for(InnerPoint p : points){ | |
201 for(GraphElement ge : p.getNeighbours()) | |
202 bounds.add(getSegment(p,ge).getBounds2D()); | |
203 } | |
204 return bounds; | |
205 } | |
206 } | |
207 | |
208 public ArrowHead[] getHeads() { | |
209 return heads; | |
210 } | |
211 | |
212 @Override | |
213 public InputStream getSound(){ | |
214 switch(getStyle()){ | |
215 case Dashed : return dashedSound; | |
216 case Dotted : return dottedSound; | |
217 default : return straightSound; | |
218 } | |
219 } | |
220 | |
221 @Override | |
222 public void setEndDescription(DiagramNode diagramNode, int index){ | |
223 Node n = (Node)diagramNode; | |
224 if(index == NO_END_DESCRIPTION_INDEX){ | |
225 currentHeads.remove(n); | |
226 super.setEndDescription(n, index); | |
227 }else{ | |
228 ArrowHead h = heads[index]; | |
229 currentHeads.put(n, h); | |
230 super.setEndDescription(n, index); | |
231 } | |
232 } | |
233 | |
234 @Override | |
235 public void encode(Document doc, Element parent, List<Node> nodes){ | |
236 super.encode(doc, parent, nodes); | |
237 /* add the head attribute to the NODE tag */ | |
238 NodeList nodeTagList = parent.getElementsByTagName(PersistenceManager.NODE); | |
239 for(int i = 0 ; i< nodeTagList.getLength(); i++){ | |
240 Element nodeTag = (Element)nodeTagList.item(i); | |
241 String nodeIdAsString = nodeTag.getAttribute(PersistenceManager.ID); | |
242 long nodeId = Long.parseLong(nodeIdAsString); | |
243 Node node = null; | |
244 /* find the node with the id of the tag */ | |
245 for(Node n : nodes) | |
246 if(n.getId() == nodeId){ | |
247 node = n; | |
248 break; | |
249 } | |
250 String head = (currentHeads.get(node) == null) ? "" : currentHeads.get(node).toString(); | |
251 nodeTag.setAttribute(SimpleShapePrototypePersistenceDelegate.HEAD, head ); | |
252 } | |
253 } | |
254 | |
255 @Override | |
256 public void decode(Document doc, Element edgeTag, Map<String,Node> nodesId) throws IOException{ | |
257 super.decode(doc, edgeTag, nodesId); | |
258 NodeList nodeList = edgeTag.getElementsByTagName(PersistenceManager.NODE); | |
259 for(int i=0; i<nodeList.getLength(); i++){ | |
260 Element nodeTag = (Element)nodeList.item(i); | |
261 String id = nodeTag.getAttribute(PersistenceManager.ID); | |
262 if(id.isEmpty()) | |
263 throw new IOException(); | |
264 String head = nodeTag.getAttribute(SimpleShapePrototypePersistenceDelegate.HEAD); | |
265 if(!head.isEmpty()){ | |
266 ArrowHead headShape = null; | |
267 try{ | |
268 headShape = ArrowHead.getArrowHeadFromString(head); | |
269 }catch(IOException e){ | |
270 throw e; | |
271 } | |
272 currentHeads.put(nodesId.get(id), headShape); | |
273 int headDescriptionIndex = Edge.NO_END_DESCRIPTION_INDEX; | |
274 for(int j=0; j<heads.length;j++){ | |
275 if(heads[j].equals(headShape)){ | |
276 headDescriptionIndex = j; | |
277 break; | |
278 } | |
279 } | |
280 setEndDescription(nodesId.get(id),headDescriptionIndex); | |
281 } | |
282 } | |
283 } | |
284 | |
285 @Override | |
286 public int getStipplePattern(){ | |
287 int result = 0; | |
288 switch(getStyle()){ | |
289 case Solid : result = 0xFFFF; | |
290 break; | |
291 case Dashed : result = 0xF0F0; | |
292 break; | |
293 case Dotted : result = 0xAAAA ; | |
294 break; | |
295 } | |
296 return result; | |
297 } | |
298 | |
299 @Override | |
300 public Object clone(){ | |
301 return new SimpleShapeEdge(getType(), getStyle(), heads, getAvailableEndDescriptions(), getMinAttachedNodes(), getMaxAttachedNodes() ); | |
302 } | |
303 | |
304 | |
305 | |
306 private ArrowHead[] heads; | |
307 private Map<Node,ArrowHead> currentHeads; | |
308 private static InputStream straightSound; | |
309 private static InputStream dottedSound; | |
310 private static InputStream dashedSound; | |
311 | |
312 static{ | |
313 Class<SimpleShapeEdge> c = SimpleShapeEdge.class; | |
314 straightSound = c.getResourceAsStream("audio/straightLine.mp3"); | |
315 dottedSound = c.getResourceAsStream("audio/dashedLine.mp3"); | |
316 dashedSound = c.getResourceAsStream("audio/dottedLine.mp3"); | |
317 SoundFactory.getInstance().loadSound(straightSound); | |
318 SoundFactory.getInstance().loadSound(dottedSound); | |
319 SoundFactory.getInstance().loadSound(dashedSound); | |
320 } | |
321 } |