1 /*
2 * Metis: Java Data Framework
3 * Copyright 2012-2026. Tony Washer
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6 * use this file except in compliance with the License. You may obtain a copy
7 * of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations under
15 * the License.
16 */
17 package io.github.tonywasher.joceanus.metis.viewer;
18
19 import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataList;
20 import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataMap;
21 import io.github.tonywasher.joceanus.metis.field.MetisFieldItem;
22 import io.github.tonywasher.joceanus.metis.field.MetisFieldItem.MetisFieldDef;
23
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Map;
29
30 /**
31 * Data Viewer Entry.
32 */
33 public class MetisViewerEntry {
34 /**
35 * Entry name prefix.
36 */
37 private static final String ENTRY_PREFIX = "TreeItem";
38
39 /**
40 * The ViewerManager.
41 */
42 private final MetisViewerManager theManager;
43
44 /**
45 * The Parent.
46 */
47 private final MetisViewerEntry theParent;
48
49 /**
50 * The id of the entry.
51 */
52 private final int theId;
53
54 /**
55 * The Child List.
56 */
57 private List<MetisViewerEntry> theChildList;
58
59 /**
60 * The unique name of the entry.
61 */
62 private final String theUniqueName;
63
64 /**
65 * The name of the entry.
66 */
67 private final String theDisplayName;
68
69 /**
70 * The object for the entry.
71 */
72 private Object theObject;
73
74 /**
75 * Is the entry visible?.
76 */
77 private boolean isVisible;
78
79 /**
80 * Constructor.
81 *
82 * @param pManager the viewer manager
83 * @param pParent the parent entry
84 * @param pName the entry display name
85 */
86 protected MetisViewerEntry(final MetisViewerManager pManager,
87 final MetisViewerEntry pParent,
88 final String pName) {
89 /* Store parameters */
90 theManager = pManager;
91 theParent = pParent;
92 theDisplayName = pName;
93
94 /* Obtain entry id. */
95 theId = pManager.getNextId();
96
97 /* Determine unique name */
98 theUniqueName = ENTRY_PREFIX
99 + theId;
100
101 /* Initialise to visible */
102 isVisible = true;
103
104 /* If we have a parent */
105 if (pParent != null) {
106 /* Add the entry to the child list */
107 pParent.addChild(this);
108 }
109 }
110
111 /**
112 * Get viewer manager.
113 *
114 * @return the manager
115 */
116 protected MetisViewerManager getManager() {
117 return theManager;
118 }
119
120 /**
121 * Get parent.
122 *
123 * @return the parent
124 */
125 protected MetisViewerEntry getParent() {
126 return theParent;
127 }
128
129 /**
130 * Get unique name.
131 *
132 * @return the name
133 */
134 public String getUniqueName() {
135 return theUniqueName;
136 }
137
138 /**
139 * Get display name.
140 *
141 * @return the name
142 */
143 public String getDisplayName() {
144 return theDisplayName;
145 }
146
147 /**
148 * Get id.
149 *
150 * @return the id
151 */
152 public int getId() {
153 return theId;
154 }
155
156 /**
157 * Get object.
158 *
159 * @return the object
160 */
161 public Object getObject() {
162 return theObject;
163 }
164
165 @Override
166 public String toString() {
167 return theDisplayName;
168 }
169
170 /**
171 * Get child iterator.
172 *
173 * @return the iterator
174 */
175 public Iterator<MetisViewerEntry> childIterator() {
176 return theChildList == null
177 ? Collections.emptyIterator()
178 : theChildList.iterator();
179 }
180
181 /**
182 * Add child.
183 *
184 * @param pChild the child to add
185 */
186 private void addChild(final MetisViewerEntry pChild) {
187 if (theChildList == null) {
188 theChildList = new ArrayList<>();
189 }
190 theChildList.add(pChild);
191 }
192
193 /**
194 * Is the entry visible?.
195 *
196 * @return true/false
197 */
198 public boolean isVisible() {
199 return isVisible;
200 }
201
202 /**
203 * Set entry visibility.
204 *
205 * @param pVisible true/false
206 */
207 public void setVisible(final boolean pVisible) {
208 /* If this is a change in status */
209 if (isVisible != pVisible) {
210 /* Change status and report it */
211 isVisible = pVisible;
212 theManager.fireEvent(MetisViewerEvent.VISIBILITY, this);
213 }
214 }
215
216 /**
217 * Set Focus onto this entry.
218 */
219 public void setFocus() {
220 theManager.setFocus(this);
221 }
222
223 /**
224 * Set Focus onto child of this entry.
225 *
226 * @param pName the name of the child
227 */
228 public void setFocus(final String pName) {
229 /* Loop through the children */
230 for (MetisViewerEntry myEntry : theChildList) {
231 /* If we match the object */
232 if (pName.equals(myEntry.getDisplayName())) {
233 /* Set the focus and return */
234 myEntry.setFocus();
235 return;
236 }
237 }
238 }
239
240 /**
241 * Set the object referred to by the entry.
242 *
243 * @param pObject the new object
244 */
245 public void setObject(final Object pObject) {
246 /* Set the new object */
247 setTheObject(pObject);
248
249 /* Notify regarding the data change */
250 theManager.fireEvent(MetisViewerEvent.VALUE, this);
251 }
252
253 /**
254 * Set the tree object referred to by the entry.
255 *
256 * @param pObject the new object
257 */
258 public void setTreeObject(final Object pObject) {
259 /* Set the new object */
260 setTheObject(pObject);
261
262 /* Create child elements if required */
263 if (pObject instanceof MetisFieldItem myItem) {
264 createChildElements(myItem);
265 }
266
267 /* Notify regarding the data change */
268 theManager.fireEvent(MetisViewerEvent.VALUE, this);
269 }
270
271 /**
272 * Set the object referred to by the entry.
273 *
274 * @param pObject the new object
275 */
276 private void setTheObject(final Object pObject) {
277 /* Set the new object */
278 theObject = pObject;
279
280 /* Clear the childList */
281 if (theChildList != null) {
282 theChildList.clear();
283 }
284 }
285
286 /**
287 * Create child elements.
288 *
289 * @param pItem the item
290 */
291 private void createChildElements(final MetisFieldItem pItem) {
292 /* Loop through the fields */
293 final Iterator<MetisFieldDef> myIterator = pItem.getDataFieldSet().fieldIterator();
294 while (myIterator.hasNext()) {
295 final MetisFieldDef myField = myIterator.next();
296
297 /* Obtain the value */
298 final Object myValue = myField.getFieldValue(pItem);
299 boolean addChild = false;
300
301 /* Determine whether to add the child */
302 if (myValue instanceof List) {
303 addChild = !((List<?>) myValue).isEmpty();
304 } else if (myValue instanceof MetisDataList) {
305 addChild = !((MetisDataList<?>) myValue).isEmpty();
306 } else if (myValue instanceof Map) {
307 addChild = !((Map<?, ?>) myValue).isEmpty();
308 } else if (myValue instanceof MetisDataMap) {
309 addChild = !((MetisDataMap<?, ?>) myValue).isEmpty();
310 }
311
312 /* If we should add the child */
313 if (addChild) {
314 /* Create it */
315 final MetisViewerEntry myChild = theManager.newEntry(this, myField.getFieldId().getId());
316 myChild.setObject(myValue);
317 }
318 }
319 }
320
321 @Override
322 public boolean equals(final Object pThat) {
323 /* Handle trivial cases */
324 if (this == pThat) {
325 return true;
326 }
327 if (pThat == null) {
328 return false;
329 }
330
331 /* Check class */
332 if (!(pThat instanceof MetisViewerEntry myThat)) {
333 return false;
334 }
335
336 /* Must have same id */
337 return theId == myThat.theId;
338 }
339
340 @Override
341 public int hashCode() {
342 return theId;
343 }
344 }