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 try {
136 return cellRendererDefault.getTableCellRendererComponent(
137 table, UiStringUtil.detectUtf8HtmlNoWrap(cellValue), isSelected, hasFocus, row, column
138 );
139 } catch (NullPointerException e) {
140 LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
141 return null;
142 }
143 }
144 );
145 }
146
147 private void initTableScroller() {
148 var scroller = new JScrollPane(this.tableValues);
149 var tableFixedColumn = new FixedColumnTable();
150 tableFixedColumn.fixColumnSize(2, scroller);
151 this.add(scroller, BorderLayout.CENTER);
152 }
153
154 private void initPanelSearch(final TableRowSorter<TableModel> rowSorter) {
155 final var panelSearch = new JPanel(new BorderLayout());
156
157 final JTextField textFilter = new JTextFieldPlaceholder("Find in table");
158 panelSearch.add(textFilter, BorderLayout.CENTER);
159
160 Action actionShowSearchTable = new ActionShowSearch(panelSearch, textFilter);
161 String keySearch = "search";
162 this.tableValues.getActionMap().put(keySearch, actionShowSearchTable);
163 this.tableValues.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_DOWN_MASK), keySearch);
164
165 Action actionCloseSearch = new ActionCloseSearch(textFilter, panelSearch, this);
166 String keyClose = "close";
167 textFilter.getActionMap().put(keyClose, actionCloseSearch);
168 textFilter.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), keyClose);
169
170
171 textFilter.getDocument().addDocumentListener(new DocumentListener() {
172 private void insertUpdateFixed() {
173 String text = textFilter.getText();
174 if (text.trim().isEmpty()) {
175 rowSorter.setRowFilter(null);
176 } else {
177 rowSorter.setRowFilter(RowFilter.regexFilter("(?i)" + Pattern.quote(text)));
178 }
179 }
180 @Override
181 public void insertUpdate(DocumentEvent e) {
182 this.insertUpdateFixed();
183 }
184 @Override
185 public void removeUpdate(DocumentEvent e) {
186 this.insertUpdateFixed();
187 }
188 @Override
189 public void changedUpdate(DocumentEvent e) {
190 throw new UnsupportedOperationException("Not supported yet.");
191 }
192 });
193
194 this.tableValues.setComponentPopupMenu(new JPopupMenuTable(this.tableValues, actionShowSearchTable));
195
196 JButton buttonCloseSearch = new ButtonClose();
197 buttonCloseSearch.addActionListener(actionCloseSearch);
198 panelSearch.add(buttonCloseSearch, BorderLayout.EAST);
199 panelSearch.setVisible(false);
200 this.add(panelSearch, BorderLayout.SOUTH);
201 }
202
203 private void initTabShortcut() {
204 this.tableValues.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
205 KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0),
206 null
207 );
208 this.tableValues.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
209 KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_DOWN_MASK),
210 null
211 );
212
213 Set<AWTKeyStroke> forward = new HashSet<>(
214 this.tableValues.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS)
215 );
216 forward.add(KeyStroke.getKeyStroke("TAB"));
217 this.tableValues.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, forward);
218
219 Set<AWTKeyStroke> backward = new HashSet<>(
220 this.tableValues.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS)
221 );
222 backward.add(KeyStroke.getKeyStroke("shift TAB"));
223 this.tableValues.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, backward);
224 }
225
226
227
228
229 public void selectTable() {
230 this.tableValues.selectAll();
231 }
232
233
234
235
236 public void copyTable() {
237 var actionEvent = new ActionEvent(this.tableValues, ActionEvent.ACTION_PERFORMED, "copy");
238 this.tableValues.getActionMap().get(actionEvent.getActionCommand()).actionPerformed(actionEvent);
239 }
240
241
242
243
244 public JTable getTableValues() {
245 return this.tableValues;
246 }
247 }