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 package uk.ac.qmul.eecs.ccmi.diagrammodel;
|
fiore@0
|
20
|
fiore@0
|
21 import java.util.ArrayList;
|
fiore@0
|
22 import java.util.Collections;
|
fiore@0
|
23 import java.util.LinkedHashMap;
|
fiore@0
|
24 import java.util.LinkedHashSet;
|
fiore@0
|
25 import java.util.List;
|
fiore@0
|
26 import java.util.Map;
|
fiore@0
|
27 import java.util.Set;
|
fiore@0
|
28
|
fiore@0
|
29 /**
|
fiore@0
|
30 * This class represents the internal properties of a node. Internal properties can be seen as
|
fiore@0
|
31 * attributes that each single nodes owns and that, in a visual diagram, would normally be displayed inside
|
fiore@0
|
32 * or in the neighbourhood of the node itself. This is a very high abstraction of the concept of properties
|
fiore@0
|
33 * of a node as the user can define their own type of properties through the property type definition object
|
fiore@0
|
34 * passed as argument in the constructor.
|
fiore@0
|
35 * An example of properties is <i>attributes</i> and <i>methods</i> of a class diagram in the UML language or just the
|
fiore@0
|
36 * <i>attributes</i> of entities in an ER diagram.
|
fiore@0
|
37 *
|
fiore@0
|
38 */
|
fiore@0
|
39 public final class NodeProperties implements Cloneable {
|
fiore@0
|
40
|
fiore@0
|
41 /**
|
fiore@0
|
42 * Creates a diagram element property data structure out of a property type specification. In a UML
|
fiore@0
|
43 * diagram the NodeProperties for a class node would be constructed passing as arguments a linked hash
|
fiore@0
|
44 * map containing the strings "attributes" and "properties" and the strings "public", "protected", "private",
|
fiore@0
|
45 * "static" as value for both the keys. "attributes" and "methods" would be the types of the NodeProperties,
|
fiore@0
|
46 * that is, all the values inserted in the object such as values would fall under either type. For example
|
fiore@0
|
47 * if a UML diagram class has the methods getX() and getY(), these would be inserted in the NodeProperties
|
fiore@0
|
48 * object with a type "methods".
|
fiore@0
|
49 *
|
fiore@0
|
50 * @param typeDefinition a linked Hash Map holding the properties types as keys
|
fiore@0
|
51 * and the modifiers type definition of each property as values
|
fiore@0
|
52 */
|
fiore@0
|
53
|
fiore@0
|
54 public NodeProperties(LinkedHashMap<String,Set<String>> typeDefinition){
|
fiore@0
|
55 if(typeDefinition == null)
|
fiore@0
|
56 this.typeDefinition = EMPTY_PROPERTY_TYPE_DEFINITION;
|
fiore@0
|
57 else
|
fiore@0
|
58 this.typeDefinition = typeDefinition;
|
fiore@0
|
59 /* create the type collection out of the typeDefinition keyset */
|
fiore@0
|
60 types = Collections.unmodifiableList(new ArrayList<String>(this.typeDefinition.keySet()));
|
fiore@0
|
61 properties = new LinkedHashMap<String,Entry>();
|
fiore@0
|
62 for(String s : types){
|
fiore@0
|
63 Entry q = new Entry();
|
fiore@0
|
64 q.values = new ArrayList<String>(); // property values to be filled by user + modifiers
|
fiore@0
|
65 q.indexes = new ArrayList<Set<Integer>>();
|
fiore@0
|
66 q.view = null;
|
fiore@0
|
67 Set<String> modifierTypeDefinition = this.typeDefinition.get(s);
|
fiore@0
|
68 if(modifierTypeDefinition == null)
|
fiore@0
|
69 /* null modifiers for this property */
|
fiore@0
|
70 q.modifiers = new Modifiers(EMPTY_MODIFIER_TYPE_DEFINITION,q.indexes);
|
fiore@0
|
71 else if(modifierTypeDefinition.size() == 0)
|
fiore@0
|
72 /* null modifiers for this property */
|
fiore@0
|
73 q.modifiers = new Modifiers(EMPTY_MODIFIER_TYPE_DEFINITION,q.indexes);
|
fiore@0
|
74 else
|
fiore@0
|
75 q.modifiers = new Modifiers(modifierTypeDefinition, q.indexes);
|
fiore@0
|
76 properties.put(s, q);
|
fiore@0
|
77 }
|
fiore@0
|
78 }
|
fiore@0
|
79
|
fiore@0
|
80 /**
|
fiore@0
|
81 * Returns the type definition argument of the constructor this object has been created through.
|
fiore@0
|
82 *
|
fiore@0
|
83 * @return the type definition
|
fiore@0
|
84 */
|
fiore@0
|
85 public Map<String,Set<String>> getTypeDefinition(){
|
fiore@0
|
86 return typeDefinition;
|
fiore@0
|
87 }
|
fiore@0
|
88
|
fiore@0
|
89 /**
|
fiore@0
|
90 * Returns the types of properties.
|
fiore@3
|
91 *
|
fiore@3
|
92 * @return a list of strings holding types of properties
|
fiore@0
|
93 */
|
fiore@0
|
94 public List<String> getTypes(){
|
fiore@0
|
95 return types;
|
fiore@0
|
96 }
|
fiore@0
|
97
|
fiore@0
|
98 /**
|
fiore@3
|
99 * @param propertyType the property type we want to get the values of.
|
fiore@0
|
100 * @return an array of string with the different properties set by the user or
|
fiore@3
|
101 * {@code null} if the specified type does not exist.
|
fiore@0
|
102 */
|
fiore@0
|
103 public List<String> getValues(String propertyType){
|
fiore@0
|
104 Entry e = properties.get(propertyType);
|
fiore@0
|
105 if(e == null)
|
fiore@0
|
106 throw new IllegalArgumentException(ILLEGAL_TYPE_MSG+propertyType);
|
fiore@0
|
107 return new ArrayList<String>(e.values);
|
fiore@0
|
108 }
|
fiore@0
|
109
|
fiore@0
|
110 /**
|
fiore@0
|
111 * Returns the view object associated with a property type in this NodeProperties instance. A view object is
|
fiore@0
|
112 * defined by the client of this class and it holds the information needed for a visual representation
|
fiore@3
|
113 * of the property.
|
fiore@3
|
114 *
|
fiore@0
|
115 * @param type the property type the returned view is associated with
|
fiore@0
|
116 * @return the View object or null if non has been set previously
|
fiore@0
|
117 */
|
fiore@0
|
118 public Object getView(String type){
|
fiore@0
|
119 Entry e = properties.get(type);
|
fiore@0
|
120 if(e == null)
|
fiore@0
|
121 throw new IllegalArgumentException(ILLEGAL_TYPE_MSG+type);
|
fiore@0
|
122 return e.view;
|
fiore@0
|
123 }
|
fiore@0
|
124
|
fiore@0
|
125 /**
|
fiore@0
|
126 * Sets the View object for the a type of properties. The NodeProperties only works
|
fiore@0
|
127 * as a holder as for the view objects. The client code of this class has to define
|
fiore@3
|
128 * its own view.
|
fiore@3
|
129 *
|
fiore@0
|
130 * @param type the type of property the view is associated with.
|
fiore@0
|
131 * @param o an object defined by user
|
fiore@0
|
132 * @see #getView(String)
|
fiore@0
|
133 */
|
fiore@0
|
134 public void setView(String type, Object o){
|
fiore@0
|
135 Entry e = properties.get(type);
|
fiore@0
|
136 if(e == null)
|
fiore@0
|
137 throw new IllegalArgumentException(ILLEGAL_TYPE_MSG+type);
|
fiore@0
|
138 e.view = o;
|
fiore@0
|
139 }
|
fiore@0
|
140
|
fiore@0
|
141 /**
|
fiore@0
|
142 * Returns a reference to the modifier object associated with a property type. Changes to the returned
|
fiore@0
|
143 * reference will affect the internal state of the NodeProperty object.
|
fiore@0
|
144 *
|
fiore@0
|
145 * @param propertyType a property type
|
fiore@0
|
146 * @return the modifiers of the specified property type or null if either
|
fiore@0
|
147 * the property type is null or it was not listed in the property type definition
|
fiore@0
|
148 * passed to the constructor
|
fiore@0
|
149 */
|
fiore@0
|
150 public Modifiers getModifiers(String propertyType){
|
fiore@0
|
151 Entry e = properties.get(propertyType);
|
fiore@0
|
152 if(e == null)
|
fiore@0
|
153 throw new IllegalArgumentException(ILLEGAL_TYPE_MSG+propertyType);
|
fiore@0
|
154 return e.modifiers;
|
fiore@0
|
155 }
|
fiore@0
|
156
|
fiore@0
|
157 /**
|
fiore@3
|
158 * Adds a value of the type passed as argument.
|
fiore@3
|
159 *
|
fiore@0
|
160 * @param propertyType a property type defined in the property type definition passed as argument to the constructor
|
fiore@0
|
161 * @param propertyValue the value to add to the property type
|
fiore@0
|
162 */
|
fiore@0
|
163 public void addValue(String propertyType, String propertyValue){
|
fiore@0
|
164 Entry e = properties.get(propertyType);
|
fiore@0
|
165 /* no such property type exists */
|
fiore@0
|
166 if(e == null)
|
fiore@0
|
167 throw new IllegalArgumentException(ILLEGAL_TYPE_MSG+propertyType);
|
fiore@0
|
168 e.values.add(propertyValue);
|
fiore@0
|
169 e.indexes.add(new LinkedHashSet<Integer>());
|
fiore@0
|
170 }
|
fiore@0
|
171
|
fiore@0
|
172 /**
|
fiore@0
|
173 * Adds a value of the type passed as argument and sets the modifier indexes for it as for
|
fiore@3
|
174 * {@link Modifiers#setIndexes(int, Set)}.
|
fiore@3
|
175 *
|
fiore@0
|
176 * @param propertyType a property type
|
fiore@0
|
177 * @param propertyValue a property value
|
fiore@0
|
178 * @param modifierIndexes the modifier set of indexes
|
fiore@0
|
179 *
|
fiore@0
|
180 * @throws IllegalArgumentException if propertyType
|
fiore@0
|
181 * is not among the ones in the type definition passed as argument to the constructor
|
fiore@0
|
182 */
|
fiore@0
|
183 public void addValue(String propertyType, String propertyValue, Set<Integer> modifierIndexes){
|
fiore@0
|
184 for(Integer i : modifierIndexes)
|
fiore@0
|
185 if((i < 0)||(i >= getModifiers(propertyType).getTypes().size()))
|
fiore@0
|
186 throw new ArrayIndexOutOfBoundsException("Index "+ i +
|
fiore@0
|
187 " corresponds to no Modifier type (modifierType size = "+
|
fiore@0
|
188 getModifiers(propertyType).getTypes().size()+")" );
|
fiore@0
|
189
|
fiore@0
|
190 Entry e = properties.get(propertyType);
|
fiore@0
|
191 if(e == null)
|
fiore@0
|
192 throw new IllegalArgumentException(ILLEGAL_TYPE_MSG+propertyType);
|
fiore@0
|
193 e.values.add(propertyValue);
|
fiore@0
|
194 e.indexes.add(modifierIndexes);
|
fiore@0
|
195 }
|
fiore@0
|
196
|
fiore@0
|
197 /**
|
fiore@3
|
198 * Removes the value at the specified index for the specified property type.
|
fiore@3
|
199 *
|
fiore@0
|
200 * @param propertyType a property type
|
fiore@0
|
201 * @param valueIndex the index of the value to remove
|
fiore@0
|
202 * @return the removed value
|
fiore@0
|
203 * @throws IllegalArgumentException if propertyType
|
fiore@0
|
204 * is not among the ones in the type definition passed as argument to the constructor
|
fiore@0
|
205 */
|
fiore@0
|
206 public String removeValue(String propertyType, int valueIndex){
|
fiore@0
|
207 Entry e = properties.get(propertyType);
|
fiore@0
|
208 if(e == null)
|
fiore@0
|
209 throw new IllegalArgumentException(ILLEGAL_TYPE_MSG+propertyType);
|
fiore@0
|
210 e.indexes.remove(valueIndex);
|
fiore@0
|
211 return e.values.remove(valueIndex);
|
fiore@0
|
212 }
|
fiore@0
|
213
|
fiore@0
|
214 /**
|
fiore@3
|
215 * Sets the value of a property type at the specified index to a new value.
|
fiore@3
|
216 *
|
fiore@0
|
217 * @param propertyType a property type
|
fiore@0
|
218 * @param valueIndex the index of the value which must be replaced
|
fiore@0
|
219 * @param newValue the new value for the specified index
|
fiore@3
|
220 * @throws IllegalArgumentException if propertyType
|
fiore@0
|
221 * is not among the ones in the type definition passed as argument to the constructor
|
fiore@0
|
222 */
|
fiore@0
|
223 public void setValue(String propertyType, int valueIndex, String newValue){
|
fiore@0
|
224 Entry e = properties.get(propertyType);
|
fiore@0
|
225 if(e == null)
|
fiore@0
|
226 throw new IllegalArgumentException(ILLEGAL_TYPE_MSG+propertyType);
|
fiore@0
|
227 e.values.set(valueIndex, newValue);
|
fiore@0
|
228 }
|
fiore@0
|
229
|
fiore@0
|
230 /**
|
fiore@3
|
231 * Removes all the values and modifiers for a specific type.
|
fiore@3
|
232 *
|
fiore@0
|
233 * @param propertyType the type whose property and modifiers must be removed
|
fiore@0
|
234 * @throws IllegalArgumentException if propertyType
|
fiore@0
|
235 * is not among the ones in the type definition passed as argument to the constructor
|
fiore@0
|
236 */
|
fiore@0
|
237 public void clear(String propertyType){
|
fiore@0
|
238 Entry e = properties.get(propertyType);
|
fiore@0
|
239 if(e == null)
|
fiore@0
|
240 throw new IllegalArgumentException(ILLEGAL_TYPE_MSG+propertyType);
|
fiore@0
|
241 e.values.clear();
|
fiore@0
|
242 e.indexes.clear();
|
fiore@0
|
243 }
|
fiore@0
|
244
|
fiore@0
|
245 /**
|
fiore@0
|
246 * Removes all the values and modifiers of this object.
|
fiore@0
|
247 */
|
fiore@0
|
248 public void clear(){
|
fiore@0
|
249 for(String type : types){
|
fiore@0
|
250 clear(type);
|
fiore@0
|
251 }
|
fiore@0
|
252 }
|
fiore@0
|
253
|
fiore@0
|
254 /**
|
fiore@3
|
255 * Returns true if this NodeProperties contains no values.
|
fiore@3
|
256 *
|
fiore@0
|
257 * @return true if this NodeProperties contains no values
|
fiore@0
|
258 */
|
fiore@0
|
259 public boolean isEmpty(){
|
fiore@0
|
260 boolean empty = true;
|
fiore@0
|
261 for(String type : types)
|
fiore@0
|
262 if(!properties.get(type).values.isEmpty()){
|
fiore@0
|
263 empty = false;
|
fiore@0
|
264 break;
|
fiore@0
|
265 }
|
fiore@0
|
266 return empty;
|
fiore@0
|
267 }
|
fiore@0
|
268
|
fiore@0
|
269 /**
|
fiore@3
|
270 * Returns true if there are no values for the specified type in this NodeProperties instance.
|
fiore@3
|
271 *
|
fiore@5
|
272 * @param propertyType the property type to be checked for value presence
|
fiore@0
|
273 * @return true if there are no values for the specified type in this NodeProperties instance
|
fiore@0
|
274 */
|
fiore@0
|
275 public boolean typeIsEmpty(String propertyType){
|
fiore@0
|
276 Entry e = properties.get(propertyType);
|
fiore@0
|
277 if(e == null)
|
fiore@0
|
278 throw new IllegalArgumentException(ILLEGAL_TYPE_MSG+propertyType);
|
fiore@0
|
279 return e.values.isEmpty();
|
fiore@0
|
280 }
|
fiore@0
|
281
|
fiore@0
|
282 /**
|
fiore@0
|
283 * true if this NodeProperties object has no types. This can happen if the constructor
|
fiore@3
|
284 * has been called with an empty or null property type definition.
|
fiore@3
|
285 *
|
fiore@0
|
286 * @return true if this NodeProperties object has no types
|
fiore@0
|
287 */
|
fiore@0
|
288 public boolean isNull(){
|
fiore@0
|
289 return types.isEmpty();
|
fiore@0
|
290 }
|
fiore@0
|
291
|
fiore@0
|
292 /**
|
fiore@0
|
293 * Returns a string representation of types, value and modifiers of this property. Such a
|
fiore@3
|
294 * representation can be passed as argument to {@link #fill(String)} to populate a NodeProperties
|
fiore@0
|
295 * object. Such NodeProperties object though must have the same type and modifier definition of
|
fiore@0
|
296 * the object this method is called on.
|
fiore@0
|
297 *
|
fiore@0
|
298 * @return a string representation of the values and modifiers of this object
|
fiore@0
|
299 */
|
fiore@0
|
300 @Override
|
fiore@0
|
301 public String toString(){
|
fiore@0
|
302 StringBuilder builder = new StringBuilder();
|
fiore@0
|
303 for(String type : types){
|
fiore@0
|
304 builder.append(TYPE_ENTRY_SEPARATOR).append(type);
|
fiore@0
|
305 int propertyValueIndex = 0;
|
fiore@0
|
306 for(String value : properties.get(type).values){
|
fiore@0
|
307 builder.append(VALUE_ENTRY_SEPARATOR);
|
fiore@0
|
308 builder.append(value);
|
fiore@0
|
309 for(int modifierIndex : getModifiers(type).getIndexes(propertyValueIndex)){
|
fiore@0
|
310 builder.append(MODIFIER_ENTRY_SEPARATOR);
|
fiore@0
|
311 builder.append(modifierIndex);
|
fiore@0
|
312 }
|
fiore@0
|
313 propertyValueIndex++;
|
fiore@0
|
314 }
|
fiore@0
|
315 }
|
fiore@0
|
316 return builder.toString();
|
fiore@0
|
317 }
|
fiore@0
|
318
|
fiore@0
|
319 /**
|
fiore@0
|
320 * Fills up the this property according to the string passed as arguments
|
fiore@3
|
321 * The string must be generated by calling toString on a NodeProperty instance
|
fiore@0
|
322 * holding the same property types as type, otherwise an IllegalArgumentException
|
fiore@0
|
323 * is likely to be thrown.
|
fiore@0
|
324 *
|
fiore@0
|
325 * @param s the string representation of the property values, such as the one returned
|
fiore@0
|
326 * by toString()
|
fiore@0
|
327 * @throws IllegalArgumentException if s contains property types which
|
fiore@0
|
328 * are not among the ones in the type definition passed as argument to the constructor
|
fiore@0
|
329 */
|
fiore@3
|
330 public void fill(String s){
|
fiore@0
|
331 /* clear up previous values */
|
fiore@0
|
332 clear();
|
fiore@0
|
333
|
fiore@0
|
334 /* a property entry is a string with the type of the property followed by value *
|
fiore@0
|
335 * entries of that type. all value entries begin with the VALUE_SEPARATOR. *
|
fiore@0
|
336 * a value entry is a property value followed by its modifiers entries, a modifier entry *
|
fiore@0
|
337 * is a modifier beginning with the MODIFIER_SEPARATOR */
|
fiore@0
|
338 String propertyEntries[] = s.split(TYPE_ENTRY_SEPARATOR);
|
fiore@0
|
339 for(String propertyEntry : propertyEntries){
|
fiore@0
|
340 String[] typeEntries = propertyEntry.split(VALUE_ENTRY_SEPARATOR);
|
fiore@0
|
341 String type = typeEntries[0];
|
fiore@0
|
342 for(int i=1;i<typeEntries.length;i++){
|
fiore@0
|
343 Entry e = properties.get(type);
|
fiore@0
|
344 if(e == null)
|
fiore@0
|
345 throw new IllegalArgumentException(ILLEGAL_TYPE_MSG+type);
|
fiore@0
|
346 String valueEntries[] = typeEntries[i].split(MODIFIER_ENTRY_SEPARATOR);
|
fiore@0
|
347 String value = valueEntries[0];
|
fiore@0
|
348 LinkedHashSet<Integer> modifiers = new LinkedHashSet<Integer>();
|
fiore@0
|
349 for(int j=1;j<valueEntries.length;j++){
|
fiore@0
|
350 modifiers.add(Integer.valueOf(valueEntries[j]));
|
fiore@0
|
351 }
|
fiore@0
|
352 addValue(type,value,modifiers);
|
fiore@0
|
353 }
|
fiore@0
|
354 }
|
fiore@0
|
355 }
|
fiore@0
|
356
|
fiore@0
|
357 @Override
|
fiore@0
|
358 @SuppressWarnings(value = "unchecked")
|
fiore@0
|
359 public Object clone(){
|
fiore@0
|
360 NodeProperties p = null;
|
fiore@0
|
361 try {
|
fiore@0
|
362 p = (NodeProperties)super.clone();
|
fiore@0
|
363 } catch (CloneNotSupportedException e) {
|
fiore@0
|
364 e.printStackTrace();
|
fiore@0
|
365 }
|
fiore@0
|
366 p.properties = (LinkedHashMap<String,Entry>)properties.clone();
|
fiore@0
|
367 for(String key : p.properties.keySet()){
|
fiore@0
|
368 Entry old = p.properties.get(key);
|
fiore@0
|
369 Entry q = new Entry();
|
fiore@0
|
370 q.values = new ArrayList<String>();
|
fiore@0
|
371 q.indexes = new ArrayList<Set<Integer>>();
|
fiore@0
|
372 q.view = old.view;
|
fiore@0
|
373 if(old.modifiers != null){
|
fiore@0
|
374 q.modifiers = new Modifiers(old.modifiers.modifierTypes, q.indexes);
|
fiore@0
|
375 for(String modifierType : q.modifiers.getTypes())
|
fiore@0
|
376 q.modifiers.setView(modifierType, old.modifiers.getView(modifierType));
|
fiore@0
|
377 }
|
fiore@0
|
378 p.properties.put(key, q);
|
fiore@0
|
379 }
|
fiore@0
|
380 return p;
|
fiore@0
|
381 }
|
fiore@0
|
382
|
fiore@0
|
383 private class Entry{
|
fiore@0
|
384 List<String> values;
|
fiore@0
|
385 List<Set<Integer>> indexes;
|
fiore@0
|
386 Modifiers modifiers;
|
fiore@0
|
387 Object view;
|
fiore@0
|
388 }
|
fiore@0
|
389
|
fiore@0
|
390 /**
|
fiore@0
|
391 * A modifier is a label peculiar of a certain subset of properties. For example in
|
fiore@0
|
392 * a UML class diagram one or more methods can be labelled as <i>public</i>, <i>private</i> or <i>protected</i>.
|
fiore@0
|
393 * Had a NodeProperties instance been used to represent the methods of a class node, there would be then
|
fiore@0
|
394 * one modifier for each label: one for <i>public</i>, one for <i>private</i>, and one for <i>protected</i>. To each modifier
|
fiore@0
|
395 * a view-object can be associated, which describes how these labels would be rendered visually.
|
fiore@0
|
396 * Following on from the UML example, a view-object would be used with the protected modifier
|
fiore@0
|
397 * to hold the information that the properties which are assigned such a modifier must be prefixed
|
fiore@0
|
398 * with the '#' sign.
|
fiore@0
|
399 */
|
fiore@0
|
400 public class Modifiers{
|
fiore@0
|
401 private Modifiers(Set<String> modifierTypes, List<Set<Integer>> indexes){
|
fiore@0
|
402 views = new LinkedHashMap<String,Object>();
|
fiore@0
|
403 indexesRef = indexes;
|
fiore@0
|
404 this.modifierTypes = Collections.unmodifiableList(new ArrayList<String>(modifierTypes));
|
fiore@0
|
405 for(String modifierType : modifierTypes){
|
fiore@0
|
406 views.put(modifierType,null);
|
fiore@0
|
407 }
|
fiore@0
|
408 }
|
fiore@0
|
409
|
fiore@0
|
410 /* only used by NodeProperties.clone() method */
|
fiore@0
|
411 private Modifiers(List<String> modifierTypes, List<Set<Integer>> indexes){
|
fiore@0
|
412 views = new LinkedHashMap<String,Object>();
|
fiore@0
|
413 indexesRef = indexes;
|
fiore@0
|
414 this.modifierTypes = modifierTypes;
|
fiore@0
|
415 for(String modifierType : modifierTypes){
|
fiore@0
|
416 views.put(modifierType,null);
|
fiore@0
|
417 }
|
fiore@0
|
418 }
|
fiore@0
|
419
|
fiore@0
|
420 /**
|
fiore@0
|
421 * Returns the list of modifier types, as per the type definition passed as argument to the NodeProperties
|
fiore@0
|
422 * constructor.
|
fiore@3
|
423 *
|
fiore@0
|
424 * @return a list of modifier types
|
fiore@0
|
425 * @see NodeProperties#NodeProperties(LinkedHashMap)
|
fiore@0
|
426 */
|
fiore@0
|
427 public List<String> getTypes(){
|
fiore@0
|
428 return modifierTypes;
|
fiore@0
|
429 }
|
fiore@0
|
430
|
fiore@0
|
431 /**
|
fiore@0
|
432 * Returns the view object associated with a modifier type in this Modifier instance. A view object is
|
fiore@0
|
433 * defined by the client of this class and it holds the information needed for a visual representation
|
fiore@0
|
434 * of the modifier.
|
fiore@3
|
435 *
|
fiore@3
|
436 * @param modifierType the property type the returned view is associated with
|
fiore@0
|
437 * @return the View object or null if non has been set previously
|
fiore@0
|
438 */
|
fiore@0
|
439 public Object getView(String modifierType){
|
fiore@0
|
440 return views.get(modifierType);
|
fiore@0
|
441 }
|
fiore@0
|
442
|
fiore@0
|
443 /**
|
fiore@0
|
444 * Sets the View object for the a type of modifier. The NodeProperties only works
|
fiore@0
|
445 * as a holder as for the view objects. The client code of this class has to define
|
fiore@0
|
446 * its own view, which will then be used by the client itself to visualise the modifier
|
fiore@3
|
447 *
|
fiore@3
|
448 * @param modifierType the type of modifier the view is associated with.
|
fiore@5
|
449 * @param view an object defined by user defining how this property looks like
|
fiore@0
|
450 * @see #getView(String)
|
fiore@0
|
451 * @throws IllegalArgumentException if modifierType
|
fiore@0
|
452 * is not among the ones in the type definition passed as argument to the constructor
|
fiore@0
|
453 */
|
fiore@0
|
454 public void setView(String modifierType, Object view){
|
fiore@0
|
455 if(!views.containsKey(modifierType))
|
fiore@0
|
456 throw new IllegalArgumentException(ILLEGAL_TYPE_MSG+modifierType);
|
fiore@0
|
457 views.put(modifierType,view);
|
fiore@0
|
458 }
|
fiore@0
|
459
|
fiore@0
|
460 /**
|
fiore@0
|
461 * Returns the modifier indexes for the specified property value. Each property type can be associated
|
fiore@0
|
462 * with one or more modifier type and each property value can be assigned one or more modifier. The
|
fiore@0
|
463 * integer set returned by this method tells the client code to which modifiers the property value at the index
|
fiore@0
|
464 * passed as argument is assigned. The returned indexes refer to the modifier list returned by {@link #getTypes()}
|
fiore@0
|
465 *
|
fiore@5
|
466 * @param propertyValueIndex the index of the property value for which the set of modifier indexes
|
fiore@5
|
467 * is being queried
|
fiore@5
|
468 * @return a set of indexes of the modifier types the property value at the index passed as argument
|
fiore@0
|
469 * is assigned to
|
fiore@0
|
470 */
|
fiore@0
|
471 public Set<Integer> getIndexes(int propertyValueIndex){
|
fiore@0
|
472 Set<Integer> set = indexesRef.get(propertyValueIndex);
|
fiore@0
|
473 return (new LinkedHashSet<Integer>(set));
|
fiore@0
|
474 }
|
fiore@0
|
475
|
fiore@0
|
476 /**
|
fiore@0
|
477 * Set the modifier indexes for the property value at the index passed as argument
|
fiore@3
|
478 *
|
fiore@0
|
479 * @param propertyValueIndex the index of the property value
|
fiore@0
|
480 * @param modifierIndexes a set of indexes which refer to the list returned by {@link #getTypes()}
|
fiore@0
|
481 * @throws ArrayIndexOutOfBoundsException if one or more of the indexes in modifierIndexes are lower than 0 or greater
|
fiore@0
|
482 * or equal to the size of the modifier type list returned by {@link #getTypes()}. The same exception is also thrown
|
fiore@0
|
483 * if propertyValueIndex is lower than 0 or greater or equal to the property values list returned by {@link NodeProperties#getValues(String)}
|
fiore@0
|
484 * passing as argument the same property type passed to {@link NodeProperties#getModifiers(String)} to obtain
|
fiore@0
|
485 * this Modifiers instance.
|
fiore@0
|
486 * @see #getIndexes(int)
|
fiore@0
|
487 */
|
fiore@0
|
488 public void setIndexes(int propertyValueIndex, Set<Integer> modifierIndexes){
|
fiore@0
|
489 for(Integer i : modifierIndexes)
|
fiore@0
|
490 if((i < 0)||(i >= getTypes().size()))
|
fiore@0
|
491 throw new ArrayIndexOutOfBoundsException("Index "+ i + " corresponds to no Modifier Type (modifierType size = "+getTypes().size()+")" );
|
fiore@0
|
492
|
fiore@0
|
493 Set<Integer> m = indexesRef.get(propertyValueIndex);
|
fiore@0
|
494 m.clear();
|
fiore@0
|
495 m.addAll(modifierIndexes);
|
fiore@0
|
496 }
|
fiore@0
|
497
|
fiore@0
|
498 /**
|
fiore@3
|
499 * Removes all the modifier indexes for a property value at the specified index.
|
fiore@3
|
500 *
|
fiore@0
|
501 * @param propertyValueIndex the index of the property value
|
fiore@0
|
502 */
|
fiore@0
|
503 public void clear(int propertyValueIndex){
|
fiore@0
|
504 Set<Integer> m = indexesRef.get(propertyValueIndex);
|
fiore@0
|
505 m.clear();
|
fiore@0
|
506 }
|
fiore@0
|
507
|
fiore@0
|
508 /**
|
fiore@0
|
509 * true if this Modifiers object has no types. This can happen if the constructor
|
fiore@0
|
510 * has been called with an empty or null modifier in the type definition passed as argument
|
fiore@3
|
511 * to the constructor of the NodeProperties object holding this Modifiers object.
|
fiore@3
|
512 *
|
fiore@0
|
513 * @return true if this Modifiers object has no types
|
fiore@0
|
514 */
|
fiore@0
|
515 public boolean isNull(){
|
fiore@0
|
516 return modifierTypes.isEmpty();
|
fiore@0
|
517 }
|
fiore@0
|
518
|
fiore@0
|
519 private LinkedHashMap<String,Object> views;
|
fiore@0
|
520 private final List<String> modifierTypes;
|
fiore@0
|
521 private List<Set<Integer>> indexesRef;
|
fiore@0
|
522 }
|
fiore@0
|
523
|
fiore@0
|
524 /* for each property (key) I associate a Couple (value) made out of *
|
fiore@0
|
525 * a list of the property values plus a list of possible modifiers */
|
fiore@0
|
526 private LinkedHashMap<String,Entry> properties;
|
fiore@0
|
527 private final List<String> types;
|
fiore@0
|
528 private Map<String,Set<String>> typeDefinition;
|
fiore@0
|
529
|
fiore@0
|
530 private static final LinkedHashMap<String,Set<String>> EMPTY_PROPERTY_TYPE_DEFINITION = new LinkedHashMap<String,Set<String>>();
|
fiore@0
|
531 private static final Set<String> EMPTY_MODIFIER_TYPE_DEFINITION = Collections.emptySet();
|
fiore@0
|
532 private static final String ILLEGAL_TYPE_MSG = "argument must be in type definition list: ";
|
fiore@0
|
533 /**
|
fiore@0
|
534 * A special static instance of the class corresponding to the null NodeProperties. A null NodeProperties instance will have isNull() returning true,
|
fiore@0
|
535 * which means it has no property types associated.
|
fiore@3
|
536 * @see #isNull()
|
fiore@0
|
537 */
|
fiore@0
|
538 public static final NodeProperties NULL_PROPERTIES = new NodeProperties(EMPTY_PROPERTY_TYPE_DEFINITION);
|
fiore@0
|
539
|
fiore@0
|
540 private final static String TYPE_ENTRY_SEPARATOR = "\n:";
|
fiore@0
|
541 private final static String VALUE_ENTRY_SEPARATOR = "\n;";
|
fiore@0
|
542 private final static String MODIFIER_ENTRY_SEPARATOR = "\n,";
|
fiore@0
|
543 }
|