1
2
3
4
5
6
7
8
9
10
11 package com.jsql.view.swing.table;
12
13 import com.jsql.util.LogLevelUtil;
14 import com.jsql.view.swing.popupmenu.JPopupMenuTable;
15 import com.jsql.view.swing.text.JTextFieldPlaceholder;
16 import com.jsql.view.swing.util.UiStringUtil;
17 import org.apache.commons.lang3.StringUtils;
18 import org.apache.logging.log4j.LogManager;
19 import org.apache.logging.log4j.Logger;
20
21 import javax.swing.*;
22 import javax.swing.event.DocumentEvent;
23 import javax.swing.event.DocumentListener;
24 import javax.swing.table.DefaultTableCellRenderer;
25 import javax.swing.table.TableCellRenderer;
26 import javax.swing.table.TableModel;
27 import javax.swing.table.TableRowSorter;
28 import java.awt.*;
29 import java.awt.event.*;
30 import java.util.Comparator;
31 import java.util.HashSet;
32 import java.util.Set;
33 import java.util.regex.Pattern;
34
35
36
37
38
39 public class PanelTable extends JPanel {
40
41
42
43
44 private static final Logger LOGGER = LogManager.getRootLogger();
45
46
47
48
49 private final JTable tableValues;
50
51
52
53
54
55
56
57 public PanelTable(String[][] data, String[] columnNames) {
58 super(new BorderLayout());
59
60 this.tableValues = new JTable(data, columnNames) {
61 @Override
62 public boolean isCellEditable(int row, int column) {
63 return false;
64 }
65 };
66 this.tableValues.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
67 this.tableValues.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
68 this.tableValues.setColumnSelectionAllowed(true);
69 this.tableValues.setRowHeight(20);
70 this.tableValues.setRowSelectionAllowed(true);
71 this.tableValues.setCellSelectionEnabled(true);
72
73 this.initRenderer();
74
75 this.tableValues.getTableHeader().setReorderingAllowed(false);
76
77 this.initMouseEvent();
78 this.initTabShortcut();
79
80 var columnAdjuster = new AdjusterTableColumn(this.tableValues);
81 columnAdjuster.adjustColumns();
82
83 final TableRowSorter<TableModel> rowSorter = new TableRowSorter<>(this.tableValues.getModel());
84 this.tableValues.setRowSorter(rowSorter);
85 this.initTableScroller();
86 this.initPanelSearch(rowSorter);
87
88 Comparator<Object> comparatorNumeric = new ComparatorColumn<>();
89 for (var i = 0 ; i < this.tableValues.getColumnCount() ; i++) {
90 rowSorter.setComparator(i, comparatorNumeric);
91 }
92 }
93
94 private void initMouseEvent() {
95 this.tableValues.setDragEnabled(true);
96 this.tableValues.addMouseListener(new MouseAdapter() {
97 @Override
98 public void mousePressed(MouseEvent e) {
99 PanelTable.this.tableValues.requestFocusInWindow();
100 if (SwingUtilities.isRightMouseButton(e)) {
101
102
103 var p = e.getPoint();
104 var rowNumber = PanelTable.this.tableValues.rowAtPoint(p);
105 var colNumber = PanelTable.this.tableValues.columnAtPoint(p);
106 DefaultListSelectionModel modelRow = (DefaultListSelectionModel) PanelTable.this.tableValues.getSelectionModel();
107 DefaultListSelectionModel modelColumn = (DefaultListSelectionModel) PanelTable.this.tableValues.getColumnModel().getSelectionModel();
108 modelRow.moveLeadSelectionIndex(rowNumber);
109 modelColumn.moveLeadSelectionIndex(colNumber);
110 }
111 }
112 });
113 }
114
115 private void initRenderer() {
116 final TableCellRenderer cellRendererHeader = this.tableValues.getTableHeader().getDefaultRenderer();
117 this.tableValues.getTableHeader().setDefaultRenderer(
118 (JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) -> cellRendererHeader.getTableCellRendererComponent(
119 table,
120 UiStringUtil.detectUtf8HtmlNoWrap(StringUtils.SPACE + value + StringUtils.SPACE),
121 isSelected,
122 hasFocus,
123 row,
124 column
125 )
126 );
127
128 final var cellRendererDefault = new DefaultTableCellRenderer();
129 this.tableValues.setDefaultRenderer(
130 this.tableValues.getColumnClass(2),
131 (JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) -> {
132
133 String cellValue = value != null ? value.toString() : StringUtils.EMPTY;
134
135
136 try {
137 return cellRendererDefault.getTableCellRendererComponent(
138 table, UiStringUtil.detectUtf8HtmlNoWrap(cellValue), isSelected, hasFocus, row, column
139 );
140 } catch (IllegalArgumentException | NullPointerException e) {
141 LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
142 return null;
143 }
144 }
145 );
146 }
147
148 private void initTableScroller() {
149 var scroller = new JScrollPane(this.tableValues);
150 var tableFixedColumn = new FixedColumnTable();
151 tableFixedColumn.fixColumnSize(2, scroller);
152 this.add(scroller, BorderLayout.CENTER);
153 }
154
155 private void initPanelSearch(final TableRowSorter<TableModel> rowSorter) {
156 final var panelSearch = new JPanel(new BorderLayout());
157
158 final JTextField textFilter = new JTextFieldPlaceholder("Find in table");
159 panelSearch.add(textFilter, BorderLayout.CENTER);
160
161 Action actionShowSearchTable = new ActionShowSearch(panelSearch, textFilter);
162 String keySearch = "search";
163 this.tableValues.getActionMap().put(keySearch, actionShowSearchTable);
164 this.tableValues.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_DOWN_MASK), keySearch);
165
166 Action actionCloseSearch = new ActionCloseSearch(textFilter, panelSearch, this);
167 String keyClose = "close";
168 textFilter.getActionMap().put(keyClose, actionCloseSearch);
169 textFilter.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), keyClose);
170
171
172 textFilter.getDocument().addDocumentListener(new DocumentListener() {
173 private void insertUpdateFixed() {
174 String text = textFilter.getText();
175 if (text.trim().isEmpty()) {
176 rowSorter.setRowFilter(null);
177 } else {
178 rowSorter.setRowFilter(RowFilter.regexFilter("(?i)" + Pattern.quote(text)));
179 }
180 }
181 @Override
182 public void insertUpdate(DocumentEvent e) {
183 this.insertUpdateFixed();
184 }
185 @Override
186 public void removeUpdate(DocumentEvent e) {
187 this.insertUpdateFixed();
188 }
189 @Override
190 public void changedUpdate(DocumentEvent e) {
191 throw new UnsupportedOperationException("Not supported yet.");
192 }
193 });
194
195 this.tableValues.setComponentPopupMenu(new JPopupMenuTable(this.tableValues, actionShowSearchTable));
196
197 JButton buttonCloseSearch = new ButtonClose();
198 buttonCloseSearch.addActionListener(actionCloseSearch);
199 panelSearch.add(buttonCloseSearch, BorderLayout.EAST);
200 panelSearch.setVisible(false);
201 this.add(panelSearch, BorderLayout.SOUTH);
202 }
203
204 private void initTabShortcut() {
205 this.tableValues.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
206 KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0),
207 null
208 );
209 this.tableValues.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
210 KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_DOWN_MASK),
211 null
212 );
213
214 Set<AWTKeyStroke> forward = new HashSet<>(
215 this.tableValues.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS)
216 );
217 forward.add(KeyStroke.getKeyStroke("TAB"));
218 this.tableValues.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, forward);
219
220 Set<AWTKeyStroke> backward = new HashSet<>(
221 this.tableValues.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS)
222 );
223 backward.add(KeyStroke.getKeyStroke("shift TAB"));
224 this.tableValues.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, backward);
225 }
226
227
228
229
230 public void selectTable() {
231 this.tableValues.selectAll();
232 }
233
234
235
236
237 public void copyTable() {
238 var actionEvent = new ActionEvent(this.tableValues, ActionEvent.ACTION_PERFORMED, "copy");
239 this.tableValues.getActionMap().get(actionEvent.getActionCommand()).actionPerformed(actionEvent);
240 }
241
242
243
244
245 public JTable getTableValues() {
246 return this.tableValues;
247 }
248 }