View Javadoc
1   package org.opentrafficsim.editor;
2   
3   import javax.swing.JTable;
4   import javax.swing.table.AbstractTableModel;
5   
6   import org.djutils.exceptions.Throw;
7   import org.w3c.dom.Node;
8   
9   import de.javagl.treetable.JTreeTable;
10  
11  /**
12   * Model for a {@code JTable} to display the attributes of a {@code XsdTreeNode}.
13   * <p>
14   * Copyright (c) 2023-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
15   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
16   * </p>
17   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
18   */
19  public class AttributesTableModel extends AbstractTableModel
20  {
21  
22      /** */
23      private static final long serialVersionUID = 20230217L;
24  
25      /** Column names. */
26      private static final String[] COLUMN_NAMES = new String[] {"Property", "Value", "Use", ""};
27  
28      /** Minimum column widths. */
29      private static final int[] MIN_COLUMN_WIDTHS = new int[] {50, 50, 30, 20};
30  
31      /** Preferred column widths. */
32      private static final int[] PREFERRED_COLUMN_WIDTHS = new int[] {400, 400, 30, 20};
33  
34      /** The node of which the attributes are displayed. */
35      private final XsdTreeNode node;
36  
37      /** Tree table, so it can be updated visually when a value has changed. */
38      private final JTreeTable treeTable;
39  
40      /**
41       * Constructor.
42       * @param node node of which the attributes are displayed.
43       * @param treeTable tree table.
44       */
45      public AttributesTableModel(final XsdTreeNode node, final JTreeTable treeTable)
46      {
47          this.node = node;
48          this.treeTable = treeTable;
49      }
50  
51      @Override
52      public int getRowCount()
53      {
54          return this.node == null ? 0 : this.node.attributeCount();
55      }
56  
57      @Override
58      public int getColumnCount()
59      {
60          return COLUMN_NAMES.length;
61      }
62  
63      @Override
64      public String getColumnName(final int columnIndex)
65      {
66          return COLUMN_NAMES[columnIndex];
67      }
68  
69      @Override
70      public Class<?> getColumnClass(final int columnIndex)
71      {
72          return String.class;
73      }
74  
75      @Override
76      public boolean isCellEditable(final int rowIndex, final int columnIndex)
77      {
78          if (this.node.getPathString().startsWith(XsdPaths.DEFINITIONS)
79                  && "xsd:boolean".equals(this.node.getAttributeBaseType(rowIndex)))
80          {
81              return false;
82          }
83          return columnIndex == 1 && !this.node.isInclude();
84      }
85  
86      @Override
87      public Object getValueAt(final int rowIndex, final int columnIndex)
88      {
89          Node attribute = this.node.getAttributeNode(rowIndex);
90          switch (columnIndex)
91          {
92              case 0:
93                  return XsdTreeNodeUtil.separatedName(DocumentReader.getAttribute(attribute, "name"));
94              case 1:
95                  Object value = this.node.getAttributeValue(rowIndex);
96                  return value;
97              case 2:
98                  String use = DocumentReader.getAttribute(attribute, "use");
99                  return use != null && use.equals("required") ? "*" : "";
100             case 3:
101                 return DocumentReader.getAnnotation(attribute, "xsd:documentation", "description") != null ? "i" : null;
102             default:
103                 throw new IndexOutOfBoundsException();
104         }
105     }
106 
107     @Override
108     public void setValueAt(final Object aValue, final int rowIndex, final int columnIndex)
109     {
110         Throw.when(columnIndex != 1, IllegalStateException.class,
111                 "Attribute table model requested to set a value from a column that does not represent the attribute value.");
112         if (aValue == null)
113         {
114             return;
115         }
116         if (this.node == null)
117         {
118             // node was deleted
119             return;
120         }
121         this.node.setAttributeValue(rowIndex, aValue.toString());
122         this.treeTable.updateUI();
123         this.fireTableCellUpdated(rowIndex, columnIndex);
124     }
125 
126     /**
127      * Returns the underlying node for which attributes are shown.
128      * @return underlying node for which attributes are shown.
129      */
130     public XsdTreeNode getNode()
131     {
132         return this.node;
133     }
134 
135     /**
136      * Apply the column widths to a newly created table.
137      * @param attributeTable table.
138      */
139     public static void applyColumnWidth(final JTable attributeTable)
140     {
141         for (int i = 0; i < attributeTable.getColumnCount(); i++)
142         {
143             attributeTable.getColumn(COLUMN_NAMES[i]).setMinWidth(MIN_COLUMN_WIDTHS[i]);
144             attributeTable.getColumn(COLUMN_NAMES[i]).setPreferredWidth(PREFERRED_COLUMN_WIDTHS[i]);
145         }
146     }
147 
148 }