annotate java/src/uk/ac/qmul/eecs/ccmi/simpletemplate/Model.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 9418ab7b7f3f
children
rev   line source
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 }