View Javadoc
1   package fr.ifremer.quadrige3.ui.swing.content.widget;
2   
3   /*-
4    * #%L
5    * Quadrige3 Core :: UI Swing Common
6    * %%
7    * Copyright (C) 2017 - 2022 Ifremer
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU Affero General Public License as published by
11   * the Free Software Foundation, either version 3 of the License, or
12   * (at your option) any later version.
13   * 
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Public License for more details.
18   * 
19   * You should have received a copy of the GNU Affero General Public License
20   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21   * #L%
22   */
23  
24  import jaxx.runtime.validator.swing.SwingValidatorMessage;
25  import jaxx.runtime.validator.swing.SwingValidatorMessageTableModel;
26  import jaxx.runtime.validator.swing.SwingValidatorMessageWidget;
27  import jaxx.runtime.validator.swing.SwingValidatorUtil;
28  import org.nuiton.validator.NuitonValidatorScope;
29  
30  import javax.swing.*;
31  import javax.swing.table.DefaultTableCellRenderer;
32  import java.awt.Component;
33  import java.awt.Dimension;
34  import java.util.ArrayList;
35  import java.util.List;
36  
37  import static org.nuiton.i18n.I18n.t;
38  
39  /**
40   * Overridden version of Nuiton SwingValidatorMessageWidget
41   * Better table renderer (Mantis #60386)
42   */
43  public class ValidatorMessageWidget extends SwingValidatorMessageWidget {
44  
45      public ValidatorMessageWidget() {
46          super();
47  
48          // Override table renderer
49          errorTable.setDefaultRenderer(Object.class, new ValidatorMessageTableRenderer());
50  
51      }
52  
53      static class ValidatorMessageTableRenderer extends DefaultTableCellRenderer {
54          private final List<List<Integer>> rowColHeight = new ArrayList<List<Integer>>();
55  
56          @Override
57          public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
58              ImageIcon icon = null;
59              String text = null;
60              String toolTipText = null;
61              boolean shouldWrapText = false;
62  
63              switch (column) {
64                  case 0:
65                      // scope
66                      NuitonValidatorScope scope = (NuitonValidatorScope) value;
67                      icon = SwingValidatorUtil.getIcon(scope);
68                      String label = t(scope.getLabel());
69                      toolTipText = t("validator.scope.tip", label);
70                      break;
71  
72                  case 1:
73                      // field name
74                      text = getFieldName(table, (String) value, row);
75                      toolTipText = t("validator.field.tip", text);
76                      shouldWrapText = true;
77                      break;
78  
79                  case 2:
80                      // message
81                      text = getMessage(table, (String) value, row);
82                      toolTipText = t("validator.message.tip", text);
83                      shouldWrapText = true;
84                      break;
85              }
86  
87              JComponent rendererComponent;
88              if (shouldWrapText) {
89                  JLabel fakeLabel = (JLabel) super.getTableCellRendererComponent(table, "", isSelected, hasFocus, row, column);
90  
91                  JTextArea textArea = new JTextArea();
92                  textArea.setLineWrap(true);
93                  textArea.setWrapStyleWord(true);
94                  textArea.setOpaque(true);
95                  textArea.setText(text);
96                  textArea.setToolTipText(toolTipText);
97                  textArea.setForeground(fakeLabel.getForeground());
98                  textArea.setBackground(fakeLabel.getBackground());
99                  textArea.setFont(fakeLabel.getFont());
100                 textArea.setBorder(fakeLabel.getBorder());
101 
102                 adjustRowHeight(table, row, column, textArea);
103 
104                 rendererComponent = textArea;
105             }
106             else {
107                 JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
108 
109                 label.setText(text);
110                 label.setToolTipText(toolTipText);
111                 label.setIcon(icon);
112                 label.setOpaque(true);
113                 label.setVerticalAlignment(TOP);
114 
115                 rendererComponent = label;
116             }
117 
118             return rendererComponent;
119         }
120 
121         public String getMessage(JTable table, String value, int row) {
122             SwingValidatorMessageTableModel tableModel
123                 = (SwingValidatorMessageTableModel) table.getModel();
124             SwingValidatorMessage model = tableModel.getRow(row);
125             return SwingValidatorUtil.getMessage(model);
126         }
127 
128         public String getFieldName(JTable table, String value, int row) {
129             SwingValidatorMessageTableModel tableModel
130                 = (SwingValidatorMessageTableModel) table.getModel();
131             SwingValidatorMessage model = tableModel.getRow(row);
132             return SwingValidatorUtil.getFieldName(model, value);
133         }
134 
135         /**
136          * Calculate the new preferred height for a given row, and sets the height on the table.
137          */
138         private void adjustRowHeight(JTable table, int row, int column, JComponent component) {
139             //The trick to get this to work properly is to set the width of the column to the
140             //textarea. The reason for this is that getPreferredSize(), without a width tries
141             //to place all the text in one line. By setting the size with the with of the column,
142             //getPreferredSize() returnes the proper height which the row should have in
143             //order to make room for the text.
144             int cWidth = table.getTableHeader().getColumnModel().getColumn(column).getWidth();
145             component.setSize(new Dimension(cWidth, 1000));
146             int prefH = component.getPreferredSize().height;
147             while (rowColHeight.size() <= row) {
148                 rowColHeight.add(new ArrayList<Integer>(column));
149             }
150             List<Integer> colHeights = rowColHeight.get(row);
151             while (colHeights.size() <= column) {
152                 colHeights.add(0);
153             }
154             colHeights.set(column, prefH);
155             int maxH = prefH;
156             for (Integer colHeight : colHeights) {
157                 if (colHeight > maxH) {
158                     maxH = colHeight;
159                 }
160             }
161             if (table.getRowHeight(row) != maxH) {
162                 table.setRowHeight(row, maxH);
163             }
164         }
165     }
166 }