View Javadoc
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 }