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