View Javadoc
1   package org.opentrafficsim.editor.render;
2   
3   import java.awt.Color;
4   import java.awt.Component;
5   import java.util.Optional;
6   
7   import javax.swing.Icon;
8   import javax.swing.JCheckBox;
9   import javax.swing.JLabel;
10  import javax.swing.JTable;
11  import javax.swing.SwingConstants;
12  import javax.swing.UIManager;
13  import javax.swing.border.Border;
14  import javax.swing.border.EmptyBorder;
15  import javax.swing.border.LineBorder;
16  import javax.swing.table.TableCellRenderer;
17  
18  import org.opentrafficsim.editor.AttributesTableModel;
19  import org.opentrafficsim.editor.OtsEditor;
20  import org.opentrafficsim.editor.XsdTreeNode;
21  
22  /**
23   * Renderer for cells in the attributes table. Provides a {@code JCheckBox} for boolean-type attributes (those that cannot be
24   * specified with an expression).
25   * <p>
26   * Copyright (c) 2023-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
27   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
28   * </p>
29   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
30   */
31  public class AttributeCellRenderer extends JLabel implements TableCellRenderer
32  {
33  
34      /** */
35      private static final long serialVersionUID = 20230226L;
36  
37      /** Empty border for re-use. */
38      private static final Border EMPTY_BORDER = new EmptyBorder(0, 0, 0, 0);
39  
40      /** Info icon. */
41      private final Icon infoIcon;
42  
43      /** Checkbox to use for boolean types. */
44      private final JCheckBox checkBox = new JCheckBox();
45  
46      /** Selection color. */
47      private final Color selectionColor = UIManager.getColor("Table.selectionBackground");
48  
49      /** Selection background color. */
50      private final Color tableSelectionBackgroundColor = UIManager.getColor("Table.selectionBackground");
51  
52      /** Foreground color. */
53      private final Color tableForgroundColor = UIManager.getColor("Table.foreground");
54  
55      /** Background color. */
56      private final Color tableBackgroundColor = UIManager.getColor("Table.background");
57  
58      /** Panel color. */
59      private final Color panelBackgroundColor = UIManager.getColor("Panel.background");
60  
61      /** Line border for editable column. */
62      private final Border lineBorder = new LineBorder(UIManager.getColor("Table.gridColor"));
63  
64      /**
65       * Constructor.
66       * @param infoIcon info icon.
67       */
68      public AttributeCellRenderer(final Icon infoIcon)
69      {
70          setOpaque(true);
71          this.infoIcon = infoIcon;
72          this.checkBox.setBorder(EMPTY_BORDER);
73      }
74  
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) == AttributesTableModel.VALUE_COLUMN)
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).orElse(null);
87                  if (message != null)
88                  {
89                      this.checkBox.setToolTipText(OtsEditor.limitTooltip(message));
90                      this.checkBox.setBackground(OtsEditor.getInvalidColor());
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.getExpressionColor());
102                     }
103                     else
104                     {
105                         this.checkBox.setBackground(table.getBackground());
106                     }
107                 }
108                 if (value == null || value.toString().isEmpty())
109                 {
110                     Optional<String> defaultValue = node.getDefaultAttributeValue(row);
111                     this.checkBox.setSelected(defaultValue.isPresent() && 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) == AttributesTableModel.VALUE_COLUMN)
135         {
136             if (value == null || value.toString().isEmpty())
137             {
138                 node = ((AttributesTableModel) table.getModel()).getNode();
139                 Optional<String> defaultValue = node.getDefaultAttributeValue(row);
140                 showingDefault = defaultValue.isPresent();
141                 setText(showingDefault ? defaultValue.get() : "");
142             }
143             else
144             {
145                 setText(value.toString());
146             }
147         }
148         else if (table.convertColumnIndexToModel(column) == AttributesTableModel.DESCRIPTION_COLUMN)
149         {
150             setText("");
151         }
152         else
153         {
154             setText(value == null ? "" : value.toString());
155 
156         }
157         setFont(table.getFont());
158         table.setGridColor(table.getBackground());
159         setIcon(null);
160         setForeground(showingDefault ? OtsEditor.INACTIVE_COLOR : this.tableForgroundColor);
161         if (table.convertColumnIndexToModel(column) == AttributesTableModel.VALUE_COLUMN)
162         {
163             String message = node.isSelfValid() ? null : node.reportInvalidAttributeValue(row).orElse(null);
164             if (message != null)
165             {
166                 setToolTipText(OtsEditor.limitTooltip(message));
167                 setBackground(OtsEditor.getInvalidColor());
168             }
169             else
170             {
171                 setToolTipText(value == null || value.toString().isEmpty() ? null : value.toString());
172                 if (node.isIncluded())
173                 {
174                     setBackground(this.panelBackgroundColor);
175                 }
176                 else if (node.attributeIsExpression(row))
177                 {
178                     setBackground(OtsEditor.getExpressionColor());
179                 }
180                 else
181                 {
182                     setBackground(this.tableBackgroundColor);
183                 }
184             }
185             setBorder(this.lineBorder);
186         }
187         else
188         {
189             setToolTipText(null);
190             setBorder(EMPTY_BORDER);
191             if (table.convertColumnIndexToModel(column) == AttributesTableModel.DESCRIPTION_COLUMN && value != null)
192             {
193                 setIcon(this.infoIcon);
194             }
195             if (isSelected)
196             {
197                 setBackground(this.tableSelectionBackgroundColor);
198             }
199             else
200             {
201                 setBackground(table.getBackground());
202             }
203         }
204         if (table.convertColumnIndexToModel(column) == AttributesTableModel.USE_COLUMN
205                 || table.convertColumnIndexToModel(column) == AttributesTableModel.DESCRIPTION_COLUMN)
206         {
207             setHorizontalAlignment(SwingConstants.CENTER);
208         }
209         else
210         {
211             setHorizontalAlignment(SwingConstants.LEFT);
212         }
213         return this;
214     }
215 
216 }