view java/src/uk/ac/qmul/eecs/ccmi/simpletemplate/Model.java @ 0:9418ab7b7f3f

Initial import
author Fiore Martin <fiore@eecs.qmul.ac.uk>
date Fri, 16 Dec 2011 17:35:51 +0000
parents
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.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.ResourceBundle;

/*
 * The Wizard Model holds all the data the user enters during the process of creating a diagram template. 
 * Such data can be re-edited by the user during the same process or if they want to create
 * a new diagram template out of an existing one. When the user has entered all the data the model is used 
 * to create an instance of the {@link Diagram class} which is then used as a prototype diagram. 
 * Diagram instances that the user will edit are created by cloning the relating prototype diagram.  
 *
 */
class Model {
	Model(){
		diagramName = new Record();
		nodes = new ModelMap<Node>();
		edges = new ModelMap<Edge>();
	}
	
	@Override
	public String toString(){// FIXME need to port the strings to the .properties file
		StringBuilder builder = new StringBuilder();
		builder.append("Diagram Name is ").append(diagramName.value).append(".\n\n");
		builder.append(diagramName.value + " diagram has "+ (nodes.isEmpty() ? "no" : nodes.size()) + " node"+((nodes.size() == 1) ? "" : "s"));
		if(!nodes.isEmpty()){
			builder.append(": ");
			int i = 0;
			for(Node n : nodes.values()){
				builder.append(n.type.value);
				if(nodes.values().size() == 1)
					break;
				if(i == nodes.values().size() - 2){
					builder.append(" and ");
				}else if(i < nodes.values().size()-1){
					builder.append(", ");
				}
				i++;
			}
		}
		builder.append(".\n");
		for(Node n : nodes.values()){
			builder.append(n.type+" node has a ")
				.append(n.shape + " shape.\n");
			builder.append(n.type+" node has "+ (n.properties.isEmpty() ? "no" : n.properties.size())+((n.properties.size() == 1) ? " property" : " properties"));
			if(!n.properties.isEmpty()){
				builder.append(": ");
				int i = 0;
				for(Property p : n.properties.values()){
					builder.append(p.type.value);
					if(n.properties.size() == 1)
						break;
					if(i == n.properties.size() - 2){
						builder.append(" and ");
					}else if(i < n.properties.size()-1){
						builder.append(", ");
					}
					i++;
				}
			}
			builder.append(".\n");
			for(Property p : n.properties.values()){
				builder.append(p.type+" property has position "+p.position);
				if(p.position.value.equals(SimpleShapeNode.Position.Outside.toString()))
					builder.append(" and shape "+p.shape+".\n");
				else
					builder.append(".\n");
				builder.append(p.type+" property has "+(p.modifiers.isEmpty() ? "no" : p.modifiers.size())+(p.modifiers.size() == 1 ? " modifier" : " modifiers"));
				if(!p.modifiers.isEmpty()){
					builder.append(": ");
					int i = 0;
					for(Modifier m : p.modifiers.values()){
						builder.append(m.type.value);
						if(p.modifiers.size() == 1)
							break;
						if(i == p.modifiers.size() - 2){
							builder.append(" and ");
						}else if(i < p.modifiers.size()-1){
							builder.append(", ");
						}
						i++;
					}
				}
				builder.append(".\n");
				for(Modifier m : p.modifiers.values()){
					builder.append(m.type+ " modifier ");
					if(m.format.values.length > 0)
						builder.append("is formatted as "+m.format+".\n");
					else
						builder.append("\n");
				}
			}
		}
		builder.append('\n');
		builder.append(diagramName.value + " diagram has "+ (edges.isEmpty() ? "no" : edges.size()) + " edge"+((edges.size() == 1) ? "" : "s"));
		if(!edges.isEmpty()){
			builder.append(": ");
			int i = 0;
			for(Edge e : edges.values()){
				builder.append(e.type.value);
				if(edges.values().size() == 1)
					break;
				if(i == edges.values().size() - 2){
					builder.append(" and ");
				}else if(i < edges.values().size()-1){
					builder.append(", ");
				}
				i++;
			}
		}
		builder.append(".\n");
		for(Edge e : edges.values()){
			builder.append(e.type+ " edge has minimum nodes "+e.minNodes+" and maximum nodes "+e.maxNodes+".\n")
			 .append(e.type+ " edge has a "+ e.lineStyle+" line style.\n")
			 .append(e.type+" edge has "+ ((e.arrowHeads.values.length == 0) ? "no harrow heads.\n" : e.arrowHeads.values.length +" harrow heads: "+e.arrowHeads+".\n"));
		}
		builder.append('\n');
		builder.append("Press up and down arrow keys to go through the summary.\n");
		return builder.toString();
	}

	Record diagramName;
	/* these are sets as when we edit an already existing node we just add */   
	/* to the set the new node and it gets replaced                        */
	ModelMap<Node> nodes;
	ModelMap<Edge> edges;
	
	static Element copy(Element src, Element dest){
		if(src instanceof Node){
			copy((Node)src,(Node)dest);
		}else if (src instanceof Edge){
			copy((Edge)src,(Edge)dest);
		}else if(src instanceof Property){
			copy((Property)src,(Property)dest);
		}else{
			copy((Modifier)src,(Modifier)dest);
		}
		return dest;
	}
	
	static void copy(Node src, Node dest){
		dest.id = src.id;
		dest.type.value = src.type.value;
		dest.shape.value = src.shape.value;
		dest.properties.clear(); 
		dest.properties.putAll(src.properties);
	}
	
	static void copy(Property src, Property dest){
		dest.id = src.id;
		dest.type.value = src.type.value;
		dest.shape.value = src.shape.value;
		dest.position.value = src.position.value;
		dest.modifiers.clear();
		dest.modifiers.putAll(src.modifiers);
	}
	
	static void copy(Edge src, Edge dest){
		dest.id = src.id;
		dest.type.value = src.type.value;
		dest.lineStyle.value = src.lineStyle.value;
		dest.maxNodes.value = src.maxNodes.value;
		dest.minNodes.value = src.minNodes.value;
		dest.arrowHeads.values = src.arrowHeads.values;
		dest.arrowHeadsDescriptions.values = src.arrowHeadsDescriptions.values;
	}
	
	static void copy(Modifier src, Modifier dest){
		dest.id = src.id;
		dest.type.value = src.type.value;
		dest.format.values = src.format.values;
		dest.affix.values = src.affix.values;
	}
	
	static class Record{
		Record(){
			value = "";
		}
		Record(String value){
			this.value = value;
		}
		@Override
		public String toString(){
			return value;
		}
		String value;
	}
	
	static class StrArrayRecord{
		String [] values;
		StrArrayRecord(){
			values = new String[0];
		}
		
		StrArrayRecord(String[] values){
			this.values = values;
		}
		
		@Override
		public String toString(){
			StringBuilder builder = new StringBuilder();
			for(int i=0; i<values.length; i++){
				builder.append(values[i]);
				if(values.length == 1)
					break;
				if(i == values.length - 2)
					builder.append(" and ");
				else if(i < values.length -1 )
					builder.append(", ");
			}
			return builder.toString();
		}
	}
	
	private static long uniqueId = 0;
	static class Element {
		Element(){
			type = new Record();
			id = uniqueId++;
		}

		void clear () {
			type.value = "";
			id = uniqueId++;
		}
		long id;
		Record type;
	}
	
	static class Node extends Element{
		Node(){
			shape = new Record();	
			properties = new ModelMap<Property>();
		}
		
		@Override
		void clear(){
			super.clear();
			shape.value = "";
			properties.clear();
		}
		Record shape;
		ModelMap<Property> properties;
	}
	
	static class Edge extends Element {
		Edge(){
			lineStyle = new Record();
			minNodes = new Record();
			maxNodes = new Record();
			arrowHeads = new StrArrayRecord(){
				@Override
				public String toString(){
					StringBuilder builder = new StringBuilder();
					for(int i=0; i<values.length; i++){
						builder.append(values[i]+" with label "+arrowHeadsDescriptions.values[i]);
						if(values.length == 1)
							break;
						if(i == values.length - 2)
							builder.append(" and ");
						else if(i < values.length -1 )
							builder.append(", ");
					}
					return builder.toString();
				}
			};
			arrowHeadsDescriptions = new StrArrayRecord();
		}
		@Override
		public void clear(){
			super.clear();
			lineStyle.value = "";
			minNodes.value = "";
			maxNodes.value = "";
			arrowHeads.values = new String[0];
			arrowHeadsDescriptions.values = new String[0];
		}
		Record lineStyle;
		Record minNodes;
		Record maxNodes;
		StrArrayRecord arrowHeads;
		StrArrayRecord arrowHeadsDescriptions;
	}
	
	static class Property extends Element{
		Property(){
			position = new Model.Record();
			shape = new Model.Record();
			modifiers = new ModelMap<Modifier>();
		}
		Record position;
		Record shape;
		ModelMap<Modifier> modifiers;
		
		@Override
		void clear(){
			super.clear();
			modifiers.clear();
			position.value = "";
			shape.value = "";
		}
	}
	
	static class Modifier extends Element {
		StrArrayRecord format;
		StrArrayRecord affix;
		
		Modifier(){
			affix = new StrArrayRecord();
			format = new StrArrayRecord(){
				@Override
				public String toString(){
					ResourceBundle resources = ResourceBundle.getBundle(SpeechWizardDialog.class.getName());
					StringBuilder builder = new StringBuilder();
					for(int i=0; i<values.length; i++){
						builder.append(values[i]);
						if(values[i].equals(resources.getString("modifier.format.prefix")) && !affix.values[0].isEmpty()){
							builder.append(' ').append(affix.values[0]);
						}
						if(values[i].equals(resources.getString("modifier.format.suffix")) && !affix.values[1].isEmpty()){
							builder.append(' ').append(affix.values[1]);
						}

						if(values.length == 1)
							break;
						if(i == values.length - 2)
							builder.append(" and ");
						else if(i < values.length -1 )
							builder.append(", ");
					}
					return builder.toString();
				}
			};
				
			/* affix is always length = 2 as it only contains prefix and suffix string */
			/* eventually it contains empty strings but its length is not variable     */
			affix.values = new String[2];
		}
		
		@Override
		void clear(){
			super.clear();
			format.values = new String[0];
			affix.values =  new String[2];
		}
	}
}


@SuppressWarnings("serial")
class ModelMap<T extends Model.Element> extends LinkedHashMap<Long,T> {
	public ModelMap(){
		namesMap = new LinkedHashMap<Long,String>();
	}
	
	@Override
	public void clear(){
		namesMap.clear();
		super.clear();
	}
	
	public T put(Long key, T value){
		namesMap.put(key, value.type.value);
		return super.put(key, value);
	}
	
	public void putAll(Map<? extends Long,? extends T> m){
		for(Map.Entry<? extends Long,? extends T> entry : m.entrySet()){
			namesMap.put(entry.getKey(), entry.getValue().type.value);
		}
		super.putAll(m);
	}
	
	public T remove(Object key){
		namesMap.remove(key);
		return super.remove(key);
	}
	
	public Collection<String> getNames(){
		return namesMap.values();
	}
	
	private Map<Long,String> namesMap;
}