fiore@0
|
1 /*
|
fiore@0
|
2 CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool
|
fiore@0
|
3
|
fiore@0
|
4 Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
|
fiore@0
|
5
|
fiore@0
|
6 This program is free software: you can redistribute it and/or modify
|
fiore@0
|
7 it under the terms of the GNU General Public License as published by
|
fiore@0
|
8 the Free Software Foundation, either version 3 of the License, or
|
fiore@0
|
9 (at your option) any later version.
|
fiore@0
|
10
|
fiore@0
|
11 This program is distributed in the hope that it will be useful,
|
fiore@0
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
fiore@0
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
fiore@0
|
14 GNU General Public License for more details.
|
fiore@0
|
15
|
fiore@0
|
16 You should have received a copy of the GNU General Public License
|
fiore@0
|
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
fiore@0
|
18 */
|
fiore@0
|
19
|
fiore@0
|
20 package uk.ac.qmul.eecs.ccmi.simpletemplate;
|
fiore@0
|
21
|
fiore@0
|
22 import java.util.Collection;
|
fiore@0
|
23 import java.util.LinkedHashMap;
|
fiore@0
|
24 import java.util.Map;
|
fiore@0
|
25 import java.util.ResourceBundle;
|
fiore@0
|
26
|
fiore@0
|
27 /*
|
fiore@0
|
28 * The Wizard Model holds all the data the user enters during the process of creating a diagram template.
|
fiore@0
|
29 * Such data can be re-edited by the user during the same process or if they want to create
|
fiore@0
|
30 * a new diagram template out of an existing one. When the user has entered all the data the model is used
|
fiore@0
|
31 * to create an instance of the {@link Diagram class} which is then used as a prototype diagram.
|
fiore@0
|
32 * Diagram instances that the user will edit are created by cloning the relating prototype diagram.
|
fiore@0
|
33 *
|
fiore@0
|
34 */
|
fiore@0
|
35 class Model {
|
fiore@0
|
36 Model(){
|
fiore@0
|
37 diagramName = new Record();
|
fiore@0
|
38 nodes = new ModelMap<Node>();
|
fiore@0
|
39 edges = new ModelMap<Edge>();
|
fiore@0
|
40 }
|
fiore@0
|
41
|
fiore@0
|
42 @Override
|
fiore@0
|
43 public String toString(){// FIXME need to port the strings to the .properties file
|
fiore@0
|
44 StringBuilder builder = new StringBuilder();
|
fiore@0
|
45 builder.append("Diagram Name is ").append(diagramName.value).append(".\n\n");
|
fiore@0
|
46 builder.append(diagramName.value + " diagram has "+ (nodes.isEmpty() ? "no" : nodes.size()) + " node"+((nodes.size() == 1) ? "" : "s"));
|
fiore@0
|
47 if(!nodes.isEmpty()){
|
fiore@0
|
48 builder.append(": ");
|
fiore@0
|
49 int i = 0;
|
fiore@0
|
50 for(Node n : nodes.values()){
|
fiore@0
|
51 builder.append(n.type.value);
|
fiore@0
|
52 if(nodes.values().size() == 1)
|
fiore@0
|
53 break;
|
fiore@0
|
54 if(i == nodes.values().size() - 2){
|
fiore@0
|
55 builder.append(" and ");
|
fiore@0
|
56 }else if(i < nodes.values().size()-1){
|
fiore@0
|
57 builder.append(", ");
|
fiore@0
|
58 }
|
fiore@0
|
59 i++;
|
fiore@0
|
60 }
|
fiore@0
|
61 }
|
fiore@0
|
62 builder.append(".\n");
|
fiore@0
|
63 for(Node n : nodes.values()){
|
fiore@0
|
64 builder.append(n.type+" node has a ")
|
fiore@0
|
65 .append(n.shape + " shape.\n");
|
fiore@0
|
66 builder.append(n.type+" node has "+ (n.properties.isEmpty() ? "no" : n.properties.size())+((n.properties.size() == 1) ? " property" : " properties"));
|
fiore@0
|
67 if(!n.properties.isEmpty()){
|
fiore@0
|
68 builder.append(": ");
|
fiore@0
|
69 int i = 0;
|
fiore@0
|
70 for(Property p : n.properties.values()){
|
fiore@0
|
71 builder.append(p.type.value);
|
fiore@0
|
72 if(n.properties.size() == 1)
|
fiore@0
|
73 break;
|
fiore@0
|
74 if(i == n.properties.size() - 2){
|
fiore@0
|
75 builder.append(" and ");
|
fiore@0
|
76 }else if(i < n.properties.size()-1){
|
fiore@0
|
77 builder.append(", ");
|
fiore@0
|
78 }
|
fiore@0
|
79 i++;
|
fiore@0
|
80 }
|
fiore@0
|
81 }
|
fiore@0
|
82 builder.append(".\n");
|
fiore@0
|
83 for(Property p : n.properties.values()){
|
fiore@0
|
84 builder.append(p.type+" property has position "+p.position);
|
fiore@0
|
85 if(p.position.value.equals(SimpleShapeNode.Position.Outside.toString()))
|
fiore@0
|
86 builder.append(" and shape "+p.shape+".\n");
|
fiore@0
|
87 else
|
fiore@0
|
88 builder.append(".\n");
|
fiore@0
|
89 builder.append(p.type+" property has "+(p.modifiers.isEmpty() ? "no" : p.modifiers.size())+(p.modifiers.size() == 1 ? " modifier" : " modifiers"));
|
fiore@0
|
90 if(!p.modifiers.isEmpty()){
|
fiore@0
|
91 builder.append(": ");
|
fiore@0
|
92 int i = 0;
|
fiore@0
|
93 for(Modifier m : p.modifiers.values()){
|
fiore@0
|
94 builder.append(m.type.value);
|
fiore@0
|
95 if(p.modifiers.size() == 1)
|
fiore@0
|
96 break;
|
fiore@0
|
97 if(i == p.modifiers.size() - 2){
|
fiore@0
|
98 builder.append(" and ");
|
fiore@0
|
99 }else if(i < p.modifiers.size()-1){
|
fiore@0
|
100 builder.append(", ");
|
fiore@0
|
101 }
|
fiore@0
|
102 i++;
|
fiore@0
|
103 }
|
fiore@0
|
104 }
|
fiore@0
|
105 builder.append(".\n");
|
fiore@0
|
106 for(Modifier m : p.modifiers.values()){
|
fiore@0
|
107 builder.append(m.type+ " modifier ");
|
fiore@0
|
108 if(m.format.values.length > 0)
|
fiore@0
|
109 builder.append("is formatted as "+m.format+".\n");
|
fiore@0
|
110 else
|
fiore@0
|
111 builder.append("\n");
|
fiore@0
|
112 }
|
fiore@0
|
113 }
|
fiore@0
|
114 }
|
fiore@0
|
115 builder.append('\n');
|
fiore@0
|
116 builder.append(diagramName.value + " diagram has "+ (edges.isEmpty() ? "no" : edges.size()) + " edge"+((edges.size() == 1) ? "" : "s"));
|
fiore@0
|
117 if(!edges.isEmpty()){
|
fiore@0
|
118 builder.append(": ");
|
fiore@0
|
119 int i = 0;
|
fiore@0
|
120 for(Edge e : edges.values()){
|
fiore@0
|
121 builder.append(e.type.value);
|
fiore@0
|
122 if(edges.values().size() == 1)
|
fiore@0
|
123 break;
|
fiore@0
|
124 if(i == edges.values().size() - 2){
|
fiore@0
|
125 builder.append(" and ");
|
fiore@0
|
126 }else if(i < edges.values().size()-1){
|
fiore@0
|
127 builder.append(", ");
|
fiore@0
|
128 }
|
fiore@0
|
129 i++;
|
fiore@0
|
130 }
|
fiore@0
|
131 }
|
fiore@0
|
132 builder.append(".\n");
|
fiore@0
|
133 for(Edge e : edges.values()){
|
fiore@0
|
134 builder.append(e.type+ " edge has minimum nodes "+e.minNodes+" and maximum nodes "+e.maxNodes+".\n")
|
fiore@0
|
135 .append(e.type+ " edge has a "+ e.lineStyle+" line style.\n")
|
fiore@0
|
136 .append(e.type+" edge has "+ ((e.arrowHeads.values.length == 0) ? "no harrow heads.\n" : e.arrowHeads.values.length +" harrow heads: "+e.arrowHeads+".\n"));
|
fiore@0
|
137 }
|
fiore@0
|
138 builder.append('\n');
|
fiore@0
|
139 builder.append("Press up and down arrow keys to go through the summary.\n");
|
fiore@0
|
140 return builder.toString();
|
fiore@0
|
141 }
|
fiore@0
|
142
|
fiore@0
|
143 Record diagramName;
|
fiore@0
|
144 /* these are sets as when we edit an already existing node we just add */
|
fiore@0
|
145 /* to the set the new node and it gets replaced */
|
fiore@0
|
146 ModelMap<Node> nodes;
|
fiore@0
|
147 ModelMap<Edge> edges;
|
fiore@0
|
148
|
fiore@0
|
149 static Element copy(Element src, Element dest){
|
fiore@0
|
150 if(src instanceof Node){
|
fiore@0
|
151 copy((Node)src,(Node)dest);
|
fiore@0
|
152 }else if (src instanceof Edge){
|
fiore@0
|
153 copy((Edge)src,(Edge)dest);
|
fiore@0
|
154 }else if(src instanceof Property){
|
fiore@0
|
155 copy((Property)src,(Property)dest);
|
fiore@0
|
156 }else{
|
fiore@0
|
157 copy((Modifier)src,(Modifier)dest);
|
fiore@0
|
158 }
|
fiore@0
|
159 return dest;
|
fiore@0
|
160 }
|
fiore@0
|
161
|
fiore@0
|
162 static void copy(Node src, Node dest){
|
fiore@0
|
163 dest.id = src.id;
|
fiore@0
|
164 dest.type.value = src.type.value;
|
fiore@0
|
165 dest.shape.value = src.shape.value;
|
fiore@0
|
166 dest.properties.clear();
|
fiore@0
|
167 dest.properties.putAll(src.properties);
|
fiore@0
|
168 }
|
fiore@0
|
169
|
fiore@0
|
170 static void copy(Property src, Property dest){
|
fiore@0
|
171 dest.id = src.id;
|
fiore@0
|
172 dest.type.value = src.type.value;
|
fiore@0
|
173 dest.shape.value = src.shape.value;
|
fiore@0
|
174 dest.position.value = src.position.value;
|
fiore@0
|
175 dest.modifiers.clear();
|
fiore@0
|
176 dest.modifiers.putAll(src.modifiers);
|
fiore@0
|
177 }
|
fiore@0
|
178
|
fiore@0
|
179 static void copy(Edge src, Edge dest){
|
fiore@0
|
180 dest.id = src.id;
|
fiore@0
|
181 dest.type.value = src.type.value;
|
fiore@0
|
182 dest.lineStyle.value = src.lineStyle.value;
|
fiore@0
|
183 dest.maxNodes.value = src.maxNodes.value;
|
fiore@0
|
184 dest.minNodes.value = src.minNodes.value;
|
fiore@0
|
185 dest.arrowHeads.values = src.arrowHeads.values;
|
fiore@0
|
186 dest.arrowHeadsDescriptions.values = src.arrowHeadsDescriptions.values;
|
fiore@0
|
187 }
|
fiore@0
|
188
|
fiore@0
|
189 static void copy(Modifier src, Modifier dest){
|
fiore@0
|
190 dest.id = src.id;
|
fiore@0
|
191 dest.type.value = src.type.value;
|
fiore@0
|
192 dest.format.values = src.format.values;
|
fiore@0
|
193 dest.affix.values = src.affix.values;
|
fiore@0
|
194 }
|
fiore@0
|
195
|
fiore@0
|
196 static class Record{
|
fiore@0
|
197 Record(){
|
fiore@0
|
198 value = "";
|
fiore@0
|
199 }
|
fiore@0
|
200 Record(String value){
|
fiore@0
|
201 this.value = value;
|
fiore@0
|
202 }
|
fiore@0
|
203 @Override
|
fiore@0
|
204 public String toString(){
|
fiore@0
|
205 return value;
|
fiore@0
|
206 }
|
fiore@0
|
207 String value;
|
fiore@0
|
208 }
|
fiore@0
|
209
|
fiore@0
|
210 static class StrArrayRecord{
|
fiore@0
|
211 String [] values;
|
fiore@0
|
212 StrArrayRecord(){
|
fiore@0
|
213 values = new String[0];
|
fiore@0
|
214 }
|
fiore@0
|
215
|
fiore@0
|
216 StrArrayRecord(String[] values){
|
fiore@0
|
217 this.values = values;
|
fiore@0
|
218 }
|
fiore@0
|
219
|
fiore@0
|
220 @Override
|
fiore@0
|
221 public String toString(){
|
fiore@0
|
222 StringBuilder builder = new StringBuilder();
|
fiore@0
|
223 for(int i=0; i<values.length; i++){
|
fiore@0
|
224 builder.append(values[i]);
|
fiore@0
|
225 if(values.length == 1)
|
fiore@0
|
226 break;
|
fiore@0
|
227 if(i == values.length - 2)
|
fiore@0
|
228 builder.append(" and ");
|
fiore@0
|
229 else if(i < values.length -1 )
|
fiore@0
|
230 builder.append(", ");
|
fiore@0
|
231 }
|
fiore@0
|
232 return builder.toString();
|
fiore@0
|
233 }
|
fiore@0
|
234 }
|
fiore@0
|
235
|
fiore@0
|
236 private static long uniqueId = 0;
|
fiore@0
|
237 static class Element {
|
fiore@0
|
238 Element(){
|
fiore@0
|
239 type = new Record();
|
fiore@0
|
240 id = uniqueId++;
|
fiore@0
|
241 }
|
fiore@0
|
242
|
fiore@0
|
243 void clear () {
|
fiore@0
|
244 type.value = "";
|
fiore@0
|
245 id = uniqueId++;
|
fiore@0
|
246 }
|
fiore@0
|
247 long id;
|
fiore@0
|
248 Record type;
|
fiore@0
|
249 }
|
fiore@0
|
250
|
fiore@0
|
251 static class Node extends Element{
|
fiore@0
|
252 Node(){
|
fiore@0
|
253 shape = new Record();
|
fiore@0
|
254 properties = new ModelMap<Property>();
|
fiore@0
|
255 }
|
fiore@0
|
256
|
fiore@0
|
257 @Override
|
fiore@0
|
258 void clear(){
|
fiore@0
|
259 super.clear();
|
fiore@0
|
260 shape.value = "";
|
fiore@0
|
261 properties.clear();
|
fiore@0
|
262 }
|
fiore@0
|
263 Record shape;
|
fiore@0
|
264 ModelMap<Property> properties;
|
fiore@0
|
265 }
|
fiore@0
|
266
|
fiore@0
|
267 static class Edge extends Element {
|
fiore@0
|
268 Edge(){
|
fiore@0
|
269 lineStyle = new Record();
|
fiore@0
|
270 minNodes = new Record();
|
fiore@0
|
271 maxNodes = new Record();
|
fiore@0
|
272 arrowHeads = new StrArrayRecord(){
|
fiore@0
|
273 @Override
|
fiore@0
|
274 public String toString(){
|
fiore@0
|
275 StringBuilder builder = new StringBuilder();
|
fiore@0
|
276 for(int i=0; i<values.length; i++){
|
fiore@0
|
277 builder.append(values[i]+" with label "+arrowHeadsDescriptions.values[i]);
|
fiore@0
|
278 if(values.length == 1)
|
fiore@0
|
279 break;
|
fiore@0
|
280 if(i == values.length - 2)
|
fiore@0
|
281 builder.append(" and ");
|
fiore@0
|
282 else if(i < values.length -1 )
|
fiore@0
|
283 builder.append(", ");
|
fiore@0
|
284 }
|
fiore@0
|
285 return builder.toString();
|
fiore@0
|
286 }
|
fiore@0
|
287 };
|
fiore@0
|
288 arrowHeadsDescriptions = new StrArrayRecord();
|
fiore@0
|
289 }
|
fiore@0
|
290 @Override
|
fiore@0
|
291 public void clear(){
|
fiore@0
|
292 super.clear();
|
fiore@0
|
293 lineStyle.value = "";
|
fiore@0
|
294 minNodes.value = "";
|
fiore@0
|
295 maxNodes.value = "";
|
fiore@0
|
296 arrowHeads.values = new String[0];
|
fiore@0
|
297 arrowHeadsDescriptions.values = new String[0];
|
fiore@0
|
298 }
|
fiore@0
|
299 Record lineStyle;
|
fiore@0
|
300 Record minNodes;
|
fiore@0
|
301 Record maxNodes;
|
fiore@0
|
302 StrArrayRecord arrowHeads;
|
fiore@0
|
303 StrArrayRecord arrowHeadsDescriptions;
|
fiore@0
|
304 }
|
fiore@0
|
305
|
fiore@0
|
306 static class Property extends Element{
|
fiore@0
|
307 Property(){
|
fiore@0
|
308 position = new Model.Record();
|
fiore@0
|
309 shape = new Model.Record();
|
fiore@0
|
310 modifiers = new ModelMap<Modifier>();
|
fiore@0
|
311 }
|
fiore@0
|
312 Record position;
|
fiore@0
|
313 Record shape;
|
fiore@0
|
314 ModelMap<Modifier> modifiers;
|
fiore@0
|
315
|
fiore@0
|
316 @Override
|
fiore@0
|
317 void clear(){
|
fiore@0
|
318 super.clear();
|
fiore@0
|
319 modifiers.clear();
|
fiore@0
|
320 position.value = "";
|
fiore@0
|
321 shape.value = "";
|
fiore@0
|
322 }
|
fiore@0
|
323 }
|
fiore@0
|
324
|
fiore@0
|
325 static class Modifier extends Element {
|
fiore@0
|
326 StrArrayRecord format;
|
fiore@0
|
327 StrArrayRecord affix;
|
fiore@0
|
328
|
fiore@0
|
329 Modifier(){
|
fiore@0
|
330 affix = new StrArrayRecord();
|
fiore@0
|
331 format = new StrArrayRecord(){
|
fiore@0
|
332 @Override
|
fiore@0
|
333 public String toString(){
|
fiore@0
|
334 ResourceBundle resources = ResourceBundle.getBundle(SpeechWizardDialog.class.getName());
|
fiore@0
|
335 StringBuilder builder = new StringBuilder();
|
fiore@0
|
336 for(int i=0; i<values.length; i++){
|
fiore@0
|
337 builder.append(values[i]);
|
fiore@0
|
338 if(values[i].equals(resources.getString("modifier.format.prefix")) && !affix.values[0].isEmpty()){
|
fiore@0
|
339 builder.append(' ').append(affix.values[0]);
|
fiore@0
|
340 }
|
fiore@0
|
341 if(values[i].equals(resources.getString("modifier.format.suffix")) && !affix.values[1].isEmpty()){
|
fiore@0
|
342 builder.append(' ').append(affix.values[1]);
|
fiore@0
|
343 }
|
fiore@0
|
344
|
fiore@0
|
345 if(values.length == 1)
|
fiore@0
|
346 break;
|
fiore@0
|
347 if(i == values.length - 2)
|
fiore@0
|
348 builder.append(" and ");
|
fiore@0
|
349 else if(i < values.length -1 )
|
fiore@0
|
350 builder.append(", ");
|
fiore@0
|
351 }
|
fiore@0
|
352 return builder.toString();
|
fiore@0
|
353 }
|
fiore@0
|
354 };
|
fiore@0
|
355
|
fiore@0
|
356 /* affix is always length = 2 as it only contains prefix and suffix string */
|
fiore@0
|
357 /* eventually it contains empty strings but its length is not variable */
|
fiore@0
|
358 affix.values = new String[2];
|
fiore@0
|
359 }
|
fiore@0
|
360
|
fiore@0
|
361 @Override
|
fiore@0
|
362 void clear(){
|
fiore@0
|
363 super.clear();
|
fiore@0
|
364 format.values = new String[0];
|
fiore@0
|
365 affix.values = new String[2];
|
fiore@0
|
366 }
|
fiore@0
|
367 }
|
fiore@0
|
368 }
|
fiore@0
|
369
|
fiore@0
|
370
|
fiore@0
|
371 @SuppressWarnings("serial")
|
fiore@0
|
372 class ModelMap<T extends Model.Element> extends LinkedHashMap<Long,T> {
|
fiore@0
|
373 public ModelMap(){
|
fiore@0
|
374 namesMap = new LinkedHashMap<Long,String>();
|
fiore@0
|
375 }
|
fiore@0
|
376
|
fiore@0
|
377 @Override
|
fiore@0
|
378 public void clear(){
|
fiore@0
|
379 namesMap.clear();
|
fiore@0
|
380 super.clear();
|
fiore@0
|
381 }
|
fiore@0
|
382
|
fiore@0
|
383 public T put(Long key, T value){
|
fiore@0
|
384 namesMap.put(key, value.type.value);
|
fiore@0
|
385 return super.put(key, value);
|
fiore@0
|
386 }
|
fiore@0
|
387
|
fiore@0
|
388 public void putAll(Map<? extends Long,? extends T> m){
|
fiore@0
|
389 for(Map.Entry<? extends Long,? extends T> entry : m.entrySet()){
|
fiore@0
|
390 namesMap.put(entry.getKey(), entry.getValue().type.value);
|
fiore@0
|
391 }
|
fiore@0
|
392 super.putAll(m);
|
fiore@0
|
393 }
|
fiore@0
|
394
|
fiore@0
|
395 public T remove(Object key){
|
fiore@0
|
396 namesMap.remove(key);
|
fiore@0
|
397 return super.remove(key);
|
fiore@0
|
398 }
|
fiore@0
|
399
|
fiore@0
|
400 public Collection<String> getNames(){
|
fiore@0
|
401 return namesMap.values();
|
fiore@0
|
402 }
|
fiore@0
|
403
|
fiore@0
|
404 private Map<Long,String> namesMap;
|
fiore@0
|
405 }
|