blob: 6077b97d5f7ef80095aa2b7cc4723fc5ba4cfa0a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you 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 org.apache.log4j.chainsaw.color;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import org.apache.commons.configuration2.AbstractConfiguration;
import org.apache.log4j.chainsaw.ChainsawConstants;
import org.apache.log4j.chainsaw.ExpressionRuleContext;
import org.apache.log4j.chainsaw.components.logpanel.LogPanel;
import org.apache.log4j.chainsaw.filter.FilterModel;
import org.apache.log4j.chainsaw.helper.SwingHelper;
import org.apache.log4j.chainsaw.icons.ChainsawIcons;
import org.apache.log4j.chainsaw.prefs.SettingsManager;
import org.apache.log4j.rule.ColorRule;
import org.apache.log4j.rule.ExpressionRule;
import org.apache.log4j.rule.Rule;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* Panel which updates a RuleColorizer, allowing the user to build expression-based
* color rules.
* <p>
* TODO: examine ColorPanel/RuleColorizer/LogPanel listeners and interactions
*
* @author Scott Deboy &lt;sdeboy@apache.org&gt;
*/
public class ColorPanel extends JPanel {
private static final String LABEL_DOUBLE_CLICK_TO_EDIT = "Double click to edit";
private static final String LABEL_BROWSE = "Browse...";
private static final String DEFAULT_STATUS = "<html>Double click a rule field to edit the rule</html>";
private static final Logger logger = LogManager.getLogger();
private final FilterModel filterModel;
private final RulesTableModel rulesTableModel;
private final JScrollPane tableScrollPane;
private final JTable rulesTable;
private ActionListener closeListener;
private final JLabel statusBar;
private static final String NO_TAB = "None";
private final DefaultComboBoxModel<String> logPanelColorizersModel;
private final Map<String, RuleColorizer> allLogPanelColorizers;
private final JTable searchTable;
private final DefaultTableModel searchTableModel;
private final Vector<Color> searchDataVectorEntry;
private final RuleColorizer globalColorizer;
private final JTable alternatingColorTable;
private final Vector<Color> alternatingColorDataVectorEntry;
private JCheckBox bypassSearchColorsCheckBox;
private JCheckBox globalRulesCheckbox;
private final LogPanel parentLogPanel;
private JLabel rulesLabel;
private SettingsManager settingsManager;
public ColorPanel(
SettingsManager settingsManager,
final RuleColorizer globalColorizer,
final FilterModel filterModel,
final Map<String, RuleColorizer> allLogPanelColorizers,
final LogPanel parent) {
super(new BorderLayout());
this.settingsManager = settingsManager;
AbstractConfiguration configuration = settingsManager.getGlobalConfiguration();
this.filterModel = filterModel;
this.allLogPanelColorizers = allLogPanelColorizers;
this.globalColorizer = globalColorizer;
this.parentLogPanel = parent;
parentLogPanel.getCurrentRuleColorizer().addPropertyChangeListener("colorrule", evt -> updateColors());
rulesTableModel = new RulesTableModel();
rulesTable = new JTable(rulesTableModel);
rulesTable.setRowHeight(ChainsawConstants.DEFAULT_ROW_HEIGHT);
rulesTable.getColumnModel().getColumn(0).setCellEditor(new RulesTableCellEditor());
searchTableModel = new DefaultTableModel();
searchTable = new JTable(searchTableModel);
searchTable.setRowHeight(ChainsawConstants.DEFAULT_ROW_HEIGHT);
searchTable.setPreferredScrollableViewportSize(new Dimension(30, 30));
DefaultTableModel alternatingColorTableModel = new DefaultTableModel();
alternatingColorTable = new JTable(alternatingColorTableModel);
alternatingColorTable.setRowHeight(ChainsawConstants.DEFAULT_ROW_HEIGHT);
alternatingColorTable.setPreferredScrollableViewportSize(new Dimension(30, 30));
Vector<String> searchColumns = new Vector<>();
searchColumns.add("Background");
searchColumns.add("Foreground");
// searchtable contains only a single-entry vector containing a two-item vector (foreground, background)
Vector<Vector<Color>> searchDataVector = new Vector<>();
searchDataVectorEntry = new Vector<>();
searchDataVectorEntry.add(
configuration.get(Color.class, "searchBackgroundColor", ChainsawConstants.FIND_LOGGER_BACKGROUND));
searchDataVectorEntry.add(
configuration.get(Color.class, "searchForegroundColor", ChainsawConstants.FIND_LOGGER_FOREGROUND));
searchDataVector.add(searchDataVectorEntry);
searchTableModel.setDataVector(searchDataVector, searchColumns);
Vector<Vector<Color>> alternatingColorDataVector = new Vector<>();
alternatingColorDataVectorEntry = new Vector<>();
alternatingColorDataVectorEntry.add(configuration.get(
Color.class, "alternatingColorBackground", ChainsawConstants.COLOR_ODD_ROW_BACKGROUND));
alternatingColorDataVectorEntry.add(configuration.get(
Color.class, "alternatingColorForeground", ChainsawConstants.COLOR_ODD_ROW_FOREGROUND));
alternatingColorDataVector.add(alternatingColorDataVectorEntry);
Vector<String> alternatingColorColumns = new Vector<>();
alternatingColorColumns.add("Background");
alternatingColorColumns.add("Foreground");
alternatingColorTableModel.setDataVector(alternatingColorDataVector, alternatingColorColumns);
rulesTable.setPreferredScrollableViewportSize(new Dimension(525, 200));
tableScrollPane = new JScrollPane(rulesTable);
rulesTable.sizeColumnsToFit(0);
rulesTable.getColumnModel().getColumn(1).setPreferredWidth(80);
rulesTable.getColumnModel().getColumn(2).setPreferredWidth(80);
rulesTable.getColumnModel().getColumn(1).setMaxWidth(80);
rulesTable.getColumnModel().getColumn(2).setMaxWidth(80);
searchTable.sizeColumnsToFit(0);
searchTable.getColumnModel().getColumn(0).setPreferredWidth(80);
searchTable.getColumnModel().getColumn(1).setPreferredWidth(80);
searchTable.getColumnModel().getColumn(0).setMaxWidth(80);
searchTable.getColumnModel().getColumn(1).setMaxWidth(80);
// building color choosers needs to be done on the EDT
SwingHelper.invokeOnEDT(() -> configureSingleEntryColorTable(searchTable));
alternatingColorTable.sizeColumnsToFit(0);
alternatingColorTable.getColumnModel().getColumn(0).setPreferredWidth(80);
alternatingColorTable.getColumnModel().getColumn(1).setPreferredWidth(80);
alternatingColorTable.getColumnModel().getColumn(0).setMaxWidth(80);
alternatingColorTable.getColumnModel().getColumn(1).setMaxWidth(80);
// building color choosers needs to be done on the EDT
SwingHelper.invokeOnEDT(() -> configureSingleEntryColorTable(alternatingColorTable));
configureTable();
statusBar = new JLabel(DEFAULT_STATUS);
JPanel rightPanel = new JPanel(new BorderLayout());
JPanel rightOuterPanel = new JPanel();
rightOuterPanel.setLayout(new BoxLayout(rightOuterPanel, BoxLayout.X_AXIS));
rightOuterPanel.add(Box.createHorizontalStrut(10));
JPanel southPanel = new JPanel();
southPanel.setLayout(new BoxLayout(southPanel, BoxLayout.Y_AXIS));
southPanel.add(Box.createVerticalStrut(5));
southPanel.add(Box.createVerticalStrut(5));
JPanel searchAndAlternatingColorPanel = buildSearchAndAlternatingColorPanel();
JPanel bypassSearchColorsPanel = buildBypassSearchColorsPanel();
bypassSearchColorsCheckBox.setSelected(configuration.getBoolean("bypassSearchColors", false));
JPanel globalLabelPanel = new JPanel();
globalLabelPanel.setLayout(new BoxLayout(globalLabelPanel, BoxLayout.X_AXIS));
JLabel globalLabel = new JLabel("Global colors:");
globalLabelPanel.add(globalLabel);
globalLabelPanel.add(Box.createHorizontalGlue());
southPanel.add(globalLabelPanel);
southPanel.add(searchAndAlternatingColorPanel);
southPanel.add(bypassSearchColorsPanel);
southPanel.add(Box.createVerticalStrut(5));
JPanel closePanel = buildClosePanel();
southPanel.add(closePanel);
JPanel statusPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
statusPanel.add(statusBar);
southPanel.add(statusPanel);
JPanel rulesPanel = buildRulesPanel();
rulesPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
rightPanel.add(rulesPanel, BorderLayout.CENTER);
rightPanel.add(southPanel, BorderLayout.SOUTH);
rightOuterPanel.add(rightPanel);
JPanel topPanel = new JPanel();
topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.X_AXIS));
JLabel selectText = new JLabel("Apply a tab's colors");
topPanel.add(selectText);
topPanel.add(Box.createHorizontalStrut(5));
logPanelColorizersModel = new DefaultComboBoxModel();
final JComboBox loadPanelColorizersComboBox = new JComboBox(logPanelColorizersModel);
loadLogPanelColorizers();
topPanel.add(loadPanelColorizersComboBox);
topPanel.add(Box.createHorizontalStrut(5));
final Action copyRulesAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
rulesTableModel.clear();
Object selectedItem = loadPanelColorizersComboBox.getSelectedItem();
if (selectedItem != null) {
RuleColorizer sourceColorizer = allLogPanelColorizers.get(selectedItem.toString());
RuleColorizer newColorizer = new RuleColorizer();
newColorizer.setRules(sourceColorizer.getRules());
parent.setRuleColorizer(newColorizer);
updateColors();
parentLogPanel
.getCurrentRuleColorizer()
.addPropertyChangeListener("colorrule", evt -> updateColors());
}
}
};
loadPanelColorizersComboBox.addActionListener(e -> {
Object selectedItem = loadPanelColorizersComboBox.getSelectedItem();
if (selectedItem != null) {
String selectedColorizerName = selectedItem.toString();
copyRulesAction.setEnabled(!(NO_TAB.equals(selectedColorizerName)));
}
});
copyRulesAction.putValue(Action.NAME, "Copy color rules");
copyRulesAction.setEnabled(!(NO_TAB.equals(loadPanelColorizersComboBox.getSelectedItem())));
JButton copyRulesButton = new JButton(copyRulesAction);
topPanel.add(copyRulesButton);
add(topPanel, BorderLayout.NORTH);
add(rightOuterPanel, BorderLayout.CENTER);
if (rulesTable.getRowCount() > 0) {
rulesTable.getSelectionModel().setSelectionInterval(0, 0);
}
}
public void loadLogPanelColorizers() {
if (logPanelColorizersModel.getIndexOf(NO_TAB) == -1) {
logPanelColorizersModel.addElement(NO_TAB);
}
RuleColorizer currentLogPanelColorizer = parentLogPanel.getCurrentRuleColorizer();
for (Map.Entry<String, RuleColorizer> entry : allLogPanelColorizers.entrySet()) {
if (!entry.getValue().equals(currentLogPanelColorizer)
&& (logPanelColorizersModel.getIndexOf(entry.getKey()) == -1)) {
logPanelColorizersModel.addElement(entry.getKey());
}
}
AbstractConfiguration configuration = settingsManager.getGlobalConfiguration();
// update search and alternating colors, since they may have changed from another color panel
searchDataVectorEntry.set(
0, configuration.get(Color.class, "searchBackgroundColor", ChainsawConstants.FIND_LOGGER_BACKGROUND));
searchDataVectorEntry.set(
1, configuration.get(Color.class, "searchForegroundColor", ChainsawConstants.FIND_LOGGER_FOREGROUND));
alternatingColorDataVectorEntry.set(
0,
configuration.get(
Color.class, "alternatingColorBackground", ChainsawConstants.COLOR_ODD_ROW_BACKGROUND));
alternatingColorDataVectorEntry.set(
1,
configuration.get(
Color.class, "alternatingColorForeground", ChainsawConstants.COLOR_ODD_ROW_FOREGROUND));
}
public void componentChanged() {
logger.debug(
"Color panel changed. Current colorizer: {} Global colorizer: {}",
parentLogPanel.getCurrentRuleColorizer(),
globalColorizer);
if (globalColorizer == parentLogPanel.getCurrentRuleColorizer()) {
globalRulesCheckbox.setSelected(true);
rulesLabel.setText("Global rules:");
} else {
globalRulesCheckbox.setSelected(false);
rulesLabel.setText("Rules:");
}
loadLogPanelColorizers();
updateColors();
}
public JPanel buildBypassSearchColorsPanel() {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
bypassSearchColorsCheckBox = new JCheckBox("Don't use a search color for matching rows");
panel.add(bypassSearchColorsCheckBox);
return panel;
}
public JPanel buildSearchAndAlternatingColorPanel() {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
JLabel defineSearchColorsLabel = new JLabel("Find colors");
panel.add(defineSearchColorsLabel);
panel.add(Box.createHorizontalStrut(10));
JScrollPane searchPane = new JScrollPane(searchTable);
searchPane.setBorder(BorderFactory.createEmptyBorder());
panel.add(searchPane);
panel.add(Box.createHorizontalStrut(10));
JLabel defineAlternatingColorLabel = new JLabel("Alternating colors");
panel.add(defineAlternatingColorLabel);
panel.add(Box.createHorizontalStrut(10));
JScrollPane alternatingColorPane = new JScrollPane(alternatingColorTable);
alternatingColorPane.setBorder(BorderFactory.createEmptyBorder());
panel.add(alternatingColorPane);
panel.setBorder(BorderFactory.createEtchedBorder());
panel.add(Box.createHorizontalGlue());
return panel;
}
public void updateColors() {
rulesTableModel.clear();
rulesTableModel.addColorRules();
rulesTableModel.fireTableDataChanged();
}
private void configureTable() {
prepareTable(rulesTable, 1, 2);
JTextField textField = new JTextField();
textField.addKeyListener(new ExpressionRuleContext(filterModel, textField));
rulesTable.getColumnModel().getColumn(0).setCellRenderer(new ExpressionTableCellRenderer());
rulesTable.getColumnModel().getColumn(1).setCellRenderer(new ColorTableCellRenderer());
rulesTable.getColumnModel().getColumn(2).setCellRenderer(new ColorTableCellRenderer());
}
private void configureSingleEntryColorTable(JTable thisTable) {
prepareTable(thisTable, 0, 1);
thisTable.getColumnModel().getColumn(0).setCellRenderer(new ColorTableCellRenderer());
thisTable.getColumnModel().getColumn(1).setCellRenderer(new ColorTableCellRenderer());
}
private JTable prepareTable(JTable table, int backgroundEditorPosition, int foregroundEditorPosition) {
table.setToolTipText(LABEL_DOUBLE_CLICK_TO_EDIT);
table.setRowHeight(20);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.setColumnSelectionAllowed(false);
JComboBox background = createColorJComboBox();
JComboBox foreground = createColorJComboBox();
DefaultCellEditor backgroundEditor = new DefaultCellEditor(background);
DefaultCellEditor foregroundEditor = new DefaultCellEditor(foreground);
table.getColumnModel().getColumn(backgroundEditorPosition).setCellEditor(backgroundEditor);
table.getColumnModel().getColumn(foregroundEditorPosition).setCellEditor(foregroundEditor);
background.addItemListener(new ColorItemListener(background));
foreground.addItemListener(new ColorItemListener(foreground));
return table;
}
private JComboBox createColorJComboBox() {
Vector colors = new Vector(RuleColorizer.getDefaultColors());
colors.add(LABEL_BROWSE);
JComboBox comboBox = new JComboBox(colors);
comboBox.setMaximumRowCount(15);
comboBox.setRenderer(new ColorListCellRenderer());
return comboBox;
}
public void setCloseActionListener(ActionListener listener) {
closeListener = listener;
}
public void hidePanel() {
if (closeListener != null) {
closeListener.actionPerformed(null);
}
}
void applyRules(RuleColorizer applyingColorizer) {
rulesTable.getColumnModel().getColumn(0).getCellEditor().stopCellEditing();
((ExpressionTableCellRenderer) rulesTable.getColumnModel().getColumn(0).getCellRenderer())
.setToolTipText(LABEL_DOUBLE_CLICK_TO_EDIT);
statusBar.setText(DEFAULT_STATUS);
applyingColorizer.setRules(rulesTableModel.rules());
}
JPanel buildClosePanel() {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
panel.add(Box.createHorizontalGlue());
JButton applyButton = new JButton(" Apply ");
applyButton.addActionListener(new AbstractAction() {
public void actionPerformed(ActionEvent evt) {
applyRules(parentLogPanel.getCurrentRuleColorizer());
saveSearchColors();
}
});
panel.add(Box.createHorizontalStrut(10));
panel.add(applyButton);
JButton closeButton = new JButton(" Close ");
closeButton.addActionListener(new AbstractAction() {
public void actionPerformed(ActionEvent evt) {
hidePanel();
}
});
panel.add(Box.createHorizontalStrut(10));
panel.add(closeButton);
return panel;
}
private void saveSearchColors() {
Vector thisVector = searchTableModel.getDataVector().get(0);
AbstractConfiguration globalConfig = settingsManager.getGlobalConfiguration();
globalConfig.setProperty("searchBackgroundColor", RuleColorizer.colorToRGBString((Color) thisVector.get(0)));
globalConfig.setProperty("searchForegroundColor", RuleColorizer.colorToRGBString((Color) thisVector.get(1)));
}
JPanel buildUpDownPanel() {
JPanel panel = new JPanel(new BorderLayout());
JPanel innerPanel = new JPanel();
innerPanel.setLayout(new GridLayout(5, 1));
final JButton upButton = new JButton(ChainsawIcons.ICON_UP);
upButton.setToolTipText("Move selected rule up");
final JButton downButton = new JButton(ChainsawIcons.ICON_DOWN);
downButton.setToolTipText("Move selected rule down");
upButton.setEnabled(false);
downButton.setEnabled(false);
rulesTable.getSelectionModel().addListSelectionListener(e -> {
if (!e.getValueIsAdjusting()) {
int index = rulesTable.getSelectionModel().getMaxSelectionIndex();
if (index < 0) {
downButton.setEnabled(false);
upButton.setEnabled(false);
} else if ((index == 0) && (rulesTableModel.getRowCount() == 1)) {
downButton.setEnabled(false);
upButton.setEnabled(false);
} else if ((index == 0) && (rulesTableModel.getRowCount() > 1)) {
downButton.setEnabled(true);
upButton.setEnabled(false);
} else if (index == (rulesTableModel.getRowCount() - 1)) {
downButton.setEnabled(false);
upButton.setEnabled(true);
} else {
downButton.setEnabled(true);
upButton.setEnabled(true);
}
}
});
JPanel upPanel = new JPanel();
upPanel.add(upButton);
JPanel downPanel = new JPanel();
downPanel.add(downButton);
innerPanel.add(new JLabel(""));
innerPanel.add(upPanel);
innerPanel.add(new JLabel(""));
innerPanel.add(downPanel);
panel.add(innerPanel, BorderLayout.CENTER);
upButton.addActionListener(new AbstractAction() {
public void actionPerformed(ActionEvent evt) {
int index = rulesTable.getSelectionModel().getMaxSelectionIndex();
rulesTableModel.moveRowAtIndexUp(index);
}
});
downButton.addActionListener(new AbstractAction() {
public void actionPerformed(ActionEvent evt) {
int index = rulesTable.getSelectionModel().getMaxSelectionIndex();
rulesTableModel.moveRowAtIndexDown(index);
}
});
return panel;
}
JPanel buildRulesPanel() {
JPanel listPanel = new JPanel(new BorderLayout());
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.add(Box.createVerticalStrut(10));
rulesLabel = new JLabel("Rules:");
globalRulesCheckbox = new JCheckBox("Use global rules");
if (globalColorizer == parentLogPanel.getCurrentRuleColorizer()) {
globalRulesCheckbox.setSelected(true);
rulesLabel.setText("Global rules:");
}
globalRulesCheckbox.addActionListener(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
if (globalRulesCheckbox.isSelected()) {
parentLogPanel.setRuleColorizer(globalColorizer);
} else {
parentLogPanel.setRuleColorizer(new RuleColorizer());
}
componentChanged();
parentLogPanel.getCurrentRuleColorizer().addPropertyChangeListener("colorrule", evt -> updateColors());
}
});
panel.add(globalRulesCheckbox);
panel.add(rulesLabel);
JPanel buttonPanel = new JPanel(new GridLayout(0, 2));
buttonPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
JPanel newPanel = new JPanel();
JButton newButton = new JButton(" New ");
newButton.addActionListener(new AbstractAction() {
public void actionPerformed(ActionEvent evt) {
rulesTableModel.addNewRule();
}
});
newPanel.add(newButton);
JPanel deletePanel = new JPanel();
final JButton deleteButton = new JButton(" Delete ");
deleteButton.setEnabled(false);
deleteButton.addActionListener(new AbstractAction() {
public void actionPerformed(ActionEvent evt) {
int index = rulesTable.getSelectionModel().getMaxSelectionIndex();
rulesTableModel.deleteRuleAtIndex(index);
}
});
rulesTable.getSelectionModel().addListSelectionListener(e -> {
if (!e.getValueIsAdjusting()) {
int index = rulesTable.getSelectionModel().getMaxSelectionIndex();
deleteButton.setEnabled(index >= 0);
}
});
deletePanel.add(deleteButton);
buttonPanel.add(newPanel);
buttonPanel.add(deletePanel);
listPanel.add(panel, BorderLayout.NORTH);
JPanel tablePanel = new JPanel(new BorderLayout());
tableScrollPane.setBorder(BorderFactory.createEtchedBorder());
tablePanel.add(tableScrollPane, BorderLayout.CENTER);
tablePanel.add(buildUpDownPanel(), BorderLayout.EAST);
listPanel.add(tablePanel, BorderLayout.CENTER);
listPanel.add(buttonPanel, BorderLayout.SOUTH);
return listPanel;
}
class ColorListCellRenderer extends JLabel implements ListCellRenderer {
ColorListCellRenderer() {
setOpaque(true);
}
public Component getListCellRendererComponent(
JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
setText(" ");
if (isSelected && (index > -1)) {
setBorder(BorderFactory.createLineBorder(Color.black, 2));
} else {
setBorder(BorderFactory.createEmptyBorder());
}
if (value instanceof Color) {
setBackground((Color) value);
} else {
setBackground(Color.white);
if (value != null) {
setText(value.toString());
}
}
return this;
}
}
class ColorItemListener implements ItemListener {
JComboBox box;
JDialog dialog;
JColorChooser colorChooser;
Color lastColor;
ColorItemListener(final JComboBox box) {
this.box = box;
colorChooser = new JColorChooser();
dialog = JColorChooser.createDialog(
box,
"Pick a Color",
true, // modal
colorChooser,
e -> {
box.insertItemAt(colorChooser.getColor(), 0);
box.setSelectedIndex(0);
}, // OK button handler
e -> box.setSelectedItem(lastColor)); // CANCEL button handler
dialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
}
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
if (box.getSelectedItem() instanceof Color) {
box.setBackground((Color) box.getSelectedItem());
repaint();
} else {
box.setBackground(Color.white);
int selectedRow = rulesTable.getSelectedRow();
int selectedColumn = rulesTable.getSelectedColumn();
if (selectedRow != -1 && selectedColumn != -1) {
colorChooser.setColor((Color) rulesTable.getValueAt(selectedRow, selectedColumn));
lastColor = (Color) rulesTable.getValueAt(selectedRow, selectedColumn);
}
dialog.setVisible(true);
}
}
}
}
class ColorTableCellRenderer implements TableCellRenderer {
Border border;
JPanel panel;
ColorTableCellRenderer() {
panel = new JPanel();
panel.setOpaque(true);
}
public Color getCurrentColor() {
return panel.getBackground();
}
public Component getTableCellRendererComponent(
JTable thisTable, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value instanceof Color) {
panel.setBackground((Color) value);
}
if (border == null) {
border = BorderFactory.createMatteBorder(2, 2, 2, 2, rulesTable.getBackground());
}
panel.setBorder(border);
return panel;
}
}
class ExpressionTableCellRenderer implements TableCellRenderer {
JPanel panel = new JPanel();
JLabel expressionLabel = new JLabel();
JLabel iconLabel = new JLabel();
Icon selectedIcon = new SelectedIcon(true);
Icon unselectedIcon = new SelectedIcon(false);
ExpressionTableCellRenderer() {
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
panel.setOpaque(true);
panel.add(iconLabel);
panel.add(Box.createHorizontalStrut(5));
panel.add(expressionLabel);
}
void setToolTipText(String text) {
panel.setToolTipText(text);
}
public Component getTableCellRendererComponent(
JTable thisTable, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value == null) {
return panel;
}
List<ColorRule> rules = rulesTableModel.rules();
ColorRule rule = rules.get(row);
expressionLabel.setText(value.toString());
expressionLabel.setBackground(rule.getBackgroundColor());
panel.setBackground(rule.getBackgroundColor());
expressionLabel.setForeground(rule.getForegroundColor());
panel.setForeground(rule.getForegroundColor());
if (isSelected) {
iconLabel.setIcon(selectedIcon);
} else {
iconLabel.setIcon(unselectedIcon);
}
return panel;
}
}
class SelectedIcon implements Icon {
private final boolean isSelected;
private final int width = 9;
private final int height = 18;
private final int[] xPoints = new int[4];
private final int[] yPoints = new int[4];
public SelectedIcon(boolean isSelected) {
this.isSelected = isSelected;
xPoints[0] = 0;
yPoints[0] = -1;
xPoints[1] = 0;
yPoints[1] = height;
xPoints[2] = width;
yPoints[2] = height / 2;
xPoints[3] = width;
yPoints[3] = (height / 2) - 1;
}
public int getIconHeight() {
return height;
}
public int getIconWidth() {
return width;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
if (isSelected) {
int length = xPoints.length;
int[] newXPoints = new int[length];
int[] newYPoints = new int[length];
for (int i = 0; i < length; i++) {
newXPoints[i] = xPoints[i] + x;
newYPoints[i] = yPoints[i] + y;
}
g.setColor(Color.black);
g.fillPolygon(newXPoints, newYPoints, length);
}
}
}
private class RulesTableModel extends AbstractTableModel {
private final List<ColorRule> colorRules;
RulesTableModel() {
colorRules = new ArrayList<>();
addColorRules();
}
List<ColorRule> rules() {
return colorRules;
}
void clear() {
colorRules.clear();
fireTableDataChanged();
}
void addNewRule() {
Rule expressionRule = ExpressionRule.getRule("msg=='sample'");
ColorRule newRule = new ColorRule("msg=='sample'", expressionRule, Color.WHITE, Color.BLACK);
colorRules.add(newRule);
fireTableRowsInserted(colorRules.size() - 1, colorRules.size() - 1);
}
void deleteRuleAtIndex(int i) {
colorRules.remove(i);
fireTableRowsDeleted(i, i);
}
void moveRowAtIndexDown(int row) {
if (row <= colorRules.size() - 2 && row >= 0) {
Collections.swap(colorRules, row, row + 1);
fireTableRowsUpdated(row, row + 1);
}
}
void moveRowAtIndexUp(int row) {
if (row <= colorRules.size() && row > 0) {
Collections.swap(colorRules, row, row - 1);
fireTableRowsUpdated(row - 1, row);
}
}
void addColorRules() {
colorRules.addAll(parentLogPanel.getCurrentRuleColorizer().getRules());
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (rowIndex >= colorRules.size()) {
return;
}
String expression = colorRules.get(rowIndex).getExpression();
Rule rule = colorRules.get(rowIndex).getRule();
Color backgroundColor = colorRules.get(rowIndex).getBackgroundColor();
Color foregroundColor = colorRules.get(rowIndex).getForegroundColor();
switch (columnIndex) {
case 0:
expression = aValue.toString();
rule = ExpressionRule.getRule(expression);
break;
case 1:
backgroundColor = (Color) aValue;
break;
case 2:
foregroundColor = (Color) aValue;
break;
}
colorRules.set(rowIndex, new ColorRule(expression, rule, backgroundColor, foregroundColor));
// Since the value has been set, resize all of the rows(if required)
rulesTable.setRowHeight(ChainsawConstants.DEFAULT_ROW_HEIGHT);
fireTableRowsUpdated(rowIndex, rowIndex);
}
@Override
public int getRowCount() {
return colorRules.size();
}
@Override
public int getColumnCount() {
return 3;
}
@Override
public Object getValueAt(int row, int col) {
ColorRule rule = colorRules.get(row);
switch (col) {
case 0:
return rule.getExpression();
case 1:
return rule.getBackgroundColor();
case 2:
return rule.getForegroundColor();
default:
return "foo";
}
}
@Override
public String getColumnName(int col) {
switch (col) {
case 0:
return "Expression";
case 1:
return "Background Color";
case 2:
return "Foreground Color";
default:
return "BAD COL NAME";
}
}
@Override
public boolean isCellEditable(int row, int col) {
return true;
}
}
private class RulesTableCellEditor extends AbstractCellEditor implements TableCellEditor {
private final DefaultCellEditor defaultEditor = new DefaultCellEditor(new JTextField());
@Override
public Object getCellEditorValue() {
return defaultEditor.getCellEditorValue();
}
@Override
public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column) {
Component component = defaultEditor.getTableCellEditorComponent(table, value, isSelected, row, column);
table.setRowHeight(row, component.getPreferredSize().height);
return component;
}
@Override
public boolean isCellEditable(EventObject event) {
if (event instanceof MouseEvent) {
MouseEvent mouseEvent = (MouseEvent) event;
return mouseEvent.getClickCount() >= 2;
}
return false;
}
}
}