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 MetisViewerEntryImpl
34          implements MetisViewerEntry {
35      /**
36       * Entry name prefix.
37       */
38      private static final String ENTRY_PREFIX = "TreeItem";
39  
40      /**
41       * The ViewerManager.
42       */
43      private final MetisViewerManager theManager;
44  
45      /**
46       * The Parent.
47       */
48      private final MetisViewerEntry theParent;
49  
50      /**
51       * The id of the entry.
52       */
53      private final int theId;
54  
55      /**
56       * The Child List.
57       */
58      private List<MetisViewerEntry> theChildList;
59  
60      /**
61       * The unique name of the entry.
62       */
63      private final String theUniqueName;
64  
65      /**
66       * The name of the entry.
67       */
68      private final String theDisplayName;
69  
70      /**
71       * The object for the entry.
72       */
73      private Object theObject;
74  
75      /**
76       * Is the entry visible?.
77       */
78      private boolean isVisible;
79  
80      /**
81       * Constructor.
82       *
83       * @param pManager the viewer manager
84       * @param pParent  the parent entry
85       * @param pName    the entry display name
86       */
87      MetisViewerEntryImpl(final MetisViewerManager pManager,
88                           final MetisViewerEntry pParent,
89                           final String pName) {
90          /* Store parameters */
91          theManager = pManager;
92          theParent = pParent;
93          theDisplayName = pName;
94  
95          /* Obtain entry id. */
96          theId = pManager.getNextId();
97  
98          /* Determine unique name */
99          theUniqueName = ENTRY_PREFIX
100                 + theId;
101 
102         /* Initialise to visible */
103         isVisible = true;
104 
105         /* If we have a parent */
106         if (pParent != null) {
107             /* Add the entry to the child list */
108             ((MetisViewerEntryImpl) pParent).addChild(this);
109         }
110     }
111 
112     /**
113      * Get viewer manager.
114      *
115      * @return the manager
116      */
117     protected MetisViewerManager getManager() {
118         return theManager;
119     }
120 
121     @Override
122     public MetisViewerEntry getParent() {
123         return theParent;
124     }
125 
126     /**
127      * Get unique name.
128      *
129      * @return the name
130      */
131     public String getUniqueName() {
132         return theUniqueName;
133     }
134 
135     @Override
136     public String getDisplayName() {
137         return theDisplayName;
138     }
139 
140     /**
141      * Get id.
142      *
143      * @return the id
144      */
145     public int getId() {
146         return theId;
147     }
148 
149     @Override
150     public Object getObject() {
151         return theObject;
152     }
153 
154     @Override
155     public String toString() {
156         return theDisplayName;
157     }
158 
159     /**
160      * Get child iterator.
161      *
162      * @return the iterator
163      */
164     public Iterator<MetisViewerEntry> childIterator() {
165         return theChildList == null
166                 ? Collections.emptyIterator()
167                 : theChildList.iterator();
168     }
169 
170     /**
171      * Add child.
172      *
173      * @param pChild the child to add
174      */
175     private void addChild(final MetisViewerEntryImpl pChild) {
176         if (theChildList == null) {
177             theChildList = new ArrayList<>();
178         }
179         theChildList.add(pChild);
180     }
181 
182     @Override
183     public boolean isVisible() {
184         return isVisible;
185     }
186 
187     @Override
188     public void setVisible(final boolean pVisible) {
189         /* If this is a change in status */
190         if (isVisible != pVisible) {
191             /* Change status and report it */
192             isVisible = pVisible;
193             theManager.fireEvent(MetisViewerEvent.VISIBILITY, this);
194         }
195     }
196 
197     @Override
198     public void setFocus() {
199         theManager.setFocus(this);
200     }
201 
202     @Override
203     public void setFocus(final String pName) {
204         /* Loop through the children */
205         for (MetisViewerEntry myEntry : theChildList) {
206             /* If we match the object */
207             if (pName.equals(myEntry.getDisplayName())) {
208                 /* Set the focus and return */
209                 myEntry.setFocus();
210                 return;
211             }
212         }
213     }
214 
215     @Override
216     public void setObject(final Object pObject) {
217         /* Set the new object */
218         setTheObject(pObject);
219 
220         /* Notify regarding the data change */
221         theManager.fireEvent(MetisViewerEvent.VALUE, this);
222     }
223 
224     /**
225      * Set the tree object referred to by the entry.
226      *
227      * @param pObject the new object
228      */
229     public void setTreeObject(final Object pObject) {
230         /* Set the new object */
231         setTheObject(pObject);
232 
233         /* Create child elements if required */
234         if (pObject instanceof MetisFieldItem myItem) {
235             createChildElements(myItem);
236         }
237 
238         /* Notify regarding the data change */
239         theManager.fireEvent(MetisViewerEvent.VALUE, this);
240     }
241 
242     /**
243      * Set the object referred to by the entry.
244      *
245      * @param pObject the new object
246      */
247     private void setTheObject(final Object pObject) {
248         /* Set the new object */
249         theObject = pObject;
250 
251         /* Clear the childList */
252         if (theChildList != null) {
253             theChildList.clear();
254         }
255     }
256 
257     /**
258      * Create child elements.
259      *
260      * @param pItem the item
261      */
262     private void createChildElements(final MetisFieldItem pItem) {
263         /* Loop through the fields */
264         final Iterator<MetisFieldDef> myIterator = pItem.getDataFieldSet().fieldIterator();
265         while (myIterator.hasNext()) {
266             final MetisFieldDef myField = myIterator.next();
267 
268             /* Obtain the value */
269             final Object myValue = myField.getFieldValue(pItem);
270             boolean addChild = false;
271 
272             /* Determine whether to add the child */
273             if (myValue instanceof List) {
274                 addChild = !((List<?>) myValue).isEmpty();
275             } else if (myValue instanceof MetisDataList) {
276                 addChild = !((MetisDataList<?>) myValue).isEmpty();
277             } else if (myValue instanceof Map) {
278                 addChild = !((Map<?, ?>) myValue).isEmpty();
279             } else if (myValue instanceof MetisDataMap) {
280                 addChild = !((MetisDataMap<?, ?>) myValue).isEmpty();
281             }
282 
283             /* If we should add the child */
284             if (addChild) {
285                 /* Create it */
286                 final MetisViewerEntry myChild = theManager.newEntry(this, myField.getFieldId().getId());
287                 myChild.setObject(myValue);
288             }
289         }
290     }
291 
292     @Override
293     public boolean equals(final Object pThat) {
294         /* Handle trivial cases */
295         if (this == pThat) {
296             return true;
297         }
298         if (pThat == null) {
299             return false;
300         }
301 
302         /* Check class */
303         if (!(pThat instanceof MetisViewerEntryImpl myThat)) {
304             return false;
305         }
306 
307         /* Must have same id */
308         return theId == myThat.theId;
309     }
310 
311     @Override
312     public int hashCode() {
313         return theId;
314     }
315 }