View Javadoc
1   package org.opentrafficsim.editor;
2   
3   import java.rmi.RemoteException;
4   import java.util.Arrays;
5   
6   import javax.swing.SwingUtilities;
7   
8   import org.w3c.dom.Document;
9   
10  import de.javagl.treetable.AbstractTreeTableModel;
11  import de.javagl.treetable.JTreeTable;
12  import de.javagl.treetable.TreeTableModel;
13  
14  /**
15   * Defines the columns in the {@code JTreeTable}. Most functionality is forwarded to the tree with {@code XsdTreeNode}'s.
16   * <p>
17   * Copyright (c) 2023-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
18   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
19   * </p>
20   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
21   */
22  public class XsdTreeTableModel extends AbstractTreeTableModel
23  {
24  
25      /** Column names. */
26      private static final String[] COLUMN_NAMES = new String[] {"Item", "Id", "Value", "#"};
27  
28      /** Index of the tree column. */
29      public static final int TREE_COLUMN = Arrays.asList(COLUMN_NAMES).indexOf("Item");
30  
31      /** Index of the Id column. */
32      public static final int ID_COLUMN = Arrays.asList(COLUMN_NAMES).indexOf("Id");
33  
34      /** Index of the Value column. */
35      public static final int VALUE_COLUMN = Arrays.asList(COLUMN_NAMES).indexOf("Value");
36  
37      /** Minimum column widths. */
38      private static final int[] MIN_COLUMN_WIDTHS = new int[] {100, 50, 50, 30};
39  
40      /** Preferred column widths. */
41      private static final int[] PREFERRED_COLUMN_WIDTHS = new int[] {600, 200, 200, 30};
42  
43      /** Column classes. */
44      private static final Class<?>[] COLUMN_CLASSES =
45              new Class<?>[] {TreeTableModel.class, String.class, String.class, String.class};
46  
47      /** Tree table, so it can be updated visually when a value has changed. */
48      private JTreeTable treeTable;
49  
50      /**
51       * Constructor.
52       * @param document XSD document.
53       * @throws RemoteException when unable to listen for created nodes.
54       */
55      protected XsdTreeTableModel(final Document document) throws RemoteException
56      {
57          super(document == null ? null : new XsdTreeNodeRoot(new Schema(document)));
58      }
59  
60      /**
61       * Sets the tree table.
62       * @param treeTable tree table.
63       */
64      public void setTreeTable(final JTreeTable treeTable)
65      {
66          this.treeTable = treeTable;
67      }
68  
69      @Override
70      public int getColumnCount()
71      {
72          return COLUMN_CLASSES.length;
73      }
74  
75      @Override
76      public String getColumnName(final int column)
77      {
78          return COLUMN_NAMES[column];
79      }
80  
81      @Override
82      public Class<?> getColumnClass(final int column)
83      {
84          return COLUMN_CLASSES[column];
85      }
86  
87      @Override
88      public Object getValueAt(final Object node, final int column)
89      {
90          if (column == TREE_COLUMN)
91          {
92              return node; // required for tree view of column 0
93          }
94          if (column == ID_COLUMN)
95          {
96              if (((XsdTreeNode) node).isIdentifiable())
97              {
98                  return ((XsdTreeNode) node).getId();
99              }
100             return "";
101         }
102         else if (column == VALUE_COLUMN)
103         {
104             if (((XsdTreeNode) node).isEditable())
105             {
106                 return ((XsdTreeNode) node).getValue();
107             }
108             return "";
109         }
110         return occurs(((XsdTreeNode) node).minOccurs(), ((XsdTreeNode) node).maxOccurs());
111     }
112 
113     /**
114      * Creates a string to display minOccurs and maxOccurs.
115      * @param minOccurs minOccurs.
116      * @param maxOccurs maxOccurs.
117      * @return string to display minOccurs and maxOccurs.
118      */
119     public String occurs(final int minOccurs, final int maxOccurs)
120     {
121         if (minOccurs == maxOccurs)
122         {
123             return Integer.toString(minOccurs);
124         }
125         return Integer.valueOf(minOccurs) + ".." + (maxOccurs == -1 ? "∞" : Integer.valueOf(maxOccurs));
126     }
127 
128     @Override
129     public Object getChild(final Object parent, final int index)
130     {
131         return ((XsdTreeNode) parent).getChild(index);
132     }
133 
134     @Override
135     public int getChildCount(final Object parent)
136     {
137         return ((XsdTreeNode) parent).getChildCount();
138     }
139 
140     @Override
141     public boolean isCellEditable(final Object node, final int column)
142     {
143         if (column == TREE_COLUMN)
144         {
145             return true; // required for tree in column 0
146         }
147         XsdTreeNode treeNode = (XsdTreeNode) node;
148         if (column == ID_COLUMN)
149         {
150             return treeNode.isIdentifiable() && !treeNode.isIncluded();
151         }
152         return treeNode.isEditable() && column == VALUE_COLUMN && !treeNode.isIncluded();
153     }
154 
155     @Override
156     public void setValueAt(final Object aValue, final Object node, final int column)
157     {
158         if (column == ID_COLUMN)
159         {
160             ((XsdTreeNode) node).setId(aValue.toString());
161         }
162         else if (column == VALUE_COLUMN)
163         {
164             ((XsdTreeNode) node).setValue(aValue.toString());
165         }
166         // invoking directly results in a NullPointerException when clicking on the table during editing of a value in the table
167         SwingUtilities.invokeLater(() -> this.treeTable.updateUI());
168     }
169 
170     /**
171      * Apply the column widths to a newly created tree table.
172      * @param treeTable tree table.
173      */
174     public static void applyColumnWidth(final JTreeTable treeTable)
175     {
176         for (int i = 0; i < treeTable.getColumnCount(); i++)
177         {
178             treeTable.getColumn(COLUMN_NAMES[i]).setMinWidth(MIN_COLUMN_WIDTHS[i]);
179             treeTable.getColumn(COLUMN_NAMES[i]).setPreferredWidth(PREFERRED_COLUMN_WIDTHS[i]);
180         }
181     }
182 
183 }