View Javadoc
1   package org.opentrafficsim.editor.extensions.map;
2   
3   import java.util.function.Consumer;
4   
5   import org.djutils.eval.Eval;
6   import org.opentrafficsim.base.OtsRuntimeException;
7   import org.opentrafficsim.editor.EvalWrapper.EvalListener;
8   import org.opentrafficsim.editor.OtsEditor;
9   import org.opentrafficsim.editor.XsdTreeNode;
10  import org.opentrafficsim.xml.bindings.ExpressionAdapter;
11  
12  /**
13   * Part of the map data structure.
14   * <p>
15   * Copyright (c) 2023-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
16   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
17   * </p>
18   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
19   */
20  public abstract class MapData implements EvalListener
21  {
22  
23      /** Map showing all the elements. */
24      private final EditorMap map;
25  
26      /** Tree node. */
27      private final XsdTreeNode node;
28  
29      /** Editor. */
30      private final OtsEditor editor;
31  
32      /**
33       * Constructor.
34       * @param map map.
35       * @param node tree node.
36       * @param editor editor.
37       */
38      public MapData(final EditorMap map, final XsdTreeNode node, final OtsEditor editor)
39      {
40          this.map = map;
41          this.node = node;
42          this.editor = editor;
43          this.editor.addEvalListener(this);
44      }
45  
46      /**
47       * Returns the tree node.
48       * @return tree node.
49       */
50      public XsdTreeNode getNode()
51      {
52          return this.node;
53      }
54  
55      /**
56       * Returns the evaluator for expressions.
57       * @return evaluator for expressions.
58       */
59      public Eval getEval()
60      {
61          return this.editor.getEval();
62      }
63  
64      /**
65       * Destroy this data object, e.g. remove self as listener. Override and call super if subclasses remove their own listeners.
66       * Using weak references for listeners is another option to deal with obsolete listening.
67       */
68      public void destroy()
69      {
70          this.editor.removeEvalListener(this);
71      }
72  
73      /**
74       * Notify the map that the element can be drawn.
75       */
76      void setValid()
77      {
78          this.map.setValid(this);
79      }
80  
81      /**
82       * Notify the map that the element cannot be drawn.
83       */
84      void setInvalid()
85      {
86          this.map.setInvalid(this);
87      }
88  
89      /**
90       * Returns the map.
91       * @return map.
92       */
93      // If public, this will remove the map from the tabbed pane when the inspector wants a renderer for this element, which is
94      // the panel itself. It gets 'reparented' towards the cell in the inspection window.
95      protected EditorMap getMap()
96      {
97          return this.map;
98      }
99  
100     /**
101      * Generic method to set a value based on a changed attribute. If the new value is {@code null}, the setter is invoked to
102      * set a {@code null} value. If the value is an invalid expression, or the value cannot be unmarshalled by the adapter, no
103      * change is made.
104      * @param <T> type of the value to set.
105      * @param setter setter that receives a successfully derived value.
106      * @param adapter adapter.
107      * @param node node that has the attribute, will often be {@code getNode()}.
108      * @param attribute name of the attribute.
109      */
110     protected <T> void setValue(final Consumer<T> setter, final ExpressionAdapter<T, ?> adapter, final XsdTreeNode node,
111             final String attribute)
112     {
113         try
114         {
115             String stringValue = node.getAttributeValue(attribute);
116             if (stringValue == null)
117             {
118                 setter.accept(null);
119                 return;
120             }
121             T value = adapter.unmarshal(stringValue).get(getEval());
122             setter.accept(value);
123         }
124         catch (RuntimeException ex)
125         {
126             setInvalid();
127             // RuntimeException: expression not valid => we should add expression validators baked in to XsdTreeNode
128             // IllegalArgumentException: invalid coordinate value, keep old coordinate
129         }
130         catch (Exception ex)
131         {
132             throw new OtsRuntimeException("Unexpected exception", ex);
133         }
134     }
135 
136 }