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