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 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      @Override
75      public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected,
76              final boolean hasFocus, final int row, final int column)
77      {
78          XsdTreeNode node = null;
79          if (table.convertColumnIndexToModel(column) == 1)
80          {
81              node = ((AttributesTableModel) table.getModel()).getNode();
82              String baseType = node.getAttributeBaseType(row);
83              if ("xsd:boolean".equals(baseType))
84              {
85                  String message = node.isSelfValid() ? null : node.reportInvalidAttributeValue(row);
86                  if (message != null)
87                  {
88                      this.checkBox.setToolTipText(OtsEditor.limitTooltip(message));
89                      this.checkBox.setBackground(OtsEditor.INVALID_COLOR);
90                  }
91                  else
92                  {
93                      this.checkBox.setToolTipText(null);
94                      if (isSelected)
95                      {
96                          this.checkBox.setBackground(this.selectionColor);
97                      }
98                      else if (node.attributeIsExpression(row))
99                      {
100                         this.checkBox.setBackground(OtsEditor.EXPRESSION_COLOR);
101                     }
102                     else
103                     {
104                         this.checkBox.setBackground(table.getBackground());
105                     }
106                 }
107                 if (value == null || value.toString().isEmpty())
108                 {
109                     String defaultValue = node.getDefaultAttributeValue(row);
110                     this.checkBox.setSelected(defaultValue != null && defaultValue.toString().equalsIgnoreCase("true"));
111                     this.checkBox.setText(" (default)");
112                     this.checkBox.setFont(table.getFont());
113                 }
114                 else
115                 {
116                     this.checkBox.setSelected(value.toString().equalsIgnoreCase("true"));
117                     this.checkBox.setText("");
118                 }
119                 // All xsd:boolean attributes under Ots.Definitions are 'Default' that should be disabled and false by default.
120                 if (node.getPathString().startsWith("Ots.Definitions"))
121                 {
122                     this.checkBox.setEnabled(false);
123                 }
124                 else
125                 {
126                     this.checkBox.setEnabled(true);
127                 }
128                 return this.checkBox;
129             }
130         }
131 
132         boolean showingDefault = false;
133         if (table.convertColumnIndexToModel(column) == 1)
134         {
135             if (value == null || value.toString().isEmpty())
136             {
137                 node = ((AttributesTableModel) table.getModel()).getNode();
138                 String defaultValue = node.getDefaultAttributeValue(row);
139                 showingDefault = defaultValue != null;
140                 setText(showingDefault ? defaultValue : "");
141             }
142             else
143             {
144                 setText(value.toString());
145             }
146         }
147         else if (table.convertColumnIndexToModel(column) < 3)
148         {
149             setText(value == null ? "" : value.toString());
150         }
151         else
152         {
153             setText("");
154         }
155         setFont(table.getFont());
156         table.setGridColor(table.getBackground());
157         setIcon(null);
158         setForeground(showingDefault ? OtsEditor.INACTIVE_COLOR : this.tableForgroundColor);
159         if (table.convertColumnIndexToModel(column) == 1)
160         {
161             String message = node.isSelfValid() ? null : node.reportInvalidAttributeValue(row);
162             if (message != null)
163             {
164                 setToolTipText(OtsEditor.limitTooltip(message));
165                 setBackground(OtsEditor.INVALID_COLOR);
166             }
167             else
168             {
169                 setToolTipText(value == null || value.toString().isEmpty() ? null : value.toString());
170                 if (node.isInclude())
171                 {
172                     setBackground(this.panelBackgroundColor);
173                 }
174                 else if (node.attributeIsExpression(row))
175                 {
176                     setBackground(OtsEditor.EXPRESSION_COLOR);
177                 }
178                 else
179                 {
180                     setBackground(this.tableBackroundColor);
181                 }
182             }
183             setBorder(this.lineBorder);
184         }
185         else
186         {
187             setToolTipText(null);
188             setBorder(EMPTY_BORDER);
189             if (table.convertColumnIndexToModel(column) == 3 && value != null)
190             {
191                 setIcon(this.infoIcon);
192             }
193             if (isSelected)
194             {
195                 setBackground(this.tableSelectionBackgroundColor);
196             }
197             else
198             {
199                 setBackground(table.getBackground());
200             }
201         }
202         if (table.convertColumnIndexToModel(column) > 1)
203         {
204             setHorizontalAlignment(SwingConstants.CENTER);
205         }
206         else
207         {
208             setHorizontalAlignment(SwingConstants.LEFT);
209         }
210         return this;
211     }
212 
213 }