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 XsdTreeNode; node of which the attributes are displayed.
43       * @param treeTable JTreeTable; tree table.
44       */
45      public AttributesTableModel(final XsdTreeNode node, final JTreeTable treeTable)
46      {
47          this.node = node;
48          this.treeTable = treeTable;
49      }
50  
51      /** {@inheritDoc} */
52      @Override
53      public int getRowCount()
54      {
55          return this.node == null ? 0 : this.node.attributeCount();
56      }
57  
58      /** {@inheritDoc} */
59      @Override
60      public int getColumnCount()
61      {
62          return COLUMN_NAMES.length;
63      }
64  
65      /** {@inheritDoc} */
66      @Override
67      public String getColumnName(final int columnIndex)
68      {
69          return COLUMN_NAMES[columnIndex];
70      }
71  
72      /** {@inheritDoc} */
73      @Override
74      public Class<?> getColumnClass(final int columnIndex)
75      {
76          return String.class;
77      }
78  
79      /** {@inheritDoc} */
80      @Override
81      public boolean isCellEditable(final int rowIndex, final int columnIndex)
82      {
83          if (this.node.getPathString().startsWith(XsdPaths.DEFINITIONS)
84                  && "xsd:boolean".equals(this.node.getAttributeBaseType(rowIndex)))
85          {
86              return false;
87          }
88          return columnIndex == 1 && !this.node.isInclude();
89      }
90  
91      /** {@inheritDoc} */
92      @Override
93      public Object getValueAt(final int rowIndex, final int columnIndex)
94      {
95          Node attribute = this.node.getAttributeNode(rowIndex);
96          switch (columnIndex)
97          {
98              case 0:
99                  return XsdTreeNodeUtil.separatedName(DocumentReader.getAttribute(attribute, "name"));
100             case 1:
101                 Object value = this.node.getAttributeValue(rowIndex);
102                 return value;
103             case 2:
104                 String use = DocumentReader.getAttribute(attribute, "use");
105                 return use != null && use.equals("required") ? "*" : "";
106             case 3:
107                 return DocumentReader.getAnnotation(attribute, "xsd:documentation", "description") != null ? "i" : null;
108             default:
109                 throw new IndexOutOfBoundsException();
110         }
111     }
112 
113     /** {@inheritDoc} */
114     @Override
115     public void setValueAt(final Object aValue, final int rowIndex, final int columnIndex)
116     {
117         Throw.when(columnIndex != 1, IllegalStateException.class,
118                 "Attribute table model requested to set a value from a column that does not represent the attribute value.");
119         if (aValue == null)
120         {
121             return;
122         }
123         if (this.node == null)
124         {
125             // node was deleted
126             return;
127         }
128         this.node.setAttributeValue(rowIndex, aValue.toString());
129         this.treeTable.updateUI();
130         this.fireTableCellUpdated(rowIndex, columnIndex);
131     }
132 
133     /**
134      * Returns the underlying node for which attributes are shown.
135      * @return XsdTreeNode; underlying node for which attributes are shown.
136      */
137     public XsdTreeNode getNode()
138     {
139         return this.node;
140     }
141 
142     /**
143      * Apply the column widths to a newly created table.
144      * @param attributeTable JTable; table.
145      */
146     public static void applyColumnWidth(final JTable attributeTable)
147     {
148         for (int i = 0; i < attributeTable.getColumnCount(); i++)
149         {
150             attributeTable.getColumn(COLUMN_NAMES[i]).setMinWidth(MIN_COLUMN_WIDTHS[i]);
151             attributeTable.getColumn(COLUMN_NAMES[i]).setPreferredWidth(PREFERRED_COLUMN_WIDTHS[i]);
152         }
153     }
154 
155 }