View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  package org.apache.log4j.chainsaw.color;
    19
    20  import java.awt.BorderLayout;
    21  import java.awt.Color;
    22  import java.awt.Component;
    23  import java.awt.Dimension;
    24  import java.awt.FlowLayout;
    25  import java.awt.Graphics;
    26  import java.awt.GridLayout;
    27  import java.awt.event.ActionEvent;
    28  import java.awt.event.ActionListener;
    29  import java.awt.event.ItemEvent;
    30  import java.awt.event.ItemListener;
    31  import java.beans.PropertyChangeEvent;
    32  import java.beans.PropertyChangeListener;
    33  import java.util.ArrayList;
    34  import java.util.HashMap;
    35  import java.util.Iterator;
    36  import java.util.List;
    37  import java.util.Map;
    38  import java.util.Vector;
    39
    40  import javax.swing.AbstractAction;
    41  import javax.swing.Action;
    42  import javax.swing.BorderFactory;
    43  import javax.swing.Box;
    44  import javax.swing.BoxLayout;
    45  import javax.swing.DefaultCellEditor;
    46  import javax.swing.DefaultComboBoxModel;
    47  import javax.swing.Icon;
    48  import javax.swing.JButton;
    49  import javax.swing.JCheckBox;
    50  import javax.swing.JColorChooser;
    51  import javax.swing.JComboBox;
    52  import javax.swing.JDialog;
    53  import javax.swing.JLabel;
    54  import javax.swing.JList;
    55  import javax.swing.JPanel;
    56  import javax.swing.JScrollPane;
    57  import javax.swing.JTable;
    58  import javax.swing.JTextField;
    59  import javax.swing.ListCellRenderer;
    60  import javax.swing.ListSelectionModel;
    61  import javax.swing.WindowConstants;
    62  import javax.swing.border.Border;
    63  import javax.swing.event.ListSelectionEvent;
    64  import javax.swing.event.ListSelectionListener;
    65  import javax.swing.table.DefaultTableModel;
    66  import javax.swing.table.TableCellRenderer;
    67
    68  import org.apache.log4j.chainsaw.ApplicationPreferenceModel;
    69  import org.apache.log4j.chainsaw.ChainsawConstants;
    70  import org.apache.log4j.chainsaw.ExpressionRuleContext;
    71  import org.apache.log4j.chainsaw.filter.FilterModel;
    72  import org.apache.log4j.chainsaw.helper.SwingHelper;
    73  import org.apache.log4j.chainsaw.icons.ChainsawIcons;
    74  import org.apache.log4j.rule.ColorRule;
    75  import org.apache.log4j.rule.ExpressionRule;
    76  import org.apache.log4j.rule.Rule;
    77
    78
    79  /**
    80   * Panel which updates a RuleColorizer, allowing the user to build expression-based
    81   * color rules.
    82   *
    83   * TODO: examine ColorPanel/RuleColorizer/LogPanel listeners and interactions
    84   *
    85   * @author Scott Deboy &lt;sdeboy@apache.org&gt;
    86   */
    87  public class ColorPanel extends JPanel
    88  {
    89    private static final String DEFAULT_STATUS = "<html>Double click a rule field to edit the rule</html>";
    90    private final String currentRuleSet = "Default";
    91
    92    private RuleColorizer colorizer;
    93    private JPanel rulesPanel;
    94    private FilterModel filterModel;
    95    private DefaultTableModel tableModel;
    96    private JScrollPane tableScrollPane;
    97    private JTable table;
    98    private ActionListener closeListener;
    99    private JLabel statusBar;
    100   private Vector columns;
    101   private final String noTab = "None";
    102   private DefaultComboBoxModel logPanelColorizersModel;
    103   private Map allLogPanelColorizers;
    104   private RuleColorizer currentLogPanelColorizer;
    105   private JTable searchTable;
    106   private DefaultTableModel searchTableModel;
    107   private Vector searchColumns;
    108   private Vector searchDataVector;
    109   private Vector searchDataVectorEntry;
    110
    111   private JTable alternatingColorTable;
    112   private DefaultTableModel alternatingColorTableModel;
    113   private Vector alternatingColorColumns;
    114   private Vector alternatingColorDataVector;
    115   private Vector alternatingColorDataVectorEntry;
    116   private ApplicationPreferenceModel applicationPreferenceModel;
    117   private JCheckBox bypassSearchColorsCheckBox;
    118
    119   public ColorPanel(final RuleColorizer currentLogPanelColorizer, final FilterModel filterModel,
    120                       final Map allLogPanelColorizers, final ApplicationPreferenceModel applicationPreferenceModel) {
    121     super(new BorderLayout());
    122
    123     this.currentLogPanelColorizer = currentLogPanelColorizer;
    124     this.colorizer = currentLogPanelColorizer;
    125     this.filterModel = filterModel;
    126     this.allLogPanelColorizers = allLogPanelColorizers;
    127     this.applicationPreferenceModel = applicationPreferenceModel;
    128
    129     currentLogPanelColorizer.addPropertyChangeListener(
    130     	      "colorrule",
    131     	      new PropertyChangeListener() {
    132     	        public void propertyChange(PropertyChangeEvent evt) {
    133     	        	updateColors();
    134     	        }
    135     	      });
    136
    137     tableModel = new DefaultTableModel();
    138     table = new JTable(tableModel);
    139     table.setRowHeight(ChainsawConstants.DEFAULT_ROW_HEIGHT);
    140
    141     searchTableModel = new DefaultTableModel();
    142     searchTable = new JTable(searchTableModel);
    143     searchTable.setRowHeight(ChainsawConstants.DEFAULT_ROW_HEIGHT);
    144     searchTable.setPreferredScrollableViewportSize(new Dimension(30, 30));
    145
    146     alternatingColorTableModel = new DefaultTableModel();
    147     alternatingColorTable = new JTable(alternatingColorTableModel);
    148     alternatingColorTable.setRowHeight(ChainsawConstants.DEFAULT_ROW_HEIGHT);
    149     alternatingColorTable.setPreferredScrollableViewportSize(new Dimension(30, 30));
    150
    151     columns = new Vector();
    152     columns.add("Expression");
    153     columns.add("Background");
    154     columns.add("Foreground");
    155
    156     searchColumns = new Vector();
    157     searchColumns.add("Background");
    158     searchColumns.add("Foreground");
    159
    160     alternatingColorColumns = new Vector();
    161     alternatingColorColumns.add("Background");
    162     alternatingColorColumns.add("Foreground");
    163
    164     //searchtable contains only a single-entry vector containing a two-item vector (foreground, background)
    165     searchDataVector = new Vector();
    166     searchDataVectorEntry = new Vector();
    167     searchDataVectorEntry.add(applicationPreferenceModel.getSearchBackgroundColor());
    168     searchDataVectorEntry.add(applicationPreferenceModel.getSearchForegroundColor());
    169     searchDataVector.add(searchDataVectorEntry);
    170     searchTableModel.setDataVector(searchDataVector, searchColumns);
    171
    172     alternatingColorDataVector = new Vector();
    173     alternatingColorDataVectorEntry = new Vector();
    174     alternatingColorDataVectorEntry.add(applicationPreferenceModel.getAlternatingColorBackgroundColor());
    175     alternatingColorDataVectorEntry.add(applicationPreferenceModel.getAlternatingColorForegroundColor());
    176     alternatingColorDataVector.add(alternatingColorDataVectorEntry);
    177     alternatingColorTableModel.setDataVector(alternatingColorDataVector, alternatingColorColumns);
    178
    179     table.setPreferredScrollableViewportSize(new Dimension(525, 200));
    180     tableScrollPane = new JScrollPane(table);
    181
    182     Vector data = getColorizerVector();
    183     tableModel.setDataVector(data, columns);
    184
    185     table.sizeColumnsToFit(0);
    186     table.getColumnModel().getColumn(1).setPreferredWidth(80);
    187     table.getColumnModel().getColumn(2).setPreferredWidth(80);
    188     table.getColumnModel().getColumn(1).setMaxWidth(80);
    189     table.getColumnModel().getColumn(2).setMaxWidth(80);
    190
    191     searchTable.sizeColumnsToFit(0);
    192     searchTable.getColumnModel().getColumn(0).setPreferredWidth(80);
    193     searchTable.getColumnModel().getColumn(1).setPreferredWidth(80);
    194     searchTable.getColumnModel().getColumn(0).setMaxWidth(80);
    195     searchTable.getColumnModel().getColumn(1).setMaxWidth(80);
    196     //building color choosers needs to be done on the EDT
    197     SwingHelper.invokeOnEDT(new Runnable() {
    198       public void run() {
    199         configureSingleEntryColorTable(searchTable);
    200       }
    201     });
    202
    203     alternatingColorTable.sizeColumnsToFit(0);
    204     alternatingColorTable.getColumnModel().getColumn(0).setPreferredWidth(80);
    205     alternatingColorTable.getColumnModel().getColumn(1).setPreferredWidth(80);
    206     alternatingColorTable.getColumnModel().getColumn(0).setMaxWidth(80);
    207     alternatingColorTable.getColumnModel().getColumn(1).setMaxWidth(80);
    208     //building color choosers needs to be done on the EDT
    209     SwingHelper.invokeOnEDT(new Runnable() {
    210       public void run() {
    211         configureSingleEntryColorTable(alternatingColorTable);
    212       }
    213     });
    214
    215     configureTable();
    216
    217     statusBar = new JLabel(DEFAULT_STATUS);
    218
    219     rulesPanel = buildRulesPanel();
    220     rulesPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
    221
    222     JPanel rightPanel = new JPanel(new BorderLayout());
    223
    224     JPanel rightOuterPanel = new JPanel();
    225     rightOuterPanel.setLayout(
    226       new BoxLayout(rightOuterPanel, BoxLayout.X_AXIS));
    227     rightOuterPanel.add(Box.createHorizontalStrut(10));
    228
    229     JPanel southPanel = new JPanel();
    230     southPanel.setLayout(new BoxLayout(southPanel, BoxLayout.Y_AXIS));
    231     southPanel.add(Box.createVerticalStrut(5));
    232     southPanel.add(Box.createVerticalStrut(5));
    233     JPanel searchAndAlternatingColorPanel = buildSearchAndAlternatingColorPanel();
    234     JPanel bypassSearchColorsPanel = buildBypassSearchColorsPanel();
    235     bypassSearchColorsCheckBox.setSelected(applicationPreferenceModel.isBypassSearchColors());
    236
    237     JPanel globalLabelPanel = new JPanel();
    238     globalLabelPanel.setLayout(new BoxLayout(globalLabelPanel, BoxLayout.X_AXIS));
    239     JLabel globalLabel = new JLabel("Global colors:");
    240     globalLabelPanel.add(globalLabel);
    241     globalLabelPanel.add(Box.createHorizontalGlue());
    242     southPanel.add(globalLabelPanel);
    243     southPanel.add(searchAndAlternatingColorPanel);
    244     southPanel.add(bypassSearchColorsPanel);
    245     southPanel.add(Box.createVerticalStrut(5));
    246     JPanel closePanel = buildClosePanel();
    247     southPanel.add(closePanel);
    248
    249     JPanel statusPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
    250     statusPanel.add(statusBar);
    251     southPanel.add(statusPanel);
    252     rightPanel.add(rulesPanel, BorderLayout.CENTER);
    253     rightPanel.add(southPanel, BorderLayout.SOUTH);
    254     rightOuterPanel.add(rightPanel);
    255
    256     JPanel topPanel = new JPanel();
    257     topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.X_AXIS));
    258
    259     JLabel selectText = new JLabel("Apply a tab's colors");
    260     topPanel.add(selectText);
    261     topPanel.add(Box.createHorizontalStrut(5));
    262
    263     logPanelColorizersModel = new DefaultComboBoxModel();
    264     final JComboBox loadPanelColorizersComboBox = new JComboBox(logPanelColorizersModel);
    265     loadLogPanelColorizers();
    266
    267     topPanel.add(loadPanelColorizersComboBox);
    268
    269     topPanel.add(Box.createHorizontalStrut(5));
    270     final Action copyRulesAction = new AbstractAction() {
    271         public void actionPerformed(ActionEvent e)
    272           {
    273               tableModel.getDataVector().clear();
    274               Object selectedItem = loadPanelColorizersComboBox.getSelectedItem();
    275               if (selectedItem != null) {
    276                 RuleColorizer sourceColorizer = (RuleColorizer) allLogPanelColorizers.get(selectedItem.toString());
    277                 colorizer.setRules(sourceColorizer.getRules());
    278                 updateColors();
    279               }
    280           }
    281       };
    282
    283       loadPanelColorizersComboBox.addActionListener(new ActionListener() {
    284           public void actionPerformed(ActionEvent e) {
    285               Object selectedItem = loadPanelColorizersComboBox.getSelectedItem();
    286               if (selectedItem != null) {
    287                 String selectedColorizerName = selectedItem.toString();
    288                 copyRulesAction.setEnabled(!(noTab.equals(selectedColorizerName)));
    289               }
    290           }
    291       });
    292
    293     copyRulesAction.putValue(Action.NAME, "Copy color rules");
    294     copyRulesAction.setEnabled(!(noTab.equals(loadPanelColorizersComboBox.getSelectedItem())));
    295
    296     JButton copyRulesButton = new JButton(copyRulesAction);
    297     topPanel.add(copyRulesButton);
    298
    299     add(topPanel, BorderLayout.NORTH);
    300     add(rightOuterPanel, BorderLayout.CENTER);
    301     if (table.getRowCount() > 0) {
    302         table.getSelectionModel().setSelectionInterval(0, 0);
    303     }
    304   }
    305
    306   public void loadLogPanelColorizers() {
    307       if (logPanelColorizersModel.getIndexOf(noTab) == -1) {
    308         logPanelColorizersModel.addElement(noTab);
    309       }
    310       for (Iterator iter = allLogPanelColorizers.entrySet().iterator();iter.hasNext();) {
    311           Map.Entry entry = (Map.Entry)iter.next();
    312           if (!entry.getValue().equals(currentLogPanelColorizer) && (logPanelColorizersModel.getIndexOf(entry.getKey()) == -1)) {
    313               logPanelColorizersModel.addElement(entry.getKey());
    314           }
    315       }
    316       //update search and alternating colors, since they may have changed from another color panel
    317       searchDataVectorEntry.set(0, applicationPreferenceModel.getSearchBackgroundColor());
    318       searchDataVectorEntry.set(1, applicationPreferenceModel.getSearchForegroundColor());
    319       alternatingColorDataVectorEntry.set(0, applicationPreferenceModel.getAlternatingColorBackgroundColor());
    320       alternatingColorDataVectorEntry.set(1, applicationPreferenceModel.getAlternatingColorForegroundColor());
    321   }
    322
    323   public JPanel buildBypassSearchColorsPanel() {
    324     JPanel panel = new JPanel();
    325     panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    326
    327     bypassSearchColorsCheckBox = new JCheckBox("Don't use a search color for matching rows");
    328     panel.add(bypassSearchColorsCheckBox);
    329     return panel;
    330   }
    331
    332   public JPanel buildSearchAndAlternatingColorPanel() {
    333       JPanel panel = new JPanel();
    334       panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    335
    336       JLabel defineSearchColorsLabel = new JLabel("Find colors");
    337
    338       panel.add(defineSearchColorsLabel);
    339
    340       panel.add(Box.createHorizontalStrut(10));
    341       JScrollPane searchPane = new JScrollPane(searchTable);
    342       searchPane.setBorder(BorderFactory.createEmptyBorder());
    343       panel.add(searchPane);
    344
    345       panel.add(Box.createHorizontalStrut(10));
    346       JLabel defineAlternatingColorLabel = new JLabel("Alternating colors");
    347
    348       panel.add(defineAlternatingColorLabel);
    349
    350       panel.add(Box.createHorizontalStrut(10));
    351       JScrollPane alternatingColorPane = new JScrollPane(alternatingColorTable);
    352       alternatingColorPane.setBorder(BorderFactory.createEmptyBorder());
    353
    354       panel.add(alternatingColorPane);
    355       panel.setBorder(BorderFactory.createEtchedBorder());
    356       panel.add(Box.createHorizontalGlue());
    357       return panel;
    358   }
    359
    360   public void updateColors() {
    361     tableModel.getDataVector().clear();
    362     tableModel.getDataVector().addAll(getColorizerVector());
    363     tableModel.fireTableDataChanged();
    364   }
    365
    366   private Vector getColorizerVector() {
    367       Vector data = new Vector();
    368       Map map = colorizer.getRules();
    369       Iterator iter = map.entrySet().iterator();
    370       while (iter.hasNext()) {
    371         Map.Entry entry = (Map.Entry)iter.next();
    372         //update ruleset list
    373         if (entry.getKey().equals(currentRuleSet)) {
    374             Iterator iter2 = ((List)entry.getValue()).iterator();
    375
    376             while (iter2.hasNext()) {
    377                 ColorRule rule = (ColorRule)iter2.next();
    378                 Vector v = new Vector();
    379                 v.add(rule.getExpression());
    380                 v.add(rule.getBackgroundColor());
    381                 v.add(rule.getForegroundColor());
    382                 data.add(v);
    383             }
    384          }
    385       }
    386       return data;
    387   }
    388
    389   private void configureTable() {
    390     table.setToolTipText("Double click to edit");
    391     table.setRowHeight(20);
    392     table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    393     table.setColumnSelectionAllowed(false);
    394
    395     Vector backgroundColors = colorizer.getDefaultColors();
    396     Vector foregroundColors = colorizer.getDefaultColors();
    397     backgroundColors.add("Browse...");
    398     foregroundColors.add("Browse...");
    399
    400     JComboBox background = new JComboBox(backgroundColors);
    401     background.setMaximumRowCount(15);
    402     background.setRenderer(new ColorListCellRenderer());
    403
    404     JComboBox foreground = new JComboBox(foregroundColors);
    405     foreground.setMaximumRowCount(15);
    406     foreground.setRenderer(new ColorListCellRenderer());
    407
    408     DefaultCellEditor backgroundEditor = new DefaultCellEditor(background);
    409     DefaultCellEditor foregroundEditor = new DefaultCellEditor(foreground);
    410     JTextField textField = new JTextField();
    411     textField.addKeyListener(
    412       new ExpressionRuleContext(filterModel, textField));
    413     table.getColumnModel().getColumn(0).setCellEditor(
    414       new DefaultCellEditor(textField));
    415     table.getColumnModel().getColumn(1).setCellEditor(backgroundEditor);
    416     table.getColumnModel().getColumn(2).setCellEditor(foregroundEditor);
    417
    418     background.addItemListener(new ColorItemListener(background));
    419     foreground.addItemListener(new ColorItemListener(foreground));
    420
    421     table.getColumnModel().getColumn(0).setCellRenderer(
    422       new ExpressionTableCellRenderer());
    423     table.getColumnModel().getColumn(1).setCellRenderer(
    424       new ColorTableCellRenderer());
    425     table.getColumnModel().getColumn(2).setCellRenderer(
    426       new ColorTableCellRenderer());
    427   }
    428
    429   private void configureSingleEntryColorTable(JTable thisTable) {
    430       thisTable.setToolTipText("Double click to edit");
    431       thisTable.setRowHeight(20);
    432       thisTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    433       thisTable.setColumnSelectionAllowed(false);
    434
    435       Vector backgroundColors = colorizer.getDefaultColors();
    436       Vector foregroundColors = colorizer.getDefaultColors();
    437       backgroundColors.add("Browse...");
    438       foregroundColors.add("Browse...");
    439
    440       JComboBox background = new JComboBox(backgroundColors);
    441       background.setMaximumRowCount(15);
    442       background.setRenderer(new ColorListCellRenderer());
    443
    444       JComboBox foreground = new JComboBox(foregroundColors);
    445       foreground.setMaximumRowCount(15);
    446       foreground.setRenderer(new ColorListCellRenderer());
    447
    448       DefaultCellEditor backgroundEditor = new DefaultCellEditor(background);
    449       DefaultCellEditor foregroundEditor = new DefaultCellEditor(foreground);
    450       thisTable.getColumnModel().getColumn(0).setCellEditor(backgroundEditor);
    451       thisTable.getColumnModel().getColumn(1).setCellEditor(foregroundEditor);
    452
    453       background.addItemListener(new ColorItemListener(background));
    454       foreground.addItemListener(new ColorItemListener(foreground));
    455
    456       thisTable.getColumnModel().getColumn(0).setCellRenderer(
    457         new ColorTableCellRenderer());
    458       thisTable.getColumnModel().getColumn(1).setCellRenderer(
    459         new ColorTableCellRenderer());
    460   }
    461
    462   public void setCloseActionListener(ActionListener listener) {
    463     closeListener = listener;
    464   }
    465
    466   public void hidePanel() {
    467     if (closeListener != null) {
    468       closeListener.actionPerformed(null);
    469     }
    470   }
    471
    472   void applyRules(String ruleSet, RuleColorizer applyingColorizer) {
    473     table.getColumnModel().getColumn(0).getCellEditor().stopCellEditing();
    474
    475     List list = new ArrayList();
    476     Vector vector = tableModel.getDataVector();
    477     StringBuffer result = new StringBuffer();
    478
    479     for (int i = 0; i < vector.size(); i++) {
    480       Vector v = (Vector) vector.elementAt(i);
    481
    482       try {
    483         Rule expressionRule = ExpressionRule.getRule((String) v.elementAt(0));
    484         Color background = getBackground();
    485         Color foreground = getForeground();
    486
    487         if (v.elementAt(1) instanceof Color) {
    488           background = (Color) v.elementAt(1);
    489         }
    490
    491         if (v.elementAt(2) instanceof Color) {
    492           foreground = (Color) v.elementAt(2);
    493         }
    494
    495         ColorRule r = new ColorRule((String)v.elementAt(0), expressionRule, background, foreground);
    496         list.add(r);
    497       } catch (IllegalArgumentException iae) {
    498         if (!result.toString().equals("")) {
    499           result.append("<br>");
    500         }
    501
    502         result.append(iae.getMessage());
    503       }
    504     }
    505
    506     //all rules are valid, they can be applied
    507     if (result.toString().equals("")) {
    508       ((ExpressionTableCellRenderer) table.getColumnModel().getColumn(0).getCellRenderer())
    509       .setToolTipText("Double click to edit");
    510       statusBar.setText(DEFAULT_STATUS);
    511
    512       //only update rules if there were no errors
    513       Map map = new HashMap();
    514       map.put(ruleSet, list);
    515       applyingColorizer.setRules(map);
    516
    517     } else {
    518       statusBar.setText("Errors - see expression tooltip (color filters won't be active until errors are resolved)");
    519       ((ExpressionTableCellRenderer) table.getColumnModel().getColumn(0).getCellRenderer())
    520       .setToolTipText("<html>" + result.toString() + "</html>");
    521     }
    522   }
    523
    524   JPanel buildClosePanel() {
    525     JPanel panel = new JPanel();
    526     panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    527     panel.add(Box.createHorizontalGlue());
    528
    529     JButton saveAsDefaultButton = new JButton(" Save as default ");
    530
    531     saveAsDefaultButton.addActionListener(
    532       new AbstractAction() {
    533         public void actionPerformed(ActionEvent evt) {
    534           RuleColorizer defaultColorizer = (RuleColorizer) allLogPanelColorizers.get(ChainsawConstants.DEFAULT_COLOR_RULE_NAME);
    535           applyRules(currentRuleSet, defaultColorizer);
    536         }
    537     });
    538
    539     panel.add(saveAsDefaultButton);
    540
    541     JButton applyButton = new JButton(" Apply ");
    542
    543     applyButton.addActionListener(
    544       new AbstractAction() {
    545         public void actionPerformed(ActionEvent evt) {
    546           applyRules(currentRuleSet, colorizer);
    547           saveSearchColors();
    548           saveAlternatingColors();
    549           saveBypassFlag();
    550         }
    551       });
    552
    553     panel.add(Box.createHorizontalStrut(10));
    554     panel.add(applyButton);
    555
    556     JButton closeButton = new JButton(" Close ");
    557
    558     closeButton.addActionListener(
    559       new AbstractAction() {
    560         public void actionPerformed(ActionEvent evt) {
    561           hidePanel();
    562         }
    563       });
    564     panel.add(Box.createHorizontalStrut(10));
    565     panel.add(closeButton);
    566
    567     return panel;
    568   }
    569
    570   private void saveSearchColors() {
    571       Vector thisVector = (Vector) searchTableModel.getDataVector().get(0);
    572       applicationPreferenceModel.setSearchBackgroundColor((Color)thisVector.get(0));
    573       applicationPreferenceModel.setSearchForegroundColor((Color)thisVector.get(1));
    574   }
    575
    576   private void saveAlternatingColors() {
    577       Vector thisVector = (Vector) alternatingColorTableModel.getDataVector().get(0);
    578       applicationPreferenceModel.setAlternatingBackgroundColor((Color)thisVector.get(0));
    579       Color alternatingColorForegroundColor = (Color) thisVector.get(1);
    580       applicationPreferenceModel.setAlternatingForegroundColor(alternatingColorForegroundColor);
    581   }
    582
    583   private void saveBypassFlag() {
    584     applicationPreferenceModel.setBypassSearchColors(bypassSearchColorsCheckBox.isSelected());
    585   }
    586
    587   JPanel buildUpDownPanel() {
    588     JPanel panel = new JPanel(new BorderLayout());
    589     JPanel innerPanel = new JPanel();
    590     innerPanel.setLayout(new GridLayout(5, 1));
    591
    592     final JButton upButton = new JButton(ChainsawIcons.ICON_UP);
    593     upButton.setToolTipText("Move selected rule up");
    594
    595     final JButton downButton = new JButton(ChainsawIcons.ICON_DOWN);
    596     downButton.setToolTipText("Move selected rule down");
    597     upButton.setEnabled(false);
    598     downButton.setEnabled(false);
    599
    600     table.getSelectionModel().addListSelectionListener(
    601       new ListSelectionListener() {
    602         public void valueChanged(ListSelectionEvent e) {
    603           if (!e.getValueIsAdjusting()) {
    604             int index = table.getSelectionModel().getMaxSelectionIndex();
    605
    606             if (index < 0) {
    607               downButton.setEnabled(false);
    608               upButton.setEnabled(false);
    609             } else if ((index == 0) && (tableModel.getRowCount() == 1)) {
    610               downButton.setEnabled(false);
    611               upButton.setEnabled(false);
    612             } else if ((index == 0) && (tableModel.getRowCount() > 1)) {
    613               downButton.setEnabled(true);
    614               upButton.setEnabled(false);
    615             } else if (index == (tableModel.getRowCount() - 1)) {
    616               downButton.setEnabled(false);
    617               upButton.setEnabled(true);
    618             } else {
    619               downButton.setEnabled(true);
    620               upButton.setEnabled(true);
    621             }
    622           }
    623         }
    624       });
    625
    626     JPanel upPanel = new JPanel();
    627
    628     upPanel.add(upButton);
    629
    630     JPanel downPanel = new JPanel();
    631     downPanel.add(downButton);
    632
    633     innerPanel.add(new JLabel(""));
    634     innerPanel.add(upPanel);
    635     innerPanel.add(new JLabel(""));
    636     innerPanel.add(downPanel);
    637     panel.add(innerPanel, BorderLayout.CENTER);
    638
    639     upButton.addActionListener(
    640       new AbstractAction() {
    641         public void actionPerformed(ActionEvent evt) {
    642           int index = table.getSelectionModel().getMaxSelectionIndex();
    643
    644           if (index > 0) {
    645             Vector v = tableModel.getDataVector();
    646             Vector row = (Vector) v.elementAt(index);
    647             tableModel.removeRow(index);
    648             index = index - 1;
    649             tableModel.insertRow(index, row);
    650             table.getSelectionModel().setSelectionInterval(index, index);
    651           }
    652         }
    653       });
    654
    655     downButton.addActionListener(
    656       new AbstractAction() {
    657         public void actionPerformed(ActionEvent evt) {
    658           int index = table.getSelectionModel().getMaxSelectionIndex();
    659
    660           if ((index > -1) && (index < (tableModel.getRowCount() - 1))) {
    661             Vector v = tableModel.getDataVector();
    662             Vector row = (Vector) v.elementAt(index);
    663
    664             tableModel.removeRow(index);
    665             index = index + 1;
    666             tableModel.insertRow(index, row);
    667             table.getSelectionModel().setSelectionInterval(index, index);
    668           }
    669         }
    670       });
    671
    672     return panel;
    673   }
    674
    675   JPanel buildRulesPanel() {
    676     JPanel listPanel = new JPanel(new BorderLayout());
    677     JPanel panel = new JPanel();
    678     panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
    679
    680     panel.add(Box.createVerticalStrut(10));
    681
    682     JLabel rulesLabel = new JLabel("Rules:");
    683
    684     panel.add(rulesLabel);
    685
    686     JPanel buttonPanel = new JPanel(new GridLayout(0, 2));
    687     buttonPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
    688
    689     JPanel newPanel = new JPanel();
    690     JButton newButton = new JButton(" New ");
    691     newButton.addActionListener(
    692       new AbstractAction() {
    693         public void actionPerformed(ActionEvent evt) {
    694           int currentRow = table.getSelectedRow();
    695           Vector v = new Vector();
    696           v.add("");
    697           v.add(Color.white);
    698           v.add(Color.black);
    699
    700           if (currentRow < 0) {
    701             tableModel.addRow(v);
    702             currentRow = table.getRowCount() - 1;
    703           } else {
    704             tableModel.insertRow(currentRow, v);
    705           }
    706
    707           table.getSelectionModel().setSelectionInterval(
    708             currentRow, currentRow);
    709         }
    710       });
    711
    712     newPanel.add(newButton);
    713
    714     JPanel deletePanel = new JPanel();
    715     final JButton deleteButton = new JButton(" Delete ");
    716     deleteButton.setEnabled(false);
    717
    718     deleteButton.addActionListener(
    719       new AbstractAction() {
    720         public void actionPerformed(ActionEvent evt) {
    721           int index = table.getSelectionModel().getMaxSelectionIndex();
    722
    723           if ((index > -1) && (index < table.getRowCount())) {
    724             tableModel.removeRow(index);
    725
    726             if (index > 0) {
    727               index = index - 1;
    728             }
    729
    730             if (tableModel.getRowCount() > 0) {
    731               table.getSelectionModel().setSelectionInterval(index, index);
    732             }
    733           }
    734         }
    735       });
    736
    737     table.getSelectionModel().addListSelectionListener(
    738       new ListSelectionListener() {
    739         public void valueChanged(ListSelectionEvent e) {
    740           if (!e.getValueIsAdjusting()) {
    741             int index = table.getSelectionModel().getMaxSelectionIndex();
    742
    743             if (index < 0) {
    744               deleteButton.setEnabled(false);
    745             } else {
    746               deleteButton.setEnabled(true);
    747             }
    748           }
    749         }
    750       });
    751
    752     deletePanel.add(deleteButton);
    753
    754     buttonPanel.add(newPanel);
    755     buttonPanel.add(deletePanel);
    756
    757     listPanel.add(panel, BorderLayout.NORTH);
    758
    759     JPanel tablePanel = new JPanel(new BorderLayout());
    760     tableScrollPane.setBorder(BorderFactory.createEtchedBorder());
    761     tablePanel.add(tableScrollPane, BorderLayout.CENTER);
    762     tablePanel.add(buildUpDownPanel(), BorderLayout.EAST);
    763     listPanel.add(tablePanel, BorderLayout.CENTER);
    764     listPanel.add(buttonPanel, BorderLayout.SOUTH);
    765
    766     return listPanel;
    767   }
    768
    769     class ColorListCellRenderer extends JLabel implements ListCellRenderer {
    770     ColorListCellRenderer() {
    771       setOpaque(true);
    772     }
    773
    774     public Component getListCellRendererComponent(
    775       JList list, Object value, int index, boolean isSelected,
    776       boolean cellHasFocus) {
    777       setText(" ");
    778
    779       if (isSelected && (index > -1)) {
    780         setBorder(BorderFactory.createLineBorder(Color.black, 2));
    781       } else {
    782         setBorder(BorderFactory.createEmptyBorder());
    783       }
    784
    785       if (value instanceof Color) {
    786         setBackground((Color) value);
    787       } else {
    788         setBackground(Color.white);
    789
    790         if (value != null) {
    791           setText(value.toString());
    792         }
    793       }
    794
    795       return this;
    796     }
    797   }
    798
    799   class ColorItemListener implements ItemListener {
    800     JComboBox box;
    801     JDialog dialog;
    802     JColorChooser colorChooser;
    803     Color lastColor;
    804
    805     ColorItemListener(final JComboBox box) {
    806       this.box = box;
    807       colorChooser = new JColorChooser();
    808       dialog =
    809         JColorChooser.createDialog(
    810           box, "Pick a Color", true, //modal
    811           colorChooser,
    812           new ActionListener() {
    813             public void actionPerformed(ActionEvent e) {
    814               box.insertItemAt(colorChooser.getColor(), 0);
    815               box.setSelectedIndex(0);
    816             }
    817           }, //OK button handler
    818           new ActionListener() {
    819             public void actionPerformed(ActionEvent e) {
    820                 box.setSelectedItem(lastColor);
    821             }
    822           }); //CANCEL button handler
    823       dialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
    824     }
    825
    826     public void itemStateChanged(ItemEvent e) {
    827       if (e.getStateChange() == ItemEvent.SELECTED) {
    828         if (box.getSelectedItem() instanceof Color) {
    829           box.setBackground((Color) box.getSelectedItem());
    830           repaint();
    831         } else {
    832           box.setBackground(Color.white);
    833           int selectedRow = table.getSelectedRow();
    834           int selectedColumn = table.getSelectedColumn();
    835           if (selectedRow != -1 && selectedColumn != -1) {
    836               colorChooser.setColor((Color)table.getValueAt(selectedRow, selectedColumn));
    837               lastColor = (Color)table.getValueAt(selectedRow, selectedColumn);
    838           }
    839           dialog.setVisible(true);
    840         }
    841       }
    842     }
    843   }
    844
    845   class ColorTableCellRenderer implements TableCellRenderer {
    846     Border border;
    847     JPanel panel;
    848
    849     ColorTableCellRenderer() {
    850         panel = new JPanel();
    851         panel.setOpaque(true);
    852     }
    853
    854     public Color getCurrentColor() {
    855         return panel.getBackground();
    856     }
    857
    858     public Component getTableCellRendererComponent(
    859       JTable thisTable, Object value, boolean isSelected, boolean hasFocus, int row,
    860       int column) {
    861       if (value instanceof Color) {
    862         panel.setBackground((Color) value);
    863       }
    864       if (border == null) {
    865         border = BorderFactory.createMatteBorder(2, 2, 2, 2, table.getBackground());
    866       }
    867
    868       panel.setBorder(border);
    869
    870       return panel;
    871     }
    872   }
    873
    874   class ExpressionTableCellRenderer implements TableCellRenderer {
    875     JPanel panel = new JPanel();
    876     JLabel expressionLabel = new JLabel();
    877     JLabel iconLabel = new JLabel();
    878     Icon selectedIcon = new SelectedIcon(true);
    879     Icon unselectedIcon = new SelectedIcon(false);
    880
    881     ExpressionTableCellRenderer() {
    882       panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    883       panel.setOpaque(true);
    884       panel.add(iconLabel);
    885       panel.add(Box.createHorizontalStrut(5));
    886       panel.add(expressionLabel);
    887     }
    888
    889     void setToolTipText(String text) {
    890         panel.setToolTipText(text);
    891     }
    892
    893     public Component getTableCellRendererComponent(
    894       JTable thisTable, Object value, boolean isSelected, boolean hasFocus, int row,
    895       int column) {
    896       if (value == null) {
    897           return panel;
    898       }
    899
    900       Vector v = tableModel.getDataVector();
    901       Vector r = (Vector) v.elementAt(row);
    902       expressionLabel.setText(value.toString());
    903
    904       if (r.elementAt(1) instanceof Color) {
    905         expressionLabel.setBackground((Color) r.elementAt(1));
    906         panel.setBackground((Color) r.elementAt(1));
    907       }
    908
    909       if (r.elementAt(2) instanceof Color) {
    910         expressionLabel.setForeground((Color) r.elementAt(2));
    911         panel.setForeground((Color) r.elementAt(2));
    912       }
    913
    914       if (isSelected) {
    915           iconLabel.setIcon(selectedIcon);
    916       } else {
    917           iconLabel.setIcon(unselectedIcon);
    918       }
    919
    920       return panel;
    921     }
    922   }
    923
    924   class SelectedIcon implements Icon {
    925       private boolean isSelected;
    926       private int width = 9;
    927       private int height = 18;
    928       private int[] xPoints = new int[4];
    929       private int[] yPoints = new int[4];
    930
    931       public SelectedIcon(boolean isSelected) {
    932         this.isSelected = isSelected;
    933         xPoints[0] = 0;
    934         yPoints[0] = -1;
    935         xPoints[1] = 0;
    936         yPoints[1] = height;
    937         xPoints[2] = width;
    938         yPoints[2] = height / 2;
    939         xPoints[3] = width;
    940         yPoints[3] = (height / 2) - 1;
    941       }
    942
    943       public int getIconHeight() {
    944         return height;
    945       }
    946
    947       public int getIconWidth() {
    948         return width;
    949       }
    950
    951       public void paintIcon(Component c, Graphics g, int x, int y) {
    952         if (isSelected) {
    953           int length = xPoints.length;
    954           int[] newXPoints = new int[length];
    955           int[] newYPoints = new int[length];
    956
    957           for (int i = 0; i < length; i++) {
    958             newXPoints[i] = xPoints[i] + x;
    959             newYPoints[i] = yPoints[i] + y;
    960           }
    961
    962           g.setColor(Color.black);
    963
    964           g.fillPolygon(newXPoints, newYPoints, length);
    965         }
    966       }
    967   }
    968 }