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