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  package org.apache.log4j.chainsaw;
18  
19  import java.awt.BorderLayout;
20  import java.awt.Component;
21  import java.awt.Dimension;
22  import java.awt.event.ActionEvent;
23  import java.awt.event.ActionListener;
24  import java.awt.event.MouseAdapter;
25  import java.awt.event.MouseEvent;
26  import java.beans.PropertyChangeEvent;
27  import java.beans.PropertyChangeListener;
28  import java.util.ArrayList;
29  import java.util.Enumeration;
30  import java.util.Iterator;
31  import java.util.List;
32  
33  import javax.swing.BorderFactory;
34  import javax.swing.Box;
35  import javax.swing.BoxLayout;
36  import javax.swing.ButtonGroup;
37  import javax.swing.JButton;
38  import javax.swing.JCheckBox;
39  import javax.swing.JEditorPane;
40  import javax.swing.JFrame;
41  import javax.swing.JLabel;
42  import javax.swing.JList;
43  import javax.swing.JPanel;
44  import javax.swing.JRadioButton;
45  import javax.swing.JScrollPane;
46  import javax.swing.JTextField;
47  import javax.swing.SwingConstants;
48  import javax.swing.table.TableColumn;
49  import javax.swing.tree.DefaultMutableTreeNode;
50  import javax.swing.tree.DefaultTreeModel;
51  import javax.swing.tree.TreeModel;
52  
53  import org.apache.log4j.LogManager;
54  import org.apache.log4j.Logger;
55  
56  
57  /**
58   * GUI panel used to manipulate the PreferenceModel for a Log Panel
59   *
60   * @author Paul Smith
61   */
62  public class LogPanelPreferencePanel extends AbstractPreferencePanel
63  {
64    //~ Instance fields =========================================================
65  
66    private final LogPanelPreferenceModel preferenceModel;
67    private final ModifiableListModel columnListModel = new ModifiableListModel();
68    private static final Logger logger = LogManager.getLogger(LogPanelPreferencePanel.class);
69    private ApplicationPreferenceModel appPreferenceModel;
70  
71    //~ Constructors ============================================================
72  
73    public LogPanelPreferencePanel(LogPanelPreferenceModel model, ApplicationPreferenceModel appModel)
74    {
75      preferenceModel = model;
76      appPreferenceModel = appModel;
77      initComponents();
78  
79      getOkButton().addActionListener(new ActionListener()
80        {
81          public void actionPerformed(ActionEvent e)
82          {
83            hidePanel();
84          }
85        });
86  
87      getCancelButton().addActionListener(new ActionListener()
88        {
89          public void actionPerformed(ActionEvent e)
90          {
91            hidePanel();
92          }
93        });
94      }
95  
96    //~ Methods =================================================================
97  
98    /**
99     * DOCUMENT ME!
100    *
101    * @param args DOCUMENT ME!
102    */
103   public static void main(String[] args)
104   {
105     JFrame f = new JFrame("Preferences Panel Test Bed");
106     LogPanelPreferenceModel model = new LogPanelPreferenceModel();
107     ApplicationPreferenceModel appModel = new ApplicationPreferenceModel();
108     LogPanelPreferencePanel panel = new LogPanelPreferencePanel(model, appModel);
109     f.getContentPane().add(panel);
110 
111     model.addPropertyChangeListener(new PropertyChangeListener()
112       {
113         public void propertyChange(PropertyChangeEvent evt)
114         {
115           logger.warn(evt.toString());
116         }
117       });
118     panel.setOkCancelActionListener(new ActionListener()
119       {
120         public void actionPerformed(ActionEvent e)
121         {
122           System.exit(1);
123         }
124       });
125 
126     f.setSize(640, 480);
127     f.setVisible(true);
128   }
129 
130   protected TreeModel createTreeModel()
131   {
132     final DefaultMutableTreeNode rootNode =
133       new DefaultMutableTreeNode("Preferences");
134     DefaultTreeModel model = new DefaultTreeModel(rootNode);
135 
136     DefaultMutableTreeNode visuals =
137       new DefaultMutableTreeNode(new VisualsPrefPanel());
138     DefaultMutableTreeNode formatting =
139       new DefaultMutableTreeNode(new FormattingPanel());
140     DefaultMutableTreeNode columns =
141       new DefaultMutableTreeNode(new ColumnSelectorPanel());
142 
143     rootNode.add(visuals);
144     rootNode.add(formatting);
145     rootNode.add(columns);
146 
147     return model;
148   }
149 
150   //~ Inner Classes ===========================================================
151 
152   /**
153    * Allows the user to choose which columns to display.
154    *
155    * @author Paul Smith
156    *
157    */
158   public class ColumnSelectorPanel extends BasicPrefPanel
159   {
160     //~ Constructors ==========================================================
161 
162     ColumnSelectorPanel()
163     {
164       super("Columns");
165       initComponents();
166     }
167 
168     //~ Methods ===============================================================
169 
170     private void initComponents()
171     {
172       setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
173 
174       Box columnBox = new Box(BoxLayout.Y_AXIS);
175 
176       //		columnBox.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Displayed Columns"));
177       final JList columnList = new JList();
178       columnList.setVisibleRowCount(17);
179 
180       for (
181         Iterator iter = preferenceModel.getColumns().iterator();
182           iter.hasNext();)
183       {
184           TableColumn col = (TableColumn)iter.next();
185           Enumeration enumeration = columnListModel.elements();
186           boolean found = false;
187           while (enumeration.hasMoreElements()) {
188               TableColumn thisCol = (TableColumn) enumeration.nextElement();
189               if (thisCol.getHeaderValue().equals(col.getHeaderValue())) {
190                   found = true;
191               }
192           }
193             if (!found) {
194               columnListModel.addElement(col);
195             }
196       }
197 
198       columnList.setModel(columnListModel);
199 
200       CheckListCellRenderer cellRenderer = new CheckListCellRenderer()
201         {
202           protected boolean isSelected(Object value)
203           {
204             return LogPanelPreferencePanel.this.preferenceModel.isColumnVisible((TableColumn)
205               value);
206           }
207         };
208 
209       columnList.addMouseListener(new MouseAdapter()
210         {
211           public void mouseClicked(MouseEvent e)
212           {
213               int i = columnList.locationToIndex(e.getPoint());
214 
215               if (i >= 0)
216               {
217                 Object column = columnListModel.get(i);
218                 preferenceModel.toggleColumn(((TableColumn)column));
219               }
220           }
221         });
222       JButton setAsDefaultsButton = new JButton("Use selected columns as default visible columns");
223       setAsDefaultsButton.addActionListener(new ActionListener() {
224         public void actionPerformed(ActionEvent actionEvent) {
225           List selectedColumns = new ArrayList();
226           for (int i = 0;i<columnListModel.getSize();i++) {
227             if (preferenceModel.isColumnVisible((TableColumn) columnListModel.get(i))) {
228               selectedColumns.add(((TableColumn)columnListModel.get(i)).getHeaderValue());
229             }
230           }
231           appPreferenceModel.setDefaultColumnNames(selectedColumns);
232         }
233       });
234       columnList.setCellRenderer(cellRenderer);
235       columnBox.add(new JScrollPane(columnList));
236       columnBox.add(Box.createVerticalStrut(5));
237       columnBox.add(setAsDefaultsButton);
238       add(columnBox);
239       add(Box.createVerticalGlue());
240     }
241   }
242 
243   /**
244    * Provides preference gui's for all the Formatting options
245    * available for the columns etc.
246    */
247   private class FormattingPanel extends BasicPrefPanel
248   {
249     //~ Instance fields =======================================================
250 
251     private JTextField customFormatText = new JTextField("", 10);
252     private JTextField loggerPrecision = new JTextField(10);
253     private JRadioButton rdCustom = new JRadioButton("Custom Format ");
254     private final JRadioButton rdISO =
255       new JRadioButton(
256         "<html><b>Fast</b> ISO 8601 format (yyyy-MM-dd HH:mm:ss) </html>");
257     private final JTextField timeZone = new JTextField(10);
258     private final JRadioButton rdLevelIcons = new JRadioButton("Icons ");
259     private final JRadioButton rdLevelText = new JRadioButton("Text ");
260     private JRadioButton rdLast;
261 
262     //~ Constructors ==========================================================
263 
264     private FormattingPanel()
265     {
266       super("Formatting");
267       this.initComponents();
268       setupListeners();
269     }
270 
271     //~ Methods ===============================================================
272 
273     private void initComponents()
274     {
275       setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
276 
277       JPanel dateFormatPanel = new JPanel();
278       dateFormatPanel.setLayout(new BoxLayout(dateFormatPanel, BoxLayout.Y_AXIS));
279       dateFormatPanel.setBorder(
280         BorderFactory.createTitledBorder(
281           BorderFactory.createEtchedBorder(), "Timestamp"));
282 
283       ButtonGroup bgDateFormat = new ButtonGroup();
284 
285       rdISO.setSelected(preferenceModel.isUseISO8601Format());
286 
287       rdISO.setHorizontalTextPosition(SwingConstants.RIGHT);
288       rdISO.setAlignmentX(Component.LEFT_ALIGNMENT);      
289 
290       bgDateFormat.add(rdISO);
291       dateFormatPanel.add(rdISO);
292 
293       for (
294         Iterator iter = LogPanelPreferenceModel.DATE_FORMATS.iterator();
295           iter.hasNext();)
296       {
297         final String format = (String) iter.next();
298         final JRadioButton rdFormat = new JRadioButton(format);
299         rdFormat.setHorizontalTextPosition(SwingConstants.RIGHT);
300         rdFormat.setAlignmentX(Component.LEFT_ALIGNMENT);      
301 
302         rdFormat.addActionListener(new ActionListener()
303           {
304             public void actionPerformed(ActionEvent e)
305             {
306               preferenceModel.setDateFormatPattern(format);
307               customFormatText.setEnabled(rdCustom.isSelected());
308               rdLast = rdFormat;
309             }
310           });
311         //update based on external changes to dateformatpattern (column context
312         //menu)
313         preferenceModel.addPropertyChangeListener(
314           "dateFormatPattern", new PropertyChangeListener()
315           {
316             public void propertyChange(PropertyChangeEvent evt)
317             {
318               rdFormat.setSelected(
319                 preferenceModel.getDateFormatPattern().equals(format));
320               rdLast = rdFormat;
321             }
322           });
323 
324         dateFormatPanel.add(rdFormat);
325         bgDateFormat.add(rdFormat);
326       }
327 
328       customFormatText.setPreferredSize(new Dimension(100, 20));
329       customFormatText.setMaximumSize(customFormatText.getPreferredSize());
330       customFormatText.setMinimumSize(customFormatText.getPreferredSize());
331       customFormatText.setEnabled(false);
332 
333       bgDateFormat.add(rdCustom);
334       rdCustom.setSelected(preferenceModel.isCustomDateFormat());
335 
336       // add a custom date format
337       if (preferenceModel.isCustomDateFormat())
338       {
339         customFormatText.setText(preferenceModel.getDateFormatPattern());
340         customFormatText.setEnabled(true);
341       }
342 
343       JPanel customPanel = new JPanel();
344       customPanel.setLayout(new BoxLayout(customPanel, BoxLayout.X_AXIS));
345       customPanel.add(rdCustom);
346       customPanel.add(customFormatText);
347       customPanel.setAlignmentX(Component.LEFT_ALIGNMENT);      
348 
349       dateFormatPanel.add(customPanel);
350       dateFormatPanel.add(Box.createVerticalStrut(5));
351 
352       JLabel dateFormatLabel = new JLabel("Time zone of events (or blank for local time zone");
353       dateFormatPanel.add(dateFormatLabel);
354 
355       timeZone.setMaximumSize(timeZone.getPreferredSize());
356       dateFormatPanel.add(Box.createVerticalStrut(5));
357       dateFormatPanel.add(timeZone);
358       
359       add(dateFormatPanel);
360 
361       JPanel levelFormatPanel = new JPanel();
362       levelFormatPanel.setLayout(
363         new BoxLayout(levelFormatPanel, BoxLayout.Y_AXIS));
364       levelFormatPanel.setBorder(
365         BorderFactory.createTitledBorder(
366           BorderFactory.createEtchedBorder(), "Level"));
367       levelFormatPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
368 
369       ButtonGroup bgLevel = new ButtonGroup();
370       bgLevel.add(rdLevelIcons);
371       bgLevel.add(rdLevelText);
372 
373       rdLevelIcons.setSelected(preferenceModel.isLevelIcons());
374 
375       levelFormatPanel.add(rdLevelIcons);
376       levelFormatPanel.add(rdLevelText);
377 
378       add(levelFormatPanel);
379 
380       JPanel loggerFormatPanel = new JPanel();
381       loggerFormatPanel.setLayout(
382         new BoxLayout(loggerFormatPanel, BoxLayout.Y_AXIS));
383       loggerFormatPanel.setBorder(
384         BorderFactory.createTitledBorder(
385           BorderFactory.createEtchedBorder(), "Logger"));
386       loggerFormatPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
387 
388       loggerFormatPanel.add(Box.createVerticalStrut(3));
389 
390       final JLabel precisionLabel =
391         new JLabel("Number of package levels to hide (or blank to display full logger)");
392 
393       loggerFormatPanel.add(precisionLabel);
394       loggerFormatPanel.add(Box.createVerticalStrut(5));
395 
396       loggerPrecision.setMaximumSize(loggerPrecision.getPreferredSize());
397       loggerFormatPanel.add(loggerPrecision);
398 
399       add(loggerFormatPanel);
400     }
401 
402     /*
403      * Restore text fields to current model values
404      */
405     private void reset() {
406 
407     	if (preferenceModel.isCustomDateFormat()) {
408     		customFormatText.setText(preferenceModel.getDateFormatPattern());
409     	} else {
410     		if (rdLast != null) {
411     			rdLast.setSelected(true);
412     		}
413     		customFormatText.setEnabled(false);
414     	}
415     	
416     	loggerPrecision.setText(preferenceModel.getLoggerPrecision());
417     	timeZone.setText(preferenceModel.getTimeZone());
418     }
419 
420     /*
421      * Commit text fields to model
422      */
423     private void commit() {
424     	if (rdCustom.isSelected()) {
425     		preferenceModel.setDateFormatPattern(customFormatText.getText());
426     	}
427     	preferenceModel.setLoggerPrecision(loggerPrecision.getText());
428     	preferenceModel.setTimeZone(timeZone.getText());
429     }
430 
431     /**
432      * DOCUMENT ME!
433     */
434     private void setupListeners()
435     {
436       getOkButton().addActionListener(new ActionListener() {
437     	  public void actionPerformed(ActionEvent evt) {
438     		  commit();
439     	  }
440       });
441       
442       getCancelButton().addActionListener(new ActionListener() {
443     	  public void actionPerformed(ActionEvent evt) {
444     		  reset();
445     	  }
446       });
447     	  
448     	  rdCustom.addActionListener(new ActionListener()
449         {
450           public void actionPerformed(ActionEvent e)
451           {
452             customFormatText.setEnabled(rdCustom.isSelected());
453             customFormatText.grabFocus();
454           }
455         });
456 
457       //a second?? listener for dateformatpattern
458       preferenceModel.addPropertyChangeListener(
459         "dateFormatPattern", new PropertyChangeListener()
460         {
461           public void propertyChange(PropertyChangeEvent evt)
462           {
463             /**
464              * we need to make sure we are not reacting to the user typing, so only do this
465              * if the text box is not the same as the model
466              */
467             if (
468               preferenceModel.isCustomDateFormat()
469                 && !customFormatText.getText().equals(
470                   evt.getNewValue().toString()))
471             {
472               customFormatText.setText(preferenceModel.getDateFormatPattern());
473               rdCustom.setSelected(true);
474               customFormatText.setEnabled(true);
475             }
476             else
477             {
478               rdCustom.setSelected(false);
479             }
480           }
481         });
482 
483       rdISO.addActionListener(new ActionListener()
484         {
485           public void actionPerformed(ActionEvent e)
486           {
487             preferenceModel.setDateFormatPattern("ISO8601");
488             customFormatText.setEnabled(rdCustom.isSelected());
489             rdLast = rdISO;
490           }
491         });
492       preferenceModel.addPropertyChangeListener(
493         "dateFormatPattern", new PropertyChangeListener()
494         {
495           public void propertyChange(PropertyChangeEvent evt)
496           {
497             rdISO.setSelected(preferenceModel.isUseISO8601Format());
498             rdLast = rdISO;
499           }
500         });
501       preferenceModel.addPropertyChangeListener(
502           "dateFormatTimeZone", new PropertyChangeListener() {
503               public void propertyChange(PropertyChangeEvent evt) {
504                   timeZone.setText(preferenceModel.getTimeZone());
505               }
506           }
507       );
508 
509       ActionListener levelIconListener = new ActionListener()
510         {
511           public void actionPerformed(ActionEvent e)
512           {
513             preferenceModel.setLevelIcons(rdLevelIcons.isSelected());
514           }
515         };
516 
517       rdLevelIcons.addActionListener(levelIconListener);
518       rdLevelText.addActionListener(levelIconListener);
519 
520       preferenceModel.addPropertyChangeListener(
521         "levelIcons", new PropertyChangeListener()
522         {
523           public void propertyChange(PropertyChangeEvent evt)
524           {
525             boolean value = ((Boolean) evt.getNewValue()).booleanValue();
526             rdLevelIcons.setSelected(value);
527             rdLevelText.setSelected(!value);
528           }
529         });
530     }
531   }
532 
533   /**
534    * DOCUMENT ME!
535    *
536    * @author $author$
537    * @version $Revision$, $Date$
538    *
539    * @author psmith
540    *
541    */
542   private class VisualsPrefPanel extends BasicPrefPanel
543   {
544     //~ Instance fields =======================================================
545 
546     private final JCheckBox detailPanelVisible =
547       new JCheckBox("Show Event Detail panel");
548 
549     private final JCheckBox loggerTreePanel =
550       new JCheckBox("Show Logger Tree");
551     private final JCheckBox wrapMessage = new JCheckBox("Wrap message field (display multi-line rows) ");
552     private final JCheckBox searchResultsVisible = new JCheckBox("Display find results in details panel ");
553     private final JCheckBox highlightSearchMatchText = new JCheckBox("Highlight find match text ");
554     private final JCheckBox scrollToBottom =
555       new JCheckBox("Scroll to bottom (view tracks with new events)");
556     private final JCheckBox showMillisDeltaAsGap =
557       new JCheckBox("Display timestamp delta between events as row gap");
558     private final JCheckBox toolTips =
559       new JCheckBox("Show Event Detail Tooltips");
560     private final JCheckBox thumbnailBarToolTips =
561       new JCheckBox("Show Thumbnail Bar Tooltips");
562     private final JEditorPane clearTableExpression = new JEditorPane();
563 
564     //~ Constructors ==========================================================
565 
566     /**
567      * Creates a new VisualsPrefPanel object.
568     */
569     private VisualsPrefPanel()
570     {
571       super("Visuals");
572       initPanelComponents();
573       setupListeners();
574     }
575 
576     //~ Methods ===============================================================
577 
578     /**
579      * DOCUMENT ME!
580     */
581     private void initPanelComponents()
582     {
583       JTextComponentFormatter.applySystemFontAndSize(clearTableExpression);
584       setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
585       toolTips.setAlignmentX(Component.LEFT_ALIGNMENT);
586       thumbnailBarToolTips.setAlignmentX(Component.LEFT_ALIGNMENT);
587       detailPanelVisible.setAlignmentX(Component.LEFT_ALIGNMENT);
588       loggerTreePanel.setAlignmentX(Component.LEFT_ALIGNMENT);
589       scrollToBottom.setAlignmentX(Component.LEFT_ALIGNMENT);
590       showMillisDeltaAsGap.setAlignmentX(Component.LEFT_ALIGNMENT);
591       add(toolTips);
592       add(thumbnailBarToolTips);
593       add(detailPanelVisible);
594       add(loggerTreePanel);
595       add(scrollToBottom);
596       add(wrapMessage);
597       add(highlightSearchMatchText);
598       add(searchResultsVisible);
599       add(showMillisDeltaAsGap);
600       JPanel clearPanel = new JPanel(new BorderLayout());
601       clearPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
602       clearPanel.add(new JLabel("Clear all events if expression matches"), BorderLayout.NORTH);
603       clearTableExpression.setText(preferenceModel.getClearTableExpression());
604       clearTableExpression.setPreferredSize(new Dimension(300, 50));
605       JPanel clearTableScrollPanel = new JPanel(new BorderLayout());
606       clearTableScrollPanel.add(new JScrollPane(clearTableExpression), BorderLayout.NORTH);
607       clearPanel.add(clearTableScrollPanel, BorderLayout.CENTER);
608       add(clearPanel);
609 
610       toolTips.setSelected(preferenceModel.isToolTips());
611       thumbnailBarToolTips.setSelected(preferenceModel.isThumbnailBarToolTips());
612       detailPanelVisible.setSelected(preferenceModel.isDetailPaneVisible());
613       searchResultsVisible.setSelected(preferenceModel.isSearchResultsVisible());
614       loggerTreePanel.setSelected(preferenceModel.isLogTreePanelVisible());
615     }
616 
617     /**
618      * DOCUMENT ME!
619     */
620     private void setupListeners()
621     {
622         ActionListener wrapMessageListener = new ActionListener()
623         {
624             public void actionPerformed(ActionEvent e)
625             {
626                 preferenceModel.setWrapMessage(wrapMessage.isSelected());
627             }
628         };
629 
630         wrapMessage.addActionListener(wrapMessageListener);
631 
632         ActionListener searchResultsVisibleListener = new ActionListener()
633         {
634             public void actionPerformed(ActionEvent e)
635             {
636                 preferenceModel.setSearchResultsVisible(searchResultsVisible.isSelected());
637             }
638         };
639 
640         searchResultsVisible.addActionListener(searchResultsVisibleListener);
641 
642         ActionListener highlightSearchMatchTextListener = new ActionListener()
643         {
644             public void actionPerformed(ActionEvent e)
645             {
646                 preferenceModel.setHighlightSearchMatchText(highlightSearchMatchText.isSelected());
647             }
648         };
649 
650         highlightSearchMatchText.addActionListener(highlightSearchMatchTextListener);
651 
652         preferenceModel.addPropertyChangeListener(
653           "wrapMessage", new PropertyChangeListener()
654           {
655             public void propertyChange(PropertyChangeEvent evt)
656             {
657               boolean value = ((Boolean) evt.getNewValue()).booleanValue();
658               wrapMessage.setSelected(value);
659             }
660           });
661 
662       preferenceModel.addPropertyChangeListener(
663         "searchResultsVisible", new PropertyChangeListener()
664         {
665           public void propertyChange(PropertyChangeEvent evt)
666           {
667             boolean value = ((Boolean) evt.getNewValue()).booleanValue();
668             searchResultsVisible.setSelected(value);
669           }
670         });
671 
672         preferenceModel.addPropertyChangeListener(
673           "highlightSearchMatchText", new PropertyChangeListener()
674           {
675             public void propertyChange(PropertyChangeEvent evt)
676             {
677               boolean value = ((Boolean) evt.getNewValue()).booleanValue();
678               highlightSearchMatchText.setSelected(value);
679             }
680           });
681 
682       toolTips.addActionListener(new ActionListener()
683         {
684           public void actionPerformed(ActionEvent e)
685           {
686             preferenceModel.setToolTips(toolTips.isSelected());
687           }
688         });
689 
690       thumbnailBarToolTips.addActionListener(new ActionListener() {
691           public void actionPerformed(ActionEvent e) {
692               preferenceModel.setThumbnailBarToolTips(thumbnailBarToolTips.isSelected());
693           }
694       });
695 
696       getOkButton().addActionListener(new ActionListener() {
697           public void actionPerformed(ActionEvent e) {
698               preferenceModel.setClearTableExpression(clearTableExpression.getText().trim());
699           }
700       });
701 
702       preferenceModel.addPropertyChangeListener(
703         "toolTips", new PropertyChangeListener()
704         {
705           public void propertyChange(PropertyChangeEvent evt)
706           {
707             boolean value = ((Boolean) evt.getNewValue()).booleanValue();
708             toolTips.setSelected(value);
709           }
710         });
711 
712     preferenceModel.addPropertyChangeListener(
713       "thumbnailBarToolTips", new PropertyChangeListener()
714       {
715         public void propertyChange(PropertyChangeEvent evt)
716         {
717           boolean value = ((Boolean) evt.getNewValue()).booleanValue();
718           thumbnailBarToolTips.setSelected(value);
719         }
720       });
721 
722       detailPanelVisible.addActionListener(new ActionListener()
723         {
724           public void actionPerformed(ActionEvent e)
725           {
726             preferenceModel.setDetailPaneVisible(detailPanelVisible.isSelected());
727           }
728         });
729 
730       preferenceModel.addPropertyChangeListener(
731         "detailPaneVisible", new PropertyChangeListener()
732         {
733           public void propertyChange(PropertyChangeEvent evt)
734           {
735             boolean value = ((Boolean) evt.getNewValue()).booleanValue();
736             detailPanelVisible.setSelected(value);
737           }
738         });
739 
740       scrollToBottom.addActionListener(new ActionListener()
741         {
742           public void actionPerformed(ActionEvent e)
743           {
744             preferenceModel.setScrollToBottom(scrollToBottom.isSelected());
745           }
746         });
747 
748       showMillisDeltaAsGap.addActionListener(new ActionListener()
749       {
750           public void actionPerformed(ActionEvent e)
751           {
752               preferenceModel.setShowMillisDeltaAsGap(showMillisDeltaAsGap.isSelected());
753           }
754       });
755 
756       preferenceModel.addPropertyChangeListener("showMillisDeltaAsGap", new PropertyChangeListener()
757       {
758           public void propertyChange(PropertyChangeEvent evt)
759           {
760               boolean value = ((Boolean) evt.getNewValue()).booleanValue();
761               showMillisDeltaAsGap.setSelected(value);
762           }
763       });
764       preferenceModel.addPropertyChangeListener(
765         "scrollToBottom", new PropertyChangeListener()
766         {
767           public void propertyChange(PropertyChangeEvent evt)
768           {
769             boolean value = ((Boolean) evt.getNewValue()).booleanValue();
770             scrollToBottom.setSelected(value);
771           }
772         });
773 
774       loggerTreePanel.addActionListener(new ActionListener()
775         {
776           public void actionPerformed(ActionEvent e)
777           {
778             preferenceModel.setLogTreePanelVisible(loggerTreePanel.isSelected());
779           }
780         });
781 
782       preferenceModel.addPropertyChangeListener(
783         "logTreePanelVisible", new PropertyChangeListener()
784         {
785           public void propertyChange(PropertyChangeEvent evt)
786           {
787             boolean value = ((Boolean) evt.getNewValue()).booleanValue();
788             loggerTreePanel.setSelected(value);
789           }
790         });
791 
792       preferenceModel.addPropertyChangeListener("columns", new PropertyChangeListener() {
793         	public void propertyChange(PropertyChangeEvent evt) {
794       	  List cols = (List)evt.getNewValue();
795             for (
796           	        Iterator iter = cols.iterator();
797           	          iter.hasNext();)
798           	      {
799           	        TableColumn col = (TableColumn) iter.next();
800                     Enumeration enumeration = columnListModel.elements();
801                     boolean found = false;
802                     while (enumeration.hasMoreElements()) {
803                         TableColumn thisCol = (TableColumn) enumeration.nextElement();
804                         if (thisCol.getHeaderValue().equals(col.getHeaderValue())) {
805                             found = true;
806                         }
807                     }
808           	        if (!found) {
809           	        	columnListModel.addElement(col);
810           	            columnListModel.fireContentsChanged();
811           	        }
812           	      }
813         }});
814 
815         preferenceModel.addPropertyChangeListener(
816                 "visibleColumns", new PropertyChangeListener()
817                 {
818                   public void propertyChange(PropertyChangeEvent evt)
819                   {
820                     columnListModel.fireContentsChanged();
821                   }
822                 });
823 
824         preferenceModel.addPropertyChangeListener("clearTableExpression", new PropertyChangeListener()
825         {
826             public void propertyChange(PropertyChangeEvent evt) {
827                 clearTableExpression.setText(((LogPanelPreferenceModel)evt.getSource()).getClearTableExpression());
828             }
829         });
830     }
831   }
832 }