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