1 package org.opentrafficsim.base.modelproperties;
2
3 import java.io.Serializable;
4 import java.util.ArrayList;
5 import java.util.Collections;
6 import java.util.Comparator;
7 import java.util.HashMap;
8 import java.util.Iterator;
9 import java.util.List;
10 import java.util.Map;
11
12
13
14
15
16
17
18
19
20
21
22 public class CompoundProperty extends AbstractProperty<List<Property<?>>> implements Serializable
23 {
24
25 private static final long serialVersionUID = 20150000L;
26
27
28 private final List<Property<?>> value = new ArrayList<>();
29
30
31 private Map<String, Property<?>> propertyGroup = new HashMap<>();
32
33
34
35
36
37
38
39
40
41
42
43 public CompoundProperty(final String key, final String shortName, final String description,
44 final List<Property<?>> initialValue, final boolean readOnly, final int displayPriority) throws PropertyException
45 {
46 super(key, displayPriority, shortName, description);
47 if (null != initialValue)
48 {
49 for (Property<?> ap : initialValue)
50 {
51 add(ap);
52 }
53 }
54 setReadOnly(readOnly);
55 }
56
57
58 @Override
59 public final List<Property<?>> getValue()
60 {
61 return new ArrayList<Property<?>>(this.value);
62 }
63
64
65 @Override
66 public final void setValue(final List<Property<?>> newValue) throws PropertyException
67 {
68 for (Property<?> ap : getValue())
69 {
70 remove(ap);
71 }
72 for (Property<?> ap : newValue)
73 {
74 add(ap);
75 }
76 }
77
78
79
80
81
82
83
84
85 public final Property<?> findSubPropertyByKey(final String key)
86 {
87
88 Iterator<Property<?>> i = this.iterator();
89 while (i.hasNext())
90 {
91 Property<?> ap = i.next();
92
93 if (ap.getKey().equals(key))
94 {
95 return ap;
96 }
97 }
98 return null;
99 }
100
101
102
103
104
105
106
107 public final void add(final int index, final Property<?> ap) throws PropertyException
108 {
109 if (isReadOnly())
110 {
111 throw new PropertyException("Cannot modify a read-only CompoundProperty");
112 }
113 if (index < 0 || index > this.value.size())
114 {
115 throw new PropertyException("index is out of range");
116 }
117 if (this.propertyGroup.containsKey(ap.getKey()))
118 {
119 throw new PropertyException("AbstractProperty " + ap + " is already registered in property group of " + this);
120 }
121
122 for (Property<?> subProperty : ap)
123 {
124 if (this.propertyGroup.containsKey(subProperty.getKey()))
125 {
126 throw new PropertyException(
127 "A property with key " + subProperty.getKey() + " is already known in this property group");
128 }
129 }
130
131 for (Property<?> subProperty : ap)
132 {
133 this.propertyGroup.put(subProperty.getKey(), subProperty);
134 if (subProperty instanceof CompoundProperty)
135 {
136
137 ((CompoundProperty) subProperty).setPropertyGroup(this.propertyGroup);
138 }
139 }
140 this.value.add(index, ap);
141 ((AbstractProperty<?>) ap).setParent(this);
142 }
143
144
145
146
147
148
149 public final void add(final Property<?> ap) throws PropertyException
150 {
151 add(this.value.size(), ap);
152 }
153
154
155
156
157
158
159 public final void remove(final int index) throws PropertyException
160 {
161 if (isReadOnly())
162 {
163 throw new PropertyException("Cannot modify a read-only CompoundProperty");
164 }
165 if (index < 0 || index >= this.value.size())
166 {
167 throw new PropertyException("index is out of range");
168 }
169 this.propertyGroup.remove(this.value.get(index));
170 Property<?> removed = this.value.remove(index);
171 ((AbstractProperty<?>) removed).setParent(null);
172 if (removed instanceof CompoundProperty)
173 {
174 ((CompoundProperty) removed).setPropertyGroup(null);
175 }
176 }
177
178
179
180
181
182
183
184 public final void remove(final Property<?> removeMe) throws PropertyException
185 {
186 int i = this.value.indexOf(removeMe);
187 if (i < 0)
188 {
189 throw new PropertyException(
190 "Cannot remove property " + removeMe + " because it is not part of this compound property");
191 }
192 remove(i);
193 }
194
195
196
197
198
199 public final int size()
200 {
201 return this.value.size();
202 }
203
204
205
206
207
208
209
210 protected final void setPropertyGroup(final Map<String, Property<?>> newPropertyGroup)
211 {
212 if (null == newPropertyGroup)
213 {
214
215 this.propertyGroup = new HashMap<String, Property<?>>();
216 for (Property<?> ap : this.value)
217 {
218 this.propertyGroup.put(ap.getKey(), ap);
219 }
220 }
221 else
222 {
223 this.propertyGroup = newPropertyGroup;
224 for (Property<?> ap : this)
225 {
226 this.propertyGroup.put(ap.getKey(), ap);
227 }
228 }
229 }
230
231
232
233
234
235
236
237 public final Property<?> get(final int index) throws PropertyException
238 {
239 if (index < 0 || index >= this.value.size())
240 {
241 throw new PropertyException("index is out of range");
242 }
243 return this.value.get(index);
244 }
245
246
247
248
249
250 public final List<Property<?>> displayOrderedValue()
251 {
252 List<Property<?>> result = new ArrayList<>(this.value);
253 final List<Property<?>> list = this.value;
254 Collections.sort(result, new Comparator<Property<?>>()
255 {
256
257 @Override
258 public int compare(final Property<?> arg0, final Property<?> arg1)
259 {
260 int dp0 = arg0.getDisplayPriority();
261 int dp1 = arg1.getDisplayPriority();
262 if (dp0 < dp1)
263 {
264 return -1;
265 }
266 else if (dp0 > dp1)
267 {
268 return 1;
269 }
270 int i0 = list.indexOf(arg0);
271 int i1 = list.indexOf(arg1);
272 if (i0 < i1)
273 {
274 return -1;
275 }
276 else if (i0 > i1)
277 {
278 return 1;
279 }
280 return 0;
281 }
282
283 });
284
285
286
287
288
289
290
291
292 return result;
293 }
294
295
296 @Override
297 public final String htmlStateDescription()
298 {
299 StringBuilder result = new StringBuilder();
300 result.append("<table border=\"1\">");
301 result.append("<tr><th align=\"left\">" + getShortName() + "</th></tr>\n");
302 for (Property<?> ap : displayOrderedValue())
303 {
304 result.append("<tr><td> " + ap.htmlStateDescription() + "</td></tr>\n");
305 }
306 result.append("</table>\n");
307 return result.toString();
308 }
309
310
311 @Override
312 public final CompoundProperty deepCopy()
313 {
314 ArrayList<Property<?>> copyOfValue = new ArrayList<>();
315 for (Property<?> ap : this.value)
316 {
317 copyOfValue.add(ap.deepCopy());
318 }
319 try
320 {
321 return new CompoundProperty(getKey(), getShortName(), getDescription(), copyOfValue, isReadOnly(),
322 getDisplayPriority());
323 }
324 catch (PropertyException exception)
325 {
326 System.err.println("Cannot happen");
327 exception.printStackTrace();
328 }
329 return null;
330 }
331
332
333
334
335
336 protected final Map<String, Property<?>> getPropertyGroup()
337 {
338 return this.propertyGroup;
339 }
340
341 }