View Javadoc
1   package org.opentrafficsim.editor.render;
2   
3   import java.awt.Color;
4   import java.awt.Component;
5   
6   import javax.swing.Icon;
7   import javax.swing.JCheckBox;
8   import javax.swing.JLabel;
9   import javax.swing.JTable;
10  import javax.swing.SwingConstants;
11  import javax.swing.UIManager;
12  import javax.swing.border.Border;
13  import javax.swing.border.EmptyBorder;
14  import javax.swing.border.LineBorder;
15  import javax.swing.table.TableCellRenderer;
16  
17  import org.opentrafficsim.editor.AttributesTableModel;
18  import org.opentrafficsim.editor.OtsEditor;
19  import org.opentrafficsim.editor.XsdTreeNode;
20  
21  /**
22   * Renderer for cells in the attributes table. Provides a {@code JCheckBox} for boolean-type attributes (those that cannot be
23   * specified with an expression).
24   * <p>
25   * Copyright (c) 2023-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
26   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
27   * </p>
28   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
29   */
30  public class AttributeCellRenderer extends JLabel implements TableCellRenderer
31  {
32  
33      /** */
34      private static final long serialVersionUID = 20230226L;
35  
36      /** Empty border for re-use. */
37      private static final Border EMPTY_BORDER = new EmptyBorder(0, 0, 0, 0);
38  
39      /** Info icon. */
40      private final Icon infoIcon;
41  
42      /** Checkbox to use for boolean types. */
43      private final JCheckBox checkBox = new JCheckBox();
44  
45      /** Selection color. */
46      private final Color selectionColor = UIManager.getColor("Table.selectionBackground");
47  
48      /** Selection background color. */
49      private final Color tableSelectionBackgroundColor = UIManager.getColor("Table.selectionBackground");
50  
51      /** Foreground color. */
52      private final Color tableForgroundColor = UIManager.getColor("Table.foreground");
53  
54      /** Background color. */
55      private final Color tableBackroundColor = UIManager.getColor("Table.background");
56  
57      /** Panel color. */
58      private final Color panelBackgroundColor = UIManager.getColor("Panel.background");
59  
60      /** Line border for editable column. */
61      private final Border lineBorder = new LineBorder(UIManager.getColor("Table.gridColor"));
62  
63      /**
64       * Constructor.
65       * @param infoIcon Icon; info icon.
66       */
67      public AttributeCellRenderer(final Icon infoIcon)
68      {
69          setOpaque(true);
70          this.infoIcon = infoIcon;
71          this.checkBox.setBorder(EMPTY_BORDER);
72      }
73  
74      /** {@inheritDoc} */
75      @Override
76      public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected,
77              final boolean hasFocus, final int row, final int column)
78      {
79          XsdTreeNode node = null;
80          if (table.convertColumnIndexToModel(column) == 1)
81          {
82              node = ((AttributesTableModel) table.getModel()).getNode();
83              String baseType = node.getAttributeBaseType(row);
84              if ("xsd:boolean".equals(baseType))
85              {
86                  String message = node.isSelfValid() ? null : node.reportInvalidAttributeValue(row);
87                  if (message != null)
88                  {
89                      this.checkBox.setToolTipText(OtsEditor.limitTooltip(message));
90                      this.checkBox.setBackground(OtsEditor.INVALID_COLOR);
91                  }
92                  else
93                  {
94                      this.checkBox.setToolTipText(null);
95                      if (isSelected)
96                      {
97                          this.checkBox.setBackground(this.selectionColor);
98                      }
99                      else if (node.attributeIsExpression(row))
100                     {
101                         this.checkBox.setBackground(OtsEditor.EXPRESSION_COLOR);
102                     }
103                     else
104                     {
105                         this.checkBox.setBackground(table.getBackground());
106                     }
107                 }
108                 if (value == null || value.toString().isEmpty())
109                 {
110                     String defaultValue = node.getDefaultAttributeValue(row);
111                     this.checkBox.setSelected(defaultValue != null && defaultValue.toString().equalsIgnoreCase("true"));
112                     this.checkBox.setText(" (default)");
113                     this.checkBox.setFont(table.getFont());
114                 }
115                 else
116                 {
117                     this.checkBox.setSelected(value.toString().equalsIgnoreCase("true"));
118                     this.checkBox.setText("");
119                 }
120                 // All xsd:boolean attributes under Ots.Definitions are 'Default' that should be disabled and false by default.
121                 if (node.getPathString().startsWith("Ots.Definitions"))
122                 {
123                     this.checkBox.setEnabled(false);
124                 }
125                 else
126                 {
127                     this.checkBox.setEnabled(true);
128                 }
129                 return this.checkBox;
130             }
131         }
132 
133         boolean showingDefault = false;
134         if (table.convertColumnIndexToModel(column) == 1)
135         {
136             if (value == null || value.toString().isEmpty())
137             {
138                 node = ((AttributesTableModel) table.getModel()).getNode();
139                 String defaultValue = node.getDefaultAttributeValue(row);
140                 showingDefault = defaultValue != null;
141                 setText(showingDefault ? defaultValue : "");
142             }
143             else
144             {
145                 setText(value.toString());
146             }
147         }
148         else if (table.convertColumnIndexToModel(column) < 3)
149         {
150             setText(value == null ? "" : value.toString());
151         }
152         else
153         {
154             setText("");
155         }
156         setFont(table.getFont());
157         table.setGridColor(table.getBackground());
158         setIcon(null);
159         setForeground(showingDefault ? OtsEditor.INACTIVE_COLOR : this.tableForgroundColor);
160         if (table.convertColumnIndexToModel(column) == 1)
161         {
162             String message = node.isSelfValid() ? null : node.reportInvalidAttributeValue(row);
163             if (message != null)
164             {
165                 setToolTipText(OtsEditor.limitTooltip(message));
166                 setBackground(OtsEditor.INVALID_COLOR);
167             }
168             else
169             {
170                 setToolTipText(value == null || value.toString().isEmpty() ? null : value.toString());
171                 if (node.isInclude())
172                 {
173                     setBackground(this.panelBackgroundColor);
174                 }
175                 else if (node.attributeIsExpression(row))
176                 {
177                     setBackground(OtsEditor.EXPRESSION_COLOR);
178                 }
179                 else
180                 {
181                     setBackground(this.tableBackroundColor);
182                 }
183             }
184             setBorder(this.lineBorder);
185         }
186         else
187         {
188             setToolTipText(null);
189             setBorder(EMPTY_BORDER);
190             if (table.convertColumnIndexToModel(column) == 3 && value != null)
191             {
192                 setIcon(this.infoIcon);
193             }
194             if (isSelected)
195             {
196                 setBackground(this.tableSelectionBackgroundColor);
197             }
198             else
199             {
200                 setBackground(table.getBackground());
201             }
202         }
203         if (table.convertColumnIndexToModel(column) > 1)
204         {
205             setHorizontalAlignment(SwingConstants.CENTER);
206         }
207         else
208         {
209             setHorizontalAlignment(SwingConstants.LEFT);
210         }
211         return this;
212     }
213 
214 }