/* * Copyright 2013 Sylvain LAURENT * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ch.sla.jdbcperflogger.console.ui; import static java.awt.event.InputEvent.CTRL_MASK; import static java.awt.event.KeyEvent.VK_BACK_SPACE; import static java.awt.event.KeyEvent.VK_DELETE; import java.awt.Color; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.SystemColor; import java.awt.Toolkit; import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.math.BigDecimal; import java.sql.Timestamp; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.DefaultComboBoxModel; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTabbedPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.ScrollPaneConstants; import javax.swing.border.EtchedBorder; import javax.swing.border.TitledBorder; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.event.UndoableEditEvent; import javax.swing.event.UndoableEditListener; import org.eclipse.jdt.annotation.Nullable; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.SyntaxConstants; import org.fife.ui.rsyntaxtextarea.SyntaxScheme; import org.fife.ui.rsyntaxtextarea.TokenTypes; import org.fife.ui.rtextarea.SearchContext; import org.fife.ui.rtextarea.SearchEngine; import ch.sla.jdbcperflogger.console.db.LogRepositoryConstants; import ch.sla.jdbcperflogger.console.ui.PerfLoggerController.FilterType; import ch.sla.jdbcperflogger.console.ui.PerfLoggerController.GroupBy; /** * @author slaurent * */ @SuppressWarnings("serial") public class PerfLoggerPanel extends JPanel { private static final Map<String, Integer> COLUMNS_WIDTH; static { COLUMNS_WIDTH = new HashMap<>(); COLUMNS_WIDTH.put(LogRepositoryConstants.ID_COLUMN, 0); COLUMNS_WIDTH.put(LogRepositoryConstants.TSTAMP_COLUMN, 150); COLUMNS_WIDTH.put(LogRepositoryConstants.FETCH_TIME_COLUMN, 50); COLUMNS_WIDTH.put(LogRepositoryConstants.EXEC_TIME_COLUMN, 50); COLUMNS_WIDTH.put(LogRepositoryConstants.EXEC_PLUS_RSET_USAGE_TIME, 50); COLUMNS_WIDTH.put(LogRepositoryConstants.STMT_TYPE_COLUMN, 40); COLUMNS_WIDTH.put(LogRepositoryConstants.RAW_SQL_COLUMN, 350); COLUMNS_WIDTH.put(LogRepositoryConstants.FILLED_SQL_COLUMN, 200); COLUMNS_WIDTH.put(LogRepositoryConstants.NB_ROWS_COLUMN, 60); COLUMNS_WIDTH.put(LogRepositoryConstants.THREAD_NAME_COLUMN, 200); COLUMNS_WIDTH.put(LogRepositoryConstants.EXEC_COUNT_COLUMN, 100); COLUMNS_WIDTH.put(LogRepositoryConstants.TOTAL_EXEC_PLUS_RSET_USAGE_TIME_COLUMN, 100); COLUMNS_WIDTH.put(LogRepositoryConstants.TIMEOUT_COLUMN, 70); COLUMNS_WIDTH.put(LogRepositoryConstants.AUTOCOMMIT_COLUMN, 40); COLUMNS_WIDTH.put(LogRepositoryConstants.ERROR_COLUMN, 0); } private JTextField txtFldSqlFilter; private JTextField txtFldMinDuration; CustomTable table; private ResultSetDataModel dataModel; private JComboBox<GroupBy> comboBoxGroupBy; private JComboBox<FilterType> comboBoxFilterType; private JButton btnClose; private JButton btnPause; RSyntaxTextArea txtFieldRawSql; RSyntaxTextArea txtFieldFilledSql; JLabel lblStatus; private StatementTimestampTableCellRenderer stmtTimestampCellRenderer; JTextField connectionUrlField; JTextField connectionCreationDateField; private JTextField sqlClauseField; JTextField connectionPropertiesField; JTextField connectionCreationDurationField; JLabel lblConnectionStatus; public PerfLoggerPanel(final PerfLoggerController perfLoggerController) { dataModel = new ResultSetDataModel(); final GridBagLayout gridBagLayout = new GridBagLayout(); gridBagLayout.columnWidths = new int[] { 36, 0 }; gridBagLayout.rowHeights = new int[] { 30, 316, 29, 0 }; gridBagLayout.columnWeights = new double[] { 1.0, Double.MIN_VALUE }; gridBagLayout.rowWeights = new double[] { 0.0, 1.0, 0.0, Double.MIN_VALUE }; setLayout(gridBagLayout); final JPanel topPanel = new JPanel(); final GridBagConstraints gbc_topPanel = new GridBagConstraints(); gbc_topPanel.fill = GridBagConstraints.BOTH; gbc_topPanel.insets = new Insets(0, 0, 5, 0); gbc_topPanel.gridx = 0; gbc_topPanel.gridy = 0; add(topPanel, gbc_topPanel); final GridBagLayout gbl_topPanel = new GridBagLayout(); gbl_topPanel.columnWidths = new int[] { 51, 0, 0, 0, 0 }; gbl_topPanel.rowHeights = new int[] { 0, 0 }; gbl_topPanel.columnWeights = new double[] { 1.0, 0.0, 0.0, 0.0, Double.MIN_VALUE }; gbl_topPanel.rowWeights = new double[] { 0.0, Double.MIN_VALUE }; topPanel.setLayout(gbl_topPanel); final JPanel filterPanel = new JPanel(); filterPanel.setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null), "Filter", TitledBorder.LEADING, TitledBorder.TOP, null, null)); final GridBagConstraints gbc_filterPanel = new GridBagConstraints(); gbc_filterPanel.fill = GridBagConstraints.HORIZONTAL; gbc_filterPanel.insets = new Insets(0, 0, 0, 5); gbc_filterPanel.gridx = 0; gbc_filterPanel.gridy = 0; topPanel.add(filterPanel, gbc_filterPanel); final GridBagLayout gbl_filterPanel = new GridBagLayout(); gbl_filterPanel.columnWidths = new int[] { 0, 51, 246, 0 }; gbl_filterPanel.rowHeights = new int[] { 30, 0, 0 }; gbl_filterPanel.columnWeights = new double[] { 0.0, 0.0, 1.0, Double.MIN_VALUE }; gbl_filterPanel.rowWeights = new double[] { 0.0, 1.0, Double.MIN_VALUE }; filterPanel.setLayout(gbl_filterPanel); comboBoxFilterType = new JComboBox<>(); comboBoxFilterType .setModel(new DefaultComboBoxModel<>(EnumSet.allOf(FilterType.class).toArray(new FilterType[0]))); comboBoxFilterType.setSelectedItem(FilterType.HIGHLIGHT); comboBoxFilterType.addActionListener(new ActionListener() { @Override public void actionPerformed(@Nullable final ActionEvent e) { final FilterType filterType = comboBoxFilterType.getItemAt(comboBoxFilterType.getSelectedIndex()); perfLoggerController.setFilterType(filterType != null ? filterType : FilterType.HIGHLIGHT); } }); final GridBagConstraints gbc_filterTypeComboBox = new GridBagConstraints(); gbc_filterTypeComboBox.insets = new Insets(0, 0, 5, 5); gbc_filterTypeComboBox.fill = GridBagConstraints.HORIZONTAL; gbc_filterTypeComboBox.gridx = 0; gbc_filterTypeComboBox.gridy = 0; filterPanel.add(comboBoxFilterType, gbc_filterTypeComboBox); final JLabel lblText = new JLabel("Text:"); final GridBagConstraints gbc_lblText = new GridBagConstraints(); gbc_lblText.anchor = GridBagConstraints.BASELINE_TRAILING; gbc_lblText.insets = new Insets(0, 0, 5, 5); gbc_lblText.gridx = 1; gbc_lblText.gridy = 0; filterPanel.add(lblText, gbc_lblText); { txtFldSqlFilter = new JTextField(); final GridBagConstraints gbc_txtFldSqlFilter = new GridBagConstraints(); gbc_txtFldSqlFilter.anchor = GridBagConstraints.BASELINE; gbc_txtFldSqlFilter.fill = GridBagConstraints.HORIZONTAL; gbc_txtFldSqlFilter.insets = new Insets(0, 0, 5, 0); gbc_txtFldSqlFilter.gridx = 2; gbc_txtFldSqlFilter.gridy = 0; filterPanel.add(txtFldSqlFilter, gbc_txtFldSqlFilter); txtFldSqlFilter.setColumns(10); txtFldSqlFilter.getDocument().addUndoableEditListener(new UndoableEditListener() { @Override public void undoableEditHappened(@Nullable final UndoableEditEvent e) { perfLoggerController.setTextFilter(txtFldSqlFilter.getText()); } }); } { final JPanel panel = new JPanel(); final GridBagConstraints gbc_panel = new GridBagConstraints(); gbc_panel.gridwidth = 3; gbc_panel.fill = GridBagConstraints.BOTH; gbc_panel.gridx = 0; gbc_panel.gridy = 1; filterPanel.add(panel, gbc_panel); final GridBagLayout gbl_panel = new GridBagLayout(); gbl_panel.columnWidths = new int[] { 0, 0, 0, 0, 0, 0 }; gbl_panel.rowHeights = new int[] { 0, 0 }; gbl_panel.columnWeights = new double[] { 0.0, 1.0, 0.0, 0.0, 0.0, Double.MIN_VALUE }; gbl_panel.rowWeights = new double[] { 0.0, Double.MIN_VALUE }; panel.setLayout(gbl_panel); final JLabel lblSqlClause = new JLabel("Advanced filter"); final GridBagConstraints gbc_lblSqlClause = new GridBagConstraints(); gbc_lblSqlClause.anchor = GridBagConstraints.EAST; gbc_lblSqlClause.insets = new Insets(0, 0, 0, 5); gbc_lblSqlClause.gridx = 0; gbc_lblSqlClause.gridy = 0; panel.add(lblSqlClause, gbc_lblSqlClause); { sqlClauseField = new JTextField(); sqlClauseField.setToolTipText( "<html>\n<p>Use this field to further filter statements by directly injecting a<br>\nWHERE clause to the SELECT statement used by the console<br>\nagainst its internal H2 database.</p>\n<p>You may use the column names that appear in the list below.<br>\nCaution: times are in nanoseconds in the internal DB<br>\nExamples:</p>\n<ul>\n<li>THREADNAME like 'Execute%'</li>\n<li>CONNECTIONNUMBER=2</li>\n<li>NBROWS>10</li>\n<li>ERROR=1</li>\n</ul>\n</html>"); final GridBagConstraints gbc_sqlClauseField = new GridBagConstraints(); gbc_sqlClauseField.insets = new Insets(0, 0, 0, 5); gbc_sqlClauseField.fill = GridBagConstraints.HORIZONTAL; gbc_sqlClauseField.gridx = 1; gbc_sqlClauseField.gridy = 0; panel.add(sqlClauseField, gbc_sqlClauseField); sqlClauseField.setColumns(10); sqlClauseField.getDocument().addUndoableEditListener(new UndoableEditListener() { @Override public void undoableEditHappened(@Nullable final UndoableEditEvent e) { perfLoggerController.setSqlPassThroughFilter(sqlClauseField.getText()); } }); } { final JLabel lblDurationms = new JLabel("Exec duration (ms) >="); final GridBagConstraints gbc_lblDurationms = new GridBagConstraints(); gbc_lblDurationms.insets = new Insets(0, 0, 0, 5); gbc_lblDurationms.gridx = 2; gbc_lblDurationms.gridy = 0; panel.add(lblDurationms, gbc_lblDurationms); } txtFldMinDuration = new JTextField(); final GridBagConstraints gbc_txtFldMinDuration = new GridBagConstraints(); gbc_txtFldMinDuration.insets = new Insets(0, 0, 0, 5); gbc_txtFldMinDuration.gridx = 3; gbc_txtFldMinDuration.gridy = 0; panel.add(txtFldMinDuration, gbc_txtFldMinDuration); txtFldMinDuration.setColumns(5); final JCheckBox chckbxExcludeCommits = new JCheckBox("Exclude commits"); final GridBagConstraints gbc_chckbxExcludeCommits = new GridBagConstraints(); gbc_chckbxExcludeCommits.gridx = 4; gbc_chckbxExcludeCommits.gridy = 0; panel.add(chckbxExcludeCommits, gbc_chckbxExcludeCommits); chckbxExcludeCommits.addItemListener(new ItemListener() { @Override public void itemStateChanged(final ItemEvent e) { perfLoggerController.setExcludeCommits(chckbxExcludeCommits.isSelected()); } }); txtFldMinDuration.getDocument().addUndoableEditListener(new UndoableEditListener() { @Override public void undoableEditHappened(@Nullable final UndoableEditEvent e) { assert e != null; Long minDurationMs = null; if (txtFldMinDuration.getText().length() > 0) { try { minDurationMs = new BigDecimal(txtFldMinDuration.getText()).longValue(); } catch (final NumberFormatException exc) { e.getEdit().undo(); return; } } perfLoggerController.setMinDurationFilter(minDurationMs); } }); } final JPanel groupByPanel = new JPanel(); groupByPanel.setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null), "Group by", TitledBorder.LEADING, TitledBorder.TOP, null, null)); final GridBagConstraints gbc_groupByPanel = new GridBagConstraints(); gbc_groupByPanel.fill = GridBagConstraints.BOTH; gbc_groupByPanel.insets = new Insets(0, 0, 0, 5); gbc_groupByPanel.gridx = 1; gbc_groupByPanel.gridy = 0; topPanel.add(groupByPanel, gbc_groupByPanel); final GridBagLayout gbl_groupByPanel = new GridBagLayout(); gbl_groupByPanel.columnWidths = new int[] { 0, 0 }; gbl_groupByPanel.rowHeights = new int[] { 0, 0 }; gbl_groupByPanel.columnWeights = new double[] { 0.0, Double.MIN_VALUE }; gbl_groupByPanel.rowWeights = new double[] { 0.0, Double.MIN_VALUE }; groupByPanel.setLayout(gbl_groupByPanel); comboBoxGroupBy = new JComboBox<>(); final GridBagConstraints gbc_comboBoxGroupBy = new GridBagConstraints(); gbc_comboBoxGroupBy.fill = GridBagConstraints.HORIZONTAL; gbc_comboBoxGroupBy.gridx = 0; gbc_comboBoxGroupBy.gridy = 0; groupByPanel.add(comboBoxGroupBy, gbc_comboBoxGroupBy); comboBoxGroupBy.setModel(new DefaultComboBoxModel<>(EnumSet.allOf(GroupBy.class).toArray(new GroupBy[0]))); comboBoxGroupBy.setSelectedIndex(0); comboBoxGroupBy.addActionListener(new ActionListener() { @Override public void actionPerformed(@Nullable final ActionEvent e) { @Nullable final GroupBy groupBy = comboBoxGroupBy.getItemAt(comboBoxGroupBy.getSelectedIndex()); perfLoggerController.setGroupBy(groupBy != null ? groupBy : GroupBy.NONE); } }); btnPause = new JButton(); btnPause.setBorder(null); btnPause.setContentAreaFilled(false); final GridBagConstraints gbc_btnPause = new GridBagConstraints(); gbc_btnPause.insets = new Insets(0, 0, 0, 5); gbc_btnPause.gridx = 2; gbc_btnPause.gridy = 0; topPanel.add(btnPause, gbc_btnPause); btnPause.setBorderPainted(false); btnPause.setIcon(new ImageIcon(PerfLoggerPanel.class.getResource("/icons/32px-Media-playback-pause.png"))); btnPause.addActionListener(new ActionListener() { @Override public void actionPerformed(@Nullable final ActionEvent e) { perfLoggerController.onPause(); } }); final JButton btnClear = new JButton(); btnClear.setBorder(null); btnClear.setBorderPainted(false); btnClear.setContentAreaFilled(false); final GridBagConstraints gbc_btnClear = new GridBagConstraints(); gbc_btnClear.gridx = 3; gbc_btnClear.gridy = 0; topPanel.add(btnClear, gbc_btnClear); btnClear.setIcon(new ImageIcon(PerfLoggerPanel.class.getResource("/icons/32px-Edit-clear.png"))); btnClear.addActionListener(new ActionListener() { @Override public void actionPerformed(@Nullable final ActionEvent e) { perfLoggerController.onClear(); } }); final JSplitPane splitPane = new JSplitPane(); splitPane.setResizeWeight(0.8); splitPane.setOneTouchExpandable(true); splitPane.setBorder(null); splitPane.setContinuousLayout(true); splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT); final JScrollPane logListPanel = new JScrollPane(); logListPanel.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); table = new CustomTable(dataModel); table.setSelectionForeground(SystemColor.textHighlightText); table.setSelectionBackground(SystemColor.textHighlight); table.setDefaultRenderer(Byte.class, new CustomTableCellRenderer()); table.setDefaultRenderer(String.class, new CustomTableCellRenderer()); stmtTimestampCellRenderer = new StatementTimestampTableCellRenderer(); table.setDefaultRenderer(Timestamp.class, stmtTimestampCellRenderer); table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); table.setFillsViewportHeight(true); table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); // table.setAutoCreateRowSorter(true); table.setRowSorter(new CustomTableRowSorter(dataModel)); logListPanel.setViewportView(table); table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(@Nullable final ListSelectionEvent e) { assert e != null; if (!e.getValueIsAdjusting()) { perfLoggerController.onSelectStatement(getSelectedLogId()); } } }); table.addKeyListener(new KeyAdapter() { @Override public void keyReleased(@Nullable final KeyEvent e) { assert e != null; if (e.getKeyCode() == VK_BACK_SPACE || e.getKeyCode() == VK_DELETE) { if (e.getModifiers() == CTRL_MASK) { perfLoggerController.onClear(); } else { final int[] selectedRowsTableIndexes = table.getSelectedRows(); final long[] logIds = new long[selectedRowsTableIndexes.length]; for (int i = 0; i < selectedRowsTableIndexes.length; i++) { logIds[i] = dataModel.getIdAtRow(table.convertRowIndexToModel(selectedRowsTableIndexes[i])); } perfLoggerController.onDeleteSelectedStatements(logIds); } } } }); {// popup menu final JPopupMenu popupMenu = new JPopupMenu(); final JMenuItem deleteItem = new JMenuItem("Append to advanced filter"); deleteItem.addActionListener(new ActionListener() { @Override public void actionPerformed(@Nullable final ActionEvent e) { perfLoggerController.appendFilter(getSelectedColumnName(), getSelectedCellRawValue()); } }); popupMenu.add(deleteItem); table.addMouseListener(new MouseAdapter() { @Override public void mousePressed(@Nullable final MouseEvent e) { assert e != null; handlePotentialRightClick(e); } @Override public void mouseReleased(@Nullable final MouseEvent e) { assert e != null; handlePotentialRightClick(e); } private void handlePotentialRightClick(final MouseEvent e) { if (e.isPopupTrigger()) { final JTable source = (JTable) e.getSource(); final int row = source.rowAtPoint(e.getPoint()); final int column = source.columnAtPoint(e.getPoint()); if (row >= 0) { if (!source.isRowSelected(row) || !source.isColumnSelected(column)) { source.changeSelection(row, column, false, false); } popupMenu.show(e.getComponent(), e.getX(), e.getY()); } } } }); } splitPane.setTopComponent(logListPanel); final JPanel sqlDetailPanel = new JPanel(); sqlDetailPanel.setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null), "SQL detail", TitledBorder.LEADING, TitledBorder.TOP, null, new Color(51, 51, 51))); splitPane.setBottomComponent(sqlDetailPanel); final GridBagLayout gbl_sqlDetailPanel = new GridBagLayout(); gbl_sqlDetailPanel.columnWidths = new int[] { 842, 0 }; gbl_sqlDetailPanel.rowHeights = new int[] { 112, 0 }; gbl_sqlDetailPanel.columnWeights = new double[] { 1.0, Double.MIN_VALUE }; gbl_sqlDetailPanel.rowWeights = new double[] { 1.0, Double.MIN_VALUE }; sqlDetailPanel.setLayout(gbl_sqlDetailPanel); final JTabbedPane tabbedPanelsqlDetails = new JTabbedPane(); // tabbedPanelsqlDetails.setTabPlacement(SwingConstants.LEFT); tabbedPanelsqlDetails.setBorder(null); final GridBagConstraints gbc_tabbedPanelsqlDetails = new GridBagConstraints(); gbc_tabbedPanelsqlDetails.fill = GridBagConstraints.BOTH; gbc_tabbedPanelsqlDetails.gridx = 0; gbc_tabbedPanelsqlDetails.gridy = 0; sqlDetailPanel.add(tabbedPanelsqlDetails, gbc_tabbedPanelsqlDetails); final JPanel panelRawSql = new JPanel(); tabbedPanelsqlDetails.addTab("Raw SQL", panelRawSql); final GridBagLayout gbl_panelRawSql = new GridBagLayout(); gbl_panelRawSql.columnWidths = new int[] { 0, 0, 0 }; gbl_panelRawSql.rowHeights = new int[] { 0, 0 }; gbl_panelRawSql.columnWeights = new double[] { 0.0, 1.0, Double.MIN_VALUE }; gbl_panelRawSql.rowWeights = new double[] { 1.0, Double.MIN_VALUE }; panelRawSql.setLayout(gbl_panelRawSql); final JButton btnCopy1 = new JButton(); btnCopy1.setBorderPainted(false); btnCopy1.setBorder(null); btnCopy1.setContentAreaFilled(false); final GridBagConstraints gbc_btnCopy1 = new GridBagConstraints(); gbc_btnCopy1.insets = new Insets(0, 5, 0, 5); gbc_btnCopy1.gridx = 0; gbc_btnCopy1.gridy = 0; panelRawSql.add(btnCopy1, gbc_btnCopy1); btnCopy1.setIcon(new ImageIcon(PerfLoggerPanel.class.getResource("/icons/32px-Edit-copy_purple.png"))); btnCopy1.setToolTipText("Copy the SQL statement unmodified (potentiall with '?' for bind variables"); btnCopy1.addActionListener(new ActionListener() { @Override public void actionPerformed(@Nullable final ActionEvent e) { final StringSelection stringSelection = new StringSelection(txtFieldRawSql.getText()); Toolkit.getDefaultToolkit().getSystemClipboard().setContents(stringSelection, stringSelection); } }); final JScrollPane scrollPaneRawSql = new JScrollPane(); final GridBagConstraints gbc_scrollPaneRawSql = new GridBagConstraints(); gbc_scrollPaneRawSql.fill = GridBagConstraints.BOTH; gbc_scrollPaneRawSql.gridx = 1; gbc_scrollPaneRawSql.gridy = 0; panelRawSql.add(scrollPaneRawSql, gbc_scrollPaneRawSql); txtFieldRawSql = new RSyntaxTextArea(); scrollPaneRawSql.setViewportView(txtFieldRawSql); applySqlSyntaxColoring(txtFieldRawSql); txtFieldRawSql.setOpaque(false); txtFieldRawSql.setEditable(false); txtFieldRawSql.setLineWrap(true); final JPanel panelFilledSql = new JPanel(); tabbedPanelsqlDetails.addTab("FilledSQL", panelFilledSql); final GridBagLayout gbl_panelFilledSql = new GridBagLayout(); gbl_panelFilledSql.columnWidths = new int[] { 0, 0, 0 }; gbl_panelFilledSql.rowHeights = new int[] { 0, 0 }; gbl_panelFilledSql.columnWeights = new double[] { 0.0, 1.0, Double.MIN_VALUE }; gbl_panelFilledSql.rowWeights = new double[] { 1.0, Double.MIN_VALUE }; panelFilledSql.setLayout(gbl_panelFilledSql); final JButton btnCopy2 = new JButton(); btnCopy2.setBorder(null); btnCopy2.setBorderPainted(false); btnCopy2.setContentAreaFilled(false); final GridBagConstraints gbc_btnCopy2 = new GridBagConstraints(); gbc_btnCopy2.insets = new Insets(0, 5, 0, 5); gbc_btnCopy2.gridx = 0; gbc_btnCopy2.gridy = 0; panelFilledSql.add(btnCopy2, gbc_btnCopy2); btnCopy2.setIcon(new ImageIcon(PerfLoggerPanel.class.getResource("/icons/32px-Edit-copy_purple.png"))); btnCopy2.setToolTipText( "Copy the SQL statement to the clipboard, with the bind variables replaced by their actual value"); final JScrollPane scrollPaneFilledSql = new JScrollPane(); final GridBagConstraints gbc_scrollPaneFilledSql = new GridBagConstraints(); gbc_scrollPaneFilledSql.fill = GridBagConstraints.BOTH; gbc_scrollPaneFilledSql.gridx = 1; gbc_scrollPaneFilledSql.gridy = 0; panelFilledSql.add(scrollPaneFilledSql, gbc_scrollPaneFilledSql); txtFieldFilledSql = new RSyntaxTextArea(); scrollPaneFilledSql.setViewportView(txtFieldFilledSql); applySqlSyntaxColoring(txtFieldFilledSql); txtFieldFilledSql.setOpaque(false); txtFieldFilledSql.setEditable(false); txtFieldFilledSql.setLineWrap(true); final JPanel panelConnectionInfo = new JPanel(); tabbedPanelsqlDetails.addTab("Connection", null, panelConnectionInfo, null); panelConnectionInfo.setBorder(new TitledBorder( new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null), "Connection info", TitledBorder.LEADING, TitledBorder.TOP, null, new Color(51, 51, 51)), "Connection info", TitledBorder.LEADING, TitledBorder.TOP, null, new Color(51, 51, 51))); final GridBagLayout gbl_panelConnectionInfo = new GridBagLayout(); gbl_panelConnectionInfo.columnWidths = new int[] { 0, 0, 0, 0, 0 }; gbl_panelConnectionInfo.rowHeights = new int[] { 0, 0, 0, 0 }; gbl_panelConnectionInfo.columnWeights = new double[] { 0.0, 0.0, 0.0, 1.0, Double.MIN_VALUE }; gbl_panelConnectionInfo.rowWeights = new double[] { 0.0, 0.0, 0.0, Double.MIN_VALUE }; panelConnectionInfo.setLayout(gbl_panelConnectionInfo); final JLabel lblConnectionUrl = new JLabel("URL:"); final GridBagConstraints gbc_lblConnectionUrl = new GridBagConstraints(); gbc_lblConnectionUrl.anchor = GridBagConstraints.EAST; gbc_lblConnectionUrl.insets = new Insets(0, 0, 5, 5); gbc_lblConnectionUrl.gridx = 0; gbc_lblConnectionUrl.gridy = 0; panelConnectionInfo.add(lblConnectionUrl, gbc_lblConnectionUrl); connectionUrlField = new JTextField(); final GridBagConstraints gbc_connectionUrlField = new GridBagConstraints(); gbc_connectionUrlField.gridwidth = 3; gbc_connectionUrlField.fill = GridBagConstraints.HORIZONTAL; gbc_connectionUrlField.insets = new Insets(0, 0, 5, 0); gbc_connectionUrlField.gridx = 1; gbc_connectionUrlField.gridy = 0; panelConnectionInfo.add(connectionUrlField, gbc_connectionUrlField); connectionUrlField.setColumns(20); final JLabel lblCreated = new JLabel("Created:"); final GridBagConstraints gbc_lblCreated = new GridBagConstraints(); gbc_lblCreated.anchor = GridBagConstraints.EAST; gbc_lblCreated.insets = new Insets(0, 0, 5, 5); gbc_lblCreated.gridx = 0; gbc_lblCreated.gridy = 1; panelConnectionInfo.add(lblCreated, gbc_lblCreated); connectionCreationDateField = new JTextField(); final GridBagConstraints gbc_connectionCreationDateField = new GridBagConstraints(); gbc_connectionCreationDateField.fill = GridBagConstraints.HORIZONTAL; gbc_connectionCreationDateField.insets = new Insets(0, 0, 5, 5); gbc_connectionCreationDateField.gridx = 1; gbc_connectionCreationDateField.gridy = 1; panelConnectionInfo.add(connectionCreationDateField, gbc_connectionCreationDateField); connectionCreationDateField.setColumns(15); final JLabel lblCreationDuration = new JLabel("Creation duration (ms):"); final GridBagConstraints gbc_lblCreationDuration = new GridBagConstraints(); gbc_lblCreationDuration.anchor = GridBagConstraints.EAST; gbc_lblCreationDuration.insets = new Insets(0, 0, 5, 5); gbc_lblCreationDuration.gridx = 2; gbc_lblCreationDuration.gridy = 1; panelConnectionInfo.add(lblCreationDuration, gbc_lblCreationDuration); connectionCreationDurationField = new JTextField(); final GridBagConstraints gbc_creationDurationField = new GridBagConstraints(); gbc_creationDurationField.insets = new Insets(0, 0, 5, 0); gbc_creationDurationField.fill = GridBagConstraints.HORIZONTAL; gbc_creationDurationField.gridx = 3; gbc_creationDurationField.gridy = 1; panelConnectionInfo.add(connectionCreationDurationField, gbc_creationDurationField); connectionCreationDurationField.setColumns(10); final JLabel lblConectionProperties = new JLabel("Properties:"); final GridBagConstraints gbc_lblConectionProperties = new GridBagConstraints(); gbc_lblConectionProperties.anchor = GridBagConstraints.EAST; gbc_lblConectionProperties.insets = new Insets(0, 0, 0, 5); gbc_lblConectionProperties.gridx = 0; gbc_lblConectionProperties.gridy = 2; panelConnectionInfo.add(lblConectionProperties, gbc_lblConectionProperties); lblConectionProperties.setToolTipText("(Password property removed)"); connectionPropertiesField = new JTextField(); final GridBagConstraints gbc_connectionPropertiesField = new GridBagConstraints(); gbc_connectionPropertiesField.fill = GridBagConstraints.HORIZONTAL; gbc_connectionPropertiesField.gridwidth = 3; gbc_connectionPropertiesField.gridx = 1; gbc_connectionPropertiesField.gridy = 2; panelConnectionInfo.add(connectionPropertiesField, gbc_connectionPropertiesField); connectionPropertiesField.setColumns(10); btnCopy2.addActionListener(new ActionListener() { @Override public void actionPerformed(@Nullable final ActionEvent e) { final StringSelection stringSelection = new StringSelection(txtFieldFilledSql.getText()); Toolkit.getDefaultToolkit().getSystemClipboard().setContents(stringSelection, stringSelection); } }); final GridBagConstraints gbc_splitPane = new GridBagConstraints(); gbc_splitPane.fill = GridBagConstraints.BOTH; gbc_splitPane.insets = new Insets(0, 0, 5, 0); gbc_splitPane.gridx = 0; gbc_splitPane.gridy = 1; add(splitPane, gbc_splitPane); final JPanel bottomPanel = new JPanel(); final GridBagConstraints gbc_bottomPanel = new GridBagConstraints(); gbc_bottomPanel.anchor = GridBagConstraints.NORTH; gbc_bottomPanel.fill = GridBagConstraints.HORIZONTAL; gbc_bottomPanel.gridx = 0; gbc_bottomPanel.gridy = 2; add(bottomPanel, gbc_bottomPanel); final GridBagLayout gbl_bottomPanel = new GridBagLayout(); gbl_bottomPanel.columnWidths = new int[] { 0, 507, 125, 125, 79, 0 }; gbl_bottomPanel.rowHeights = new int[] { 29, 0 }; gbl_bottomPanel.columnWeights = new double[] { 0.0, 1.0, 0.0, 0.0, 0.0, Double.MIN_VALUE }; gbl_bottomPanel.rowWeights = new double[] { 0.0, Double.MIN_VALUE }; bottomPanel.setLayout(gbl_bottomPanel); btnClose = new JButton("Close"); btnClose.addActionListener(new ActionListener() { @Override public void actionPerformed(@Nullable final ActionEvent e) { perfLoggerController.onClose(); } }); final JButton btnExportCsv = new JButton("Export CSV..."); btnExportCsv.setToolTipText("Export all statements to a CSV file"); btnExportCsv.addActionListener(new ActionListener() { @Override public void actionPerformed(@Nullable final ActionEvent e) { perfLoggerController.onExportCsv(); } }); final JButton btnExportSql = new JButton("Export SQL..."); btnExportSql.setToolTipText("Export all statements as a sql script"); btnExportSql.addActionListener(new ActionListener() { @Override public void actionPerformed(@Nullable final ActionEvent e) { perfLoggerController.onExportSql(); } }); lblConnectionStatus = new JLabel(""); final GridBagConstraints gbc_lblConnectionStatus = new GridBagConstraints(); gbc_lblConnectionStatus.insets = new Insets(0, 0, 0, 5); gbc_lblConnectionStatus.gridx = 0; gbc_lblConnectionStatus.gridy = 0; bottomPanel.add(lblConnectionStatus, gbc_lblConnectionStatus); lblStatus = new JLabel(" "); final GridBagConstraints gbc_lblStatus = new GridBagConstraints(); gbc_lblStatus.anchor = GridBagConstraints.BASELINE; gbc_lblStatus.fill = GridBagConstraints.HORIZONTAL; gbc_lblStatus.insets = new Insets(0, 0, 0, 5); gbc_lblStatus.gridx = 1; gbc_lblStatus.gridy = 0; bottomPanel.add(lblStatus, gbc_lblStatus); final GridBagConstraints gbc_btnExportSql = new GridBagConstraints(); gbc_btnExportSql.anchor = GridBagConstraints.BASELINE_LEADING; gbc_btnExportSql.insets = new Insets(0, 0, 0, 5); gbc_btnExportSql.gridx = 2; gbc_btnExportSql.gridy = 0; bottomPanel.add(btnExportSql, gbc_btnExportSql); final GridBagConstraints gbc_btnExportCsv = new GridBagConstraints(); gbc_btnExportCsv.anchor = GridBagConstraints.BASELINE_LEADING; gbc_btnExportCsv.insets = new Insets(0, 0, 0, 5); gbc_btnExportCsv.gridx = 3; gbc_btnExportCsv.gridy = 0; bottomPanel.add(btnExportCsv, gbc_btnExportCsv); final GridBagConstraints gbc_btnClose = new GridBagConstraints(); gbc_btnClose.anchor = GridBagConstraints.BASELINE_LEADING; gbc_btnClose.gridx = 4; gbc_btnClose.gridy = 0; bottomPanel.add(btnClose, gbc_btnClose); } private void applySqlSyntaxColoring(final RSyntaxTextArea txtArea) { txtArea.setCurrentLineHighlightColor(Color.WHITE); txtArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_SQL); final SyntaxScheme scheme = txtArea.getSyntaxScheme(); scheme.getStyle(TokenTypes.LITERAL_CHAR).background = Color.CYAN; scheme.getStyle(TokenTypes.LITERAL_NUMBER_DECIMAL_INT).background = Color.YELLOW; // scheme.getStyle(TokenTypes.LITERAL_NUMBER_FLOAT).background = Color.YELLOW; } void setCloseEnable(final boolean enabled) { btnClose.setEnabled(enabled); if (enabled) { btnClose.setToolTipText(""); } else { btnClose.setToolTipText("Server connection cannot be closed, only GUI-initiated connections can be closed"); } } void setData(final List<Object[]> rows, final List<String> columnNames, final List<Class<?>> columnTypes, final boolean tableStructureChanged) { final int selectedRow = table.getSelectedRow(); int modelRowIndex = -1; if (selectedRow >= 0) { modelRowIndex = table.convertRowIndexToModel(selectedRow); } dataModel.setNewData(rows, columnNames, columnTypes); if (tableStructureChanged) { for (int i = 0; i < dataModel.getColumnCount(); i++) { final Integer width = COLUMNS_WIDTH.get(dataModel.getColumnName(i)); if (width != null) { if (width == 0) { table.getColumnModel().getColumn(i).setMinWidth(0); table.getColumnModel().getColumn(i).setMaxWidth(0); } else { table.getColumnModel().getColumn(i).setPreferredWidth(width.intValue()); } } } } else if (selectedRow >= 0 && selectedRow < rows.size() && modelRowIndex < rows.size()) { final int newSelectedRowIndex = table.convertRowIndexToView(modelRowIndex); table.setRowSelectionInterval(newSelectedRowIndex, newSelectedRowIndex); } } void setPaused(final boolean paused) { if (paused) { btnPause.setIcon(new ImageIcon(PerfLoggerPanel.class.getResource("/icons/32px-Media-record.png"))); } else { btnPause.setIcon(new ImageIcon(PerfLoggerPanel.class.getResource("/icons/32px-Media-playback-pause.png"))); } } void setDeltaTimestampBaseMillis(final long deltaTimestampBaseMillis) { stmtTimestampCellRenderer.setDeltaTimestampBaseMillis(deltaTimestampBaseMillis); if (dataModel.getRowCount() > 0) { dataModel.fireTableRowsUpdated(0, dataModel.getRowCount() - 1); } } @Nullable Long getSelectedLogId() { final ListSelectionModel lsm = table.getSelectionModel(); if (lsm.getMinSelectionIndex() >= 0) { return dataModel.getIdAtRow(table.convertRowIndexToModel(lsm.getMinSelectionIndex())); } return null; } String getSelectedColumnName() { return dataModel.getColumnName(table.convertColumnIndexToModel(table.getSelectedColumn())); } @Nullable Object getSelectedCellRawValue() { return dataModel.getRawValueAt(table.convertRowIndexToModel(table.getSelectedRow()), table.convertColumnIndexToModel(table.getSelectedColumn())); } void setAdvancedFilter(final @Nullable String filter) { sqlClauseField.setText(filter); } public void setTxtToHighlight(@Nullable final String txtToHighlight) { final SearchContext searchContext = new SearchContext(txtToHighlight); searchContext.setMarkAll(true); SearchEngine.markAll(txtFieldRawSql, searchContext); SearchEngine.markAll(txtFieldFilledSql, searchContext); } }