1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.log4j.chainsaw;
19
20 import java.awt.BorderLayout;
21 import java.awt.Color;
22 import java.awt.Component;
23 import java.awt.Container;
24 import java.awt.Dimension;
25 import java.awt.EventQueue;
26 import java.awt.Font;
27 import java.awt.FontMetrics;
28 import java.awt.Graphics;
29 import java.awt.Point;
30 import java.awt.Toolkit;
31 import java.awt.Window;
32 import java.awt.datatransfer.Clipboard;
33 import java.awt.datatransfer.StringSelection;
34 import java.awt.event.ActionEvent;
35 import java.awt.event.ActionListener;
36 import java.awt.event.FocusEvent;
37 import java.awt.event.FocusListener;
38 import java.awt.event.InputEvent;
39 import java.awt.event.KeyEvent;
40 import java.awt.event.KeyListener;
41 import java.awt.event.MouseAdapter;
42 import java.awt.event.MouseEvent;
43 import java.awt.event.MouseListener;
44 import java.awt.event.MouseMotionAdapter;
45 import java.awt.event.WindowAdapter;
46 import java.awt.event.WindowEvent;
47 import java.beans.PropertyChangeEvent;
48 import java.beans.PropertyChangeListener;
49 import java.io.EOFException;
50 import java.io.File;
51 import java.io.FileReader;
52 import java.io.FileWriter;
53 import java.io.IOException;
54 import java.io.ObjectInputStream;
55 import java.io.ObjectOutputStream;
56 import java.io.StringReader;
57 import java.io.UnsupportedEncodingException;
58 import java.net.URLEncoder;
59 import java.text.DateFormat;
60 import java.text.NumberFormat;
61 import java.text.SimpleDateFormat;
62 import java.util.ArrayList;
63 import java.util.Date;
64 import java.util.Enumeration;
65 import java.util.EventObject;
66 import java.util.HashMap;
67 import java.util.HashSet;
68 import java.util.Iterator;
69 import java.util.List;
70 import java.util.Locale;
71 import java.util.Map;
72 import java.util.Set;
73 import java.util.StringTokenizer;
74 import java.util.Vector;
75
76 import javax.swing.AbstractAction;
77 import javax.swing.AbstractListModel;
78 import javax.swing.Action;
79 import javax.swing.BorderFactory;
80 import javax.swing.Box;
81 import javax.swing.BoxLayout;
82 import javax.swing.ButtonGroup;
83 import javax.swing.ComboBoxEditor;
84 import javax.swing.ImageIcon;
85 import javax.swing.JButton;
86 import javax.swing.JCheckBoxMenuItem;
87 import javax.swing.JColorChooser;
88 import javax.swing.JComboBox;
89 import javax.swing.JComponent;
90 import javax.swing.JDialog;
91 import javax.swing.JEditorPane;
92 import javax.swing.JFrame;
93 import javax.swing.JLabel;
94 import javax.swing.JMenuItem;
95 import javax.swing.JPanel;
96 import javax.swing.JPopupMenu;
97 import javax.swing.JRadioButtonMenuItem;
98 import javax.swing.JScrollPane;
99 import javax.swing.JSeparator;
100 import javax.swing.JSplitPane;
101 import javax.swing.JTable;
102 import javax.swing.JTextField;
103 import javax.swing.JToolBar;
104 import javax.swing.KeyStroke;
105 import javax.swing.ListSelectionModel;
106 import javax.swing.MutableComboBoxModel;
107 import javax.swing.SwingConstants;
108 import javax.swing.SwingUtilities;
109 import javax.swing.UIManager;
110 import javax.swing.WindowConstants;
111 import javax.swing.event.CellEditorListener;
112 import javax.swing.event.ChangeEvent;
113 import javax.swing.event.DocumentEvent;
114 import javax.swing.event.DocumentListener;
115 import javax.swing.event.ListSelectionEvent;
116 import javax.swing.event.ListSelectionListener;
117 import javax.swing.event.PopupMenuEvent;
118 import javax.swing.event.PopupMenuListener;
119 import javax.swing.event.TableColumnModelEvent;
120 import javax.swing.event.TableColumnModelListener;
121 import javax.swing.event.TableModelEvent;
122 import javax.swing.event.TableModelListener;
123 import javax.swing.table.TableCellEditor;
124 import javax.swing.table.TableColumn;
125 import javax.swing.table.TableColumnModel;
126 import javax.swing.text.Document;
127
128 import org.apache.log4j.Level;
129 import org.apache.log4j.LogManager;
130 import org.apache.log4j.Logger;
131 import org.apache.log4j.PatternLayout;
132 import org.apache.log4j.chainsaw.color.ColorPanel;
133 import org.apache.log4j.chainsaw.color.RuleColorizer;
134 import org.apache.log4j.chainsaw.filter.FilterModel;
135 import org.apache.log4j.chainsaw.helper.SwingHelper;
136 import org.apache.log4j.chainsaw.icons.ChainsawIcons;
137 import org.apache.log4j.chainsaw.icons.LineIconFactory;
138 import org.apache.log4j.chainsaw.layout.DefaultLayoutFactory;
139 import org.apache.log4j.chainsaw.layout.EventDetailLayout;
140 import org.apache.log4j.chainsaw.layout.LayoutEditorPane;
141 import org.apache.log4j.chainsaw.messages.MessageCenter;
142 import org.apache.log4j.chainsaw.prefs.LoadSettingsEvent;
143 import org.apache.log4j.chainsaw.prefs.Profileable;
144 import org.apache.log4j.chainsaw.prefs.SaveSettingsEvent;
145 import org.apache.log4j.chainsaw.prefs.SettingsManager;
146 import org.apache.log4j.chainsaw.xstream.TableColumnConverter;
147 import org.apache.log4j.helpers.Constants;
148 import org.apache.log4j.rule.ColorRule;
149 import org.apache.log4j.rule.ExpressionRule;
150 import org.apache.log4j.rule.Rule;
151 import org.apache.log4j.spi.LoggingEvent;
152 import org.apache.log4j.spi.LoggingEventFieldResolver;
153
154 import com.thoughtworks.xstream.XStream;
155 import com.thoughtworks.xstream.io.xml.DomDriver;
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209 public class LogPanel extends DockablePanel implements EventBatchListener, Profileable {
210 private static final DateFormat TIMESTAMP_DATE_FORMAT = new SimpleDateFormat(Constants.TIMESTAMP_RULE_FORMAT);
211 private static final double DEFAULT_DETAIL_SPLIT_LOCATION = 0.71d;
212 private static final double DEFAULT_LOG_TREE_SPLIT_LOCATION = 0.2d;
213 private final String identifier;
214 private final ChainsawStatusBar statusBar;
215 private final JFrame logPanelPreferencesFrame = new JFrame();
216 private ColorPanel colorPanel;
217 private final JFrame colorFrame = new JFrame();
218 private final JFrame undockedFrame;
219 private final DockablePanel externalPanel;
220 private final Action dockingAction;
221 private final JToolBar undockedToolbar;
222 private final JSortTable table;
223 private final TableColorizingRenderer renderer;
224 private final EventContainer tableModel;
225 private final JEditorPane detail;
226 private final JSplitPane lowerPanel;
227 private final DetailPaneUpdater detailPaneUpdater;
228 private final JPanel detailPanel = new JPanel(new BorderLayout());
229 private final JSplitPane nameTreeAndMainPanelSplit;
230 private final LoggerNameTreePanel logTreePanel;
231 private final LogPanelPreferenceModel preferenceModel = new LogPanelPreferenceModel();
232 private ApplicationPreferenceModel applicationPreferenceModel;
233 private final LogPanelPreferencePanel logPanelPreferencesPanel;
234 private final FilterModel filterModel = new FilterModel();
235 private final RuleColorizer colorizer = new RuleColorizer();
236 private final RuleMediator tableRuleMediator = new RuleMediator(false);
237 private final RuleMediator searchRuleMediator = new RuleMediator(true);
238 private final EventDetailLayout detailLayout = new EventDetailLayout();
239 private double lastLogTreePanelSplitLocation = DEFAULT_LOG_TREE_SPLIT_LOCATION;
240 private Point currentPoint;
241 private JTable currentTable;
242 private boolean paused = false;
243 private Rule findRule;
244 private String currentFindRuleText;
245 private Rule findMarkerRule;
246 private final int dividerSize;
247 static final String TABLE_COLUMN_ORDER = "table.columns.order";
248 static final String TABLE_COLUMN_WIDTHS = "table.columns.widths";
249 static final String COLORS_EXTENSION = ".colors";
250 private static final int LOG_PANEL_SERIALIZATION_VERSION_NUMBER = 2;
251 private int previousLastIndex = -1;
252 private final Logger logger = LogManager.getLogger(LogPanel.class);
253 private AutoFilterComboBox filterCombo;
254 private AutoFilterComboBox findCombo;
255 private JScrollPane eventsPane;
256 private int currentSearchMatchCount;
257 private Rule clearTableExpressionRule;
258 private int lowerPanelDividerLocation;
259 private EventContainer searchModel;
260 private final JSortTable searchTable;
261 private TableColorizingRenderer searchRenderer;
262 private ToggleToolTips mainToggleToolTips;
263 private ToggleToolTips searchToggleToolTips;
264 private JScrollPane detailPane;
265 private JScrollPane searchPane;
266
267 private TableCellEditor markerCellEditor;
268 private JToolBar detailToolbar;
269 private boolean searchResultsDisplayed;
270 private ColorizedEventAndSearchMatchThumbnail colorizedEventAndSearchMatchThumbnail;
271 private EventTimeDeltaMatchThumbnail eventTimeDeltaMatchThumbnail;
272 private boolean isDetailPanelVisible;
273
274
275
276
277
278
279
280
281 public LogPanel(final ChainsawStatusBar statusBar, final String identifier, int cyclicBufferSize,
282 Map allColorizers, final ApplicationPreferenceModel applicationPreferenceModel) {
283 this.identifier = identifier;
284 this.statusBar = statusBar;
285 this.applicationPreferenceModel = applicationPreferenceModel;
286 this.logPanelPreferencesPanel = new LogPanelPreferencePanel(preferenceModel, applicationPreferenceModel);
287 logger.debug("creating logpanel for " + identifier);
288
289 setLayout(new BorderLayout());
290
291 String prototypeValue = "1231231231231231231231";
292
293 filterCombo = new AutoFilterComboBox();
294 findCombo = new AutoFilterComboBox();
295
296 filterCombo.setPrototypeDisplayValue(prototypeValue);
297 buildCombo(filterCombo, true, findCombo.model);
298
299 findCombo.setPrototypeDisplayValue(prototypeValue);
300 buildCombo(findCombo, false, filterCombo.model);
301
302 final Map columnNameKeywordMap = new HashMap();
303 columnNameKeywordMap.put(ChainsawConstants.CLASS_COL_NAME, LoggingEventFieldResolver.CLASS_FIELD);
304 columnNameKeywordMap.put(ChainsawConstants.FILE_COL_NAME, LoggingEventFieldResolver.FILE_FIELD);
305 columnNameKeywordMap.put(ChainsawConstants.LEVEL_COL_NAME, LoggingEventFieldResolver.LEVEL_FIELD);
306 columnNameKeywordMap.put(ChainsawConstants.LINE_COL_NAME, LoggingEventFieldResolver.LINE_FIELD);
307 columnNameKeywordMap.put(ChainsawConstants.LOGGER_COL_NAME, LoggingEventFieldResolver.LOGGER_FIELD);
308 columnNameKeywordMap.put(ChainsawConstants.NDC_COL_NAME, LoggingEventFieldResolver.NDC_FIELD);
309 columnNameKeywordMap.put(ChainsawConstants.MESSAGE_COL_NAME, LoggingEventFieldResolver.MSG_FIELD);
310 columnNameKeywordMap.put(ChainsawConstants.THREAD_COL_NAME, LoggingEventFieldResolver.THREAD_FIELD);
311 columnNameKeywordMap.put(ChainsawConstants.THROWABLE_COL_NAME, LoggingEventFieldResolver.EXCEPTION_FIELD);
312 columnNameKeywordMap.put(ChainsawConstants.TIMESTAMP_COL_NAME, LoggingEventFieldResolver.TIMESTAMP_FIELD);
313 columnNameKeywordMap.put(ChainsawConstants.ID_COL_NAME.toUpperCase(), LoggingEventFieldResolver.PROP_FIELD + Constants.LOG4J_ID_KEY);
314 columnNameKeywordMap.put(ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE.toUpperCase(), LoggingEventFieldResolver.PROP_FIELD + ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE);
315 columnNameKeywordMap.put(ChainsawConstants.MILLIS_DELTA_COL_NAME_LOWERCASE.toUpperCase(), LoggingEventFieldResolver.PROP_FIELD + ChainsawConstants.MILLIS_DELTA_COL_NAME_LOWERCASE);
316
317 logPanelPreferencesFrame.setTitle("'" + identifier + "' Log Panel Preferences");
318 logPanelPreferencesFrame.setIconImage(
319 ((ImageIcon) ChainsawIcons.ICON_PREFERENCES).getImage());
320 logPanelPreferencesFrame.getContentPane().add(new JScrollPane(logPanelPreferencesPanel));
321
322 logPanelPreferencesFrame.setSize(740, 520);
323
324 logPanelPreferencesPanel.setOkCancelActionListener(
325 new ActionListener() {
326 public void actionPerformed(ActionEvent e) {
327 logPanelPreferencesFrame.setVisible(false);
328 }
329 });
330
331 KeyStroke escape = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
332 Action closeLogPanelPreferencesFrameAction = new AbstractAction() {
333 public void actionPerformed(ActionEvent e) {
334 logPanelPreferencesFrame.setVisible(false);
335 }
336 };
337 logPanelPreferencesFrame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(escape, "ESCAPE"); logPanelPreferencesFrame.getRootPane().
338 getActionMap().put("ESCAPE", closeLogPanelPreferencesFrameAction);
339
340
341 setDetailPaneConversionPattern(
342 DefaultLayoutFactory.getDefaultPatternLayout());
343 detailLayout.setConversionPattern(
344 DefaultLayoutFactory.getDefaultPatternLayout());
345
346 undockedFrame = new JFrame(identifier);
347 undockedFrame.setDefaultCloseOperation(
348 WindowConstants.DO_NOTHING_ON_CLOSE);
349
350 if (ChainsawIcons.UNDOCKED_ICON != null) {
351 undockedFrame.setIconImage(
352 new ImageIcon(ChainsawIcons.UNDOCKED_ICON).getImage());
353 }
354
355 externalPanel = new DockablePanel();
356 externalPanel.setLayout(new BorderLayout());
357
358 undockedFrame.addWindowListener(
359 new WindowAdapter() {
360 public void windowClosing(WindowEvent e) {
361 dock();
362 }
363 });
364
365 undockedToolbar = createDockwindowToolbar();
366 externalPanel.add(undockedToolbar, BorderLayout.NORTH);
367 undockedFrame.getContentPane().add(externalPanel);
368 undockedFrame.setSize(new Dimension(1024, 768));
369 undockedFrame.pack();
370
371 preferenceModel.addPropertyChangeListener(
372 "scrollToBottom",
373 new PropertyChangeListener() {
374 public void propertyChange(PropertyChangeEvent evt) {
375 boolean value = ((Boolean) evt.getNewValue()).booleanValue();
376 if (value) {
377 scrollToBottom();
378 }
379 }
380 });
381
382
383
384
385
386
387
388
389 final JPopupMenu dateFormatChangePopup = new JPopupMenu();
390 final JRadioButtonMenuItem isoButton =
391 new JRadioButtonMenuItem(
392 new AbstractAction("Use ISO8601Format") {
393 public void actionPerformed(ActionEvent e) {
394 preferenceModel.setDateFormatPattern("ISO8601");
395 }
396 });
397 final JRadioButtonMenuItem simpleTimeButton =
398 new JRadioButtonMenuItem(
399 new AbstractAction("Use simple time") {
400 public void actionPerformed(ActionEvent e) {
401 preferenceModel.setDateFormatPattern("HH:mm:ss");
402 }
403 });
404
405 ButtonGroup dfBG = new ButtonGroup();
406 dfBG.add(isoButton);
407 dfBG.add(simpleTimeButton);
408 simpleTimeButton.setSelected(true);
409 dateFormatChangePopup.add(isoButton);
410 dateFormatChangePopup.add(simpleTimeButton);
411
412 final JCheckBoxMenuItem menuItemLoggerTree =
413 new JCheckBoxMenuItem("Show Logger Tree");
414 menuItemLoggerTree.addActionListener(
415 new ActionListener() {
416 public void actionPerformed(ActionEvent e) {
417 preferenceModel.setLogTreePanelVisible(
418 menuItemLoggerTree.isSelected());
419 }
420 });
421 menuItemLoggerTree.setIcon(new ImageIcon(ChainsawIcons.WINDOW_ICON));
422
423 final JCheckBoxMenuItem menuItemToggleDetails =
424 new JCheckBoxMenuItem("Show Detail Pane");
425 menuItemToggleDetails.addActionListener(
426 new ActionListener() {
427 public void actionPerformed(ActionEvent e) {
428 preferenceModel.setDetailPaneVisible(
429 menuItemToggleDetails.isSelected());
430 }
431 });
432
433 menuItemToggleDetails.setIcon(new ImageIcon(ChainsawIcons.INFO));
434
435
436
437
438 preferenceModel.addPropertyChangeListener("levelIcons",
439 new PropertyChangeListener() {
440 public void propertyChange(PropertyChangeEvent evt) {
441 boolean useIcons = ((Boolean) evt.getNewValue()).booleanValue();
442 renderer.setLevelUseIcons(useIcons);
443 table.tableChanged(new TableModelEvent(tableModel));
444 searchRenderer.setLevelUseIcons(useIcons);
445 searchTable.tableChanged(new TableModelEvent(searchModel));
446 }
447 });
448
449
450
451
452 preferenceModel.addPropertyChangeListener("wrapMessage",
453 new PropertyChangeListener() {
454 public void propertyChange(PropertyChangeEvent evt) {
455 boolean wrap = ((Boolean) evt.getNewValue()).booleanValue();
456 renderer.setWrapMessage(wrap);
457 table.tableChanged(new TableModelEvent(tableModel));
458 searchRenderer.setWrapMessage(wrap);
459 searchTable.tableChanged(new TableModelEvent(searchModel));
460 }
461 });
462
463 preferenceModel.addPropertyChangeListener("searchResultsVisible",
464 new PropertyChangeListener() {
465 public void propertyChange(PropertyChangeEvent evt) {
466 boolean displaySearchResultsInDetailsIfAvailable = ((Boolean) evt.getNewValue()).booleanValue();
467 if (displaySearchResultsInDetailsIfAvailable) {
468 showSearchResults();
469 } else {
470 hideSearchResults();
471 }
472 }
473 });
474
475 preferenceModel.addPropertyChangeListener("highlightSearchMatchText",
476 new PropertyChangeListener() {
477 public void propertyChange(PropertyChangeEvent evt) {
478 boolean highlightText = ((Boolean) evt.getNewValue()).booleanValue();
479 renderer.setHighlightSearchMatchText(highlightText);
480 table.tableChanged(new TableModelEvent(tableModel));
481 searchRenderer.setHighlightSearchMatchText(highlightText);
482 searchTable.tableChanged(new TableModelEvent(searchModel));
483 }
484 });
485
486 preferenceModel.addPropertyChangeListener(
487 "detailPaneVisible",
488 new PropertyChangeListener() {
489 public void propertyChange(PropertyChangeEvent evt) {
490 boolean detailPaneVisible = ((Boolean) evt.getNewValue()).booleanValue();
491
492 if (detailPaneVisible) {
493 showDetailPane();
494 } else {
495
496 if (!searchResultsDisplayed) {
497 hideDetailPane();
498 }
499 }
500 }
501 });
502
503 preferenceModel.addPropertyChangeListener(
504 "logTreePanelVisible",
505 new PropertyChangeListener() {
506 public void propertyChange(PropertyChangeEvent evt) {
507 boolean newValue = ((Boolean) evt.getNewValue()).booleanValue();
508
509 if (newValue) {
510 showLogTreePanel();
511 } else {
512 hideLogTreePanel();
513 }
514 }
515 });
516
517 preferenceModel.addPropertyChangeListener("toolTips",
518 new PropertyChangeListener() {
519 public void propertyChange(PropertyChangeEvent evt) {
520 boolean toolTips = ((Boolean) evt.getNewValue()).booleanValue();
521 renderer.setToolTipsVisible(toolTips);
522 searchRenderer.setToolTipsVisible(toolTips);
523 }
524 });
525
526 preferenceModel.addPropertyChangeListener("visibleColumns",
527 new PropertyChangeListener() {
528 public void propertyChange(PropertyChangeEvent evt) {
529
530 TableColumnModel columnModel = table.getColumnModel();
531 while (columnModel.getColumnCount() > 0) {
532 columnModel.removeColumn(columnModel.getColumn(0));
533 }
534 for (Iterator iter = preferenceModel.getVisibleColumnOrder().iterator();iter.hasNext();) {
535 TableColumn c = (TableColumn)iter.next();
536 if (c.getHeaderValue().toString().equalsIgnoreCase(ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE))
537 {
538 c.setCellEditor(markerCellEditor);
539 }
540 columnModel.addColumn(c);
541 }
542 TableColumnModel searchColumnModel = searchTable.getColumnModel();
543 while (searchColumnModel.getColumnCount() > 0) {
544 searchColumnModel.removeColumn(searchColumnModel.getColumn(0));
545 }
546 for (Iterator iter = preferenceModel.getVisibleColumnOrder().iterator();iter.hasNext();) {
547 TableColumn c = (TableColumn)iter.next();
548 searchColumnModel.addColumn(c);
549 }
550 }
551 });
552
553 PropertyChangeListener datePrefsChangeListener =
554 new PropertyChangeListener() {
555 public void propertyChange(PropertyChangeEvent evt) {
556 LogPanelPreferenceModel model = (LogPanelPreferenceModel) evt.getSource();
557
558 isoButton.setSelected(model.isUseISO8601Format());
559 simpleTimeButton.setSelected(!model.isUseISO8601Format() && !model.isCustomDateFormat());
560
561 if (model.getTimeZone() != null) {
562 renderer.setTimeZone(model.getTimeZone());
563 searchRenderer.setTimeZone(model.getTimeZone());
564 }
565
566 if (model.isUseISO8601Format()) {
567 renderer.setDateFormatter(new SimpleDateFormat(Constants.ISO8601_PATTERN));
568 searchRenderer.setDateFormatter(new SimpleDateFormat(Constants.ISO8601_PATTERN));
569 } else {
570 try {
571 renderer.setDateFormatter(new SimpleDateFormat(model.getDateFormatPattern()));
572 } catch (IllegalArgumentException iae) {
573 model.setDefaultDatePatternFormat();
574 renderer.setDateFormatter(new SimpleDateFormat(Constants.ISO8601_PATTERN));
575 }
576 try {
577 searchRenderer.setDateFormatter(new SimpleDateFormat(model.getDateFormatPattern()));
578 } catch (IllegalArgumentException iae) {
579 model.setDefaultDatePatternFormat();
580 searchRenderer.setDateFormatter(new SimpleDateFormat(Constants.ISO8601_PATTERN));
581 }
582 }
583
584 table.tableChanged(new TableModelEvent(tableModel));
585 searchTable.tableChanged(new TableModelEvent(searchModel));
586 }
587 };
588
589 preferenceModel.addPropertyChangeListener("dateFormatPattern", datePrefsChangeListener);
590 preferenceModel.addPropertyChangeListener("dateFormatTimeZone", datePrefsChangeListener);
591
592 preferenceModel.addPropertyChangeListener("clearTableExpression", new PropertyChangeListener() {
593 public void propertyChange(PropertyChangeEvent evt) {
594 LogPanelPreferenceModel model = (LogPanelPreferenceModel)evt.getSource();
595 String expression = model.getClearTableExpression();
596 try {
597 clearTableExpressionRule = ExpressionRule.getRule(expression);
598 logger.info("clearTableExpressionRule set to: " + expression);
599 } catch (Exception e) {
600 logger.info("clearTableExpressionRule invalid - ignoring: " + expression);
601 clearTableExpressionRule = null;
602 }
603 }
604 });
605
606 preferenceModel.addPropertyChangeListener("loggerPrecision",
607 new PropertyChangeListener() {
608 public void propertyChange(PropertyChangeEvent evt) {
609 LogPanelPreferenceModel model = (LogPanelPreferenceModel) evt.getSource();
610
611 renderer.setLoggerPrecision(model.getLoggerPrecision());
612 table.tableChanged(new TableModelEvent(tableModel));
613
614 searchRenderer.setLoggerPrecision(model.getLoggerPrecision());
615 searchTable.tableChanged(new TableModelEvent(searchModel));
616 }
617 });
618
619 preferenceModel.addPropertyChangeListener("toolTips",
620 new PropertyChangeListener() {
621 public void propertyChange(PropertyChangeEvent evt) {
622 boolean value = ((Boolean) evt.getNewValue()).booleanValue();
623 searchToggleToolTips.setSelected(value);
624 mainToggleToolTips.setSelected(value);
625 }
626 });
627
628 preferenceModel.addPropertyChangeListener(
629 "logTreePanelVisible",
630 new PropertyChangeListener() {
631 public void propertyChange(PropertyChangeEvent evt) {
632 boolean value = ((Boolean) evt.getNewValue()).booleanValue();
633 menuItemLoggerTree.setSelected(value);
634 }
635 });
636
637 preferenceModel.addPropertyChangeListener(
638 "detailPaneVisible",
639 new PropertyChangeListener() {
640 public void propertyChange(PropertyChangeEvent evt) {
641 boolean value = ((Boolean) evt.getNewValue()).booleanValue();
642 menuItemToggleDetails.setSelected(value);
643 }
644 });
645
646 applicationPreferenceModel.addPropertyChangeListener("searchColor", new PropertyChangeListener() {
647 public void propertyChange(PropertyChangeEvent evt)
648 {
649 if (table != null) {
650 table.repaint();
651 }
652 if (searchTable != null) {
653 searchTable.repaint();
654 }
655 }
656 });
657
658 applicationPreferenceModel.addPropertyChangeListener("alternatingColor", new PropertyChangeListener() {
659 public void propertyChange(PropertyChangeEvent evt)
660 {
661 if (table != null) {
662 table.repaint();
663 }
664 if (searchTable != null) {
665 searchTable.repaint();
666 }
667 }
668 });
669
670
671
672
673 tableModel = new ChainsawCyclicBufferTableModel(cyclicBufferSize, colorizer, "main");
674 table = new JSortTable(tableModel);
675
676 markerCellEditor = new MarkerCellEditor();
677 table.setName("main");
678 table.setColumnSelectionAllowed(false);
679 table.setRowSelectionAllowed(true);
680
681 searchModel = new ChainsawCyclicBufferTableModel(cyclicBufferSize, colorizer, "search");
682 searchTable = new JSortTable(searchModel);
683
684 searchTable.setName("search");
685 searchTable.setColumnSelectionAllowed(false);
686 searchTable.setRowSelectionAllowed(true);
687
688
689 table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke("F2"), "none");
690 table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, InputEvent.SHIFT_MASK), "none");
691 table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "none");
692 table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() | InputEvent.SHIFT_MASK), "none");
693
694
695 table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_A, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "none");
696
697 searchTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke("F2"), "none");
698 searchTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, InputEvent.SHIFT_MASK), "none");
699 searchTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "none");
700 searchTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() | InputEvent.SHIFT_MASK), "none");
701
702
703 searchTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_A, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "none");
704
705
706 tableModel.addNewKeyListener(new NewKeyListener() {
707 public void newKeyAdded(NewKeyEvent e) {
708 columnNameKeywordMap.put(e.getKey(), "PROP." + e.getKey());
709 }
710 });
711
712
713
714
715
716 tableModel.setRuleMediator(tableRuleMediator);
717 searchModel.setRuleMediator(searchRuleMediator);
718
719 tableModel.addEventCountListener(
720 new EventCountListener() {
721 public void eventCountChanged(int currentCount, int totalCount) {
722 if (LogPanel.this.isVisible()) {
723 statusBar.setSelectedLine(
724 table.getSelectedRow() + 1, currentCount, totalCount, getIdentifier());
725 }
726 }
727 });
728
729 tableModel.addEventCountListener(
730 new EventCountListener() {
731 final NumberFormat formatter = NumberFormat.getPercentInstance();
732 boolean warning75 = false;
733 boolean warning100 = false;
734
735 public void eventCountChanged(int currentCount, int totalCount) {
736 if (preferenceModel.isCyclic()) {
737 double percent =
738 ((double) totalCount) / ((ChainsawCyclicBufferTableModel) tableModel)
739 .getMaxSize();
740 String msg = null;
741 boolean wasWarning = warning75 || warning100;
742 if ((percent > 0.75) && (percent < 1.0) && !warning75) {
743 msg =
744 "Warning :: " + formatter.format(percent) + " of the '"
745 + getIdentifier() + "' buffer has been used";
746 warning75 = true;
747 } else if ((percent >= 1.0) && !warning100) {
748 msg =
749 "Warning :: " + formatter.format(percent) + " of the '"
750 + getIdentifier()
751 + "' buffer has been used. Older events are being discarded.";
752 warning100 = true;
753 } else {
754
755 msg = "";
756 warning75 = false;
757 warning100 = false;
758 }
759
760 if (msg != null && wasWarning) {
761 MessageCenter.getInstance().getLogger().info(msg);
762 }
763 }
764 }
765 });
766
767
768
769
770
771 LogPanelLoggerTreeModel logTreeModel = new LogPanelLoggerTreeModel();
772 logTreePanel = new LoggerNameTreePanel(logTreeModel, preferenceModel, this, colorizer, filterModel);
773 logTreePanel.getLoggerVisibilityRule().addPropertyChangeListener(new PropertyChangeListener()
774 {
775 public void propertyChange(PropertyChangeEvent evt)
776 {
777 if (evt.getPropertyName().equals("searchExpression")) {
778 findCombo.setSelectedItem(evt.getNewValue().toString());
779 findNext();
780 }
781 }
782 });
783
784 tableModel.addLoggerNameListener(logTreeModel);
785 tableModel.addLoggerNameListener(logTreePanel);
786
787
788
789
790
791
792 tableRuleMediator.setLoggerRule(logTreePanel.getLoggerVisibilityRule());
793 searchRuleMediator.setLoggerRule(logTreePanel.getLoggerVisibilityRule());
794
795 colorizer.setLoggerRule(logTreePanel.getLoggerColorRule());
796
797
798
799
800 colorFrame.setTitle("'" + identifier + "' color settings");
801 colorFrame.setIconImage(
802 ((ImageIcon) ChainsawIcons.ICON_PREFERENCES).getImage());
803
804 allColorizers.put(identifier, colorizer);
805 colorPanel = new ColorPanel(colorizer, filterModel, allColorizers, applicationPreferenceModel);
806
807 colorFrame.getContentPane().add(colorPanel);
808
809 Action closeColorPanelAction = new AbstractAction() {
810 public void actionPerformed(ActionEvent e) {
811 colorPanel.hidePanel();
812 }
813 };
814 colorFrame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(escape, "ESCAPE"); colorFrame.getRootPane().
815 getActionMap().put("ESCAPE", closeColorPanelAction);
816
817 colorPanel.setCloseActionListener(
818 new ActionListener() {
819 public void actionPerformed(ActionEvent e) {
820 colorFrame.setVisible(false);
821 }
822 });
823
824 colorizer.addPropertyChangeListener(
825 "colorrule",
826 new PropertyChangeListener() {
827 public void propertyChange(PropertyChangeEvent evt) {
828 for (Iterator iter = tableModel.getAllEvents().iterator();iter.hasNext();) {
829 LoggingEventWrapper loggingEventWrapper = (LoggingEventWrapper)iter.next();
830 loggingEventWrapper.updateColorRuleColors(colorizer.getBackgroundColor(loggingEventWrapper.getLoggingEvent()), colorizer.getForegroundColor(loggingEventWrapper.getLoggingEvent()));
831 }
832
833
834
835
836
837
838
839 colorizedEventAndSearchMatchThumbnail.configureColors();
840 lowerPanel.revalidate();
841 lowerPanel.repaint();
842
843 searchTable.revalidate();
844 searchTable.repaint();
845 }
846 });
847
848
849
850
851 table.setRowHeight(ChainsawConstants.DEFAULT_ROW_HEIGHT);
852 table.setRowMargin(0);
853 table.getColumnModel().setColumnMargin(0);
854 table.setShowGrid(false);
855 table.getColumnModel().addColumnModelListener(new ChainsawTableColumnModelListener(table));
856 table.setAutoCreateColumnsFromModel(false);
857 table.addMouseMotionListener(new TableColumnDetailMouseListener(table, tableModel));
858 table.addMouseListener(new TableMarkerListener(table, tableModel, searchModel));
859 table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
860
861 searchTable.setRowHeight(ChainsawConstants.DEFAULT_ROW_HEIGHT);
862 searchTable.setRowMargin(0);
863 searchTable.getColumnModel().setColumnMargin(0);
864 searchTable.setShowGrid(false);
865 searchTable.getColumnModel().addColumnModelListener(new ChainsawTableColumnModelListener(searchTable));
866 searchTable.setAutoCreateColumnsFromModel(false);
867 searchTable.addMouseMotionListener(new TableColumnDetailMouseListener(searchTable, searchModel));
868 searchTable.addMouseListener(new TableMarkerListener(searchTable, searchModel, tableModel));
869 searchTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
870
871
872
873 table.addKeyListener(
874 new KeyListener() {
875 public void keyTyped(KeyEvent e) {
876 }
877
878 public void keyPressed(KeyEvent e) {
879 synchronized (detail) {
880 table.getSelectionModel().setValueIsAdjusting(true);
881 detail.notify();
882 }
883 }
884
885 public void keyReleased(KeyEvent e) {
886 synchronized (detail) {
887 table.getSelectionModel().setValueIsAdjusting(false);
888 detail.notify();
889 }
890 }
891 });
892
893 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
894 searchTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
895
896 table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
897 public void valueChanged(ListSelectionEvent evt) {
898 if (((evt.getFirstIndex() == evt.getLastIndex())
899 && (evt.getFirstIndex() > 0) && previousLastIndex != -1) || (evt.getValueIsAdjusting())) {
900 return;
901 }
902 boolean lastIndexOnLastRow = (evt.getLastIndex() == (table.getRowCount() - 1));
903 boolean lastIndexSame = (previousLastIndex == evt.getLastIndex());
904
905
906
907
908
909
910
911
912
913
914
915
916 boolean disableScrollToBottom = (lastIndexOnLastRow && lastIndexSame && previousLastIndex != evt.getFirstIndex());
917 if (disableScrollToBottom && isScrollToBottom() && table.getRowCount() > 0) {
918 preferenceModel.setScrollToBottom(false);
919 }
920 previousLastIndex = evt.getLastIndex();
921 }
922 }
923 );
924
925 table.getSelectionModel().addListSelectionListener(
926 new ListSelectionListener() {
927 public void valueChanged(ListSelectionEvent evt) {
928 if (((evt.getFirstIndex() == evt.getLastIndex())
929 && (evt.getFirstIndex() > 0) && previousLastIndex != -1) || (evt.getValueIsAdjusting())) {
930 return;
931 }
932
933 final ListSelectionModel lsm = (ListSelectionModel) evt.getSource();
934
935 if (lsm.isSelectionEmpty()) {
936 if (isVisible()) {
937 statusBar.setNothingSelected();
938 }
939
940 if (detail.getDocument().getDefaultRootElement() != null) {
941 detailPaneUpdater.setSelectedRow(-1);
942 }
943 } else {
944 if (table.getSelectedRow() > -1) {
945 int selectedRow = table.getSelectedRow();
946
947 if (isVisible()) {
948 updateStatusBar();
949 }
950
951 try {
952 if (tableModel.getRowCount() >= selectedRow) {
953 detailPaneUpdater.setSelectedRow(table.getSelectedRow());
954 } else {
955 detailPaneUpdater.setSelectedRow(-1);
956 }
957 } catch (Exception e) {
958 e.printStackTrace();
959 detailPaneUpdater.setSelectedRow(-1);
960 }
961 }
962 }
963 }
964 });
965
966 renderer = new TableColorizingRenderer(colorizer, applicationPreferenceModel, tableModel, preferenceModel, true);
967 renderer.setToolTipsVisible(preferenceModel.isToolTips());
968
969 table.setDefaultRenderer(Object.class, renderer);
970
971 searchRenderer = new TableColorizingRenderer(colorizer, applicationPreferenceModel, searchModel, preferenceModel, false);
972 searchRenderer.setToolTipsVisible(preferenceModel.isToolTips());
973
974 searchTable.setDefaultRenderer(Object.class, searchRenderer);
975
976
977
978
979 table.addMouseListener(new ThrowableDisplayMouseAdapter(table, tableModel));
980 searchTable.addMouseListener(new ThrowableDisplayMouseAdapter(searchTable, searchModel));
981
982
983 searchTable.addMouseListener(new MouseAdapter() {
984 public void mouseClicked(MouseEvent e) {
985 LoggingEventWrapper loggingEventWrapper = searchModel.getRow(searchTable.getSelectedRow());
986 if (loggingEventWrapper != null) {
987 int id = new Integer(loggingEventWrapper.getLoggingEvent().getProperty("log4jid")).intValue();
988
989 setSelectedEvent(id);
990 }
991 }
992 });
993
994
995
996
997
998 tableModel.addNewKeyListener(
999 new NewKeyListener() {
1000 public void newKeyAdded(final NewKeyEvent e) {
1001 SwingHelper.invokeOnEDT(new Runnable() {
1002 public void run() {
1003
1004
1005
1006
1007 try {
1008 if(table.getColumn(e.getKey())!=null){
1009 return;
1010 }
1011
1012 } catch (IllegalArgumentException iae) {}
1013 TableColumn col = new TableColumn(e.getNewModelIndex());
1014 col.setHeaderValue(e.getKey());
1015
1016 if (preferenceModel.addColumn(col)) {
1017 if (preferenceModel.isColumnVisible(col) || !applicationPreferenceModel.isDefaultColumnsSet() || applicationPreferenceModel.isDefaultColumnsSet() &&
1018 applicationPreferenceModel.getDefaultColumnNames().contains(col.getHeaderValue())) {
1019 table.addColumn(col);
1020 searchTable.addColumn(col);
1021 preferenceModel.setColumnVisible(e.getKey().toString(), true);
1022 }
1023 }
1024 }
1025 });
1026 }
1027 });
1028
1029
1030
1031
1032
1033 tableModel.addPropertyChangeListener("refilter", new PropertyChangeListener() {
1034 private LoggingEventWrapper currentEvent;
1035 public void propertyChange(PropertyChangeEvent evt) {
1036
1037
1038 if (evt.getNewValue().equals(Boolean.TRUE)) {
1039 int currentRow = table.getSelectedRow();
1040 if (currentRow > -1) {
1041 currentEvent = tableModel.getRow(currentRow);
1042 }
1043 } else {
1044 if (currentEvent != null) {
1045 table.scrollToRow(tableModel.getRowIndex(currentEvent));
1046 }
1047 }
1048 }
1049 });
1050
1051 table.getTableHeader().addMouseListener(
1052 new MouseAdapter() {
1053 public void mouseClicked(MouseEvent e) {
1054 checkEvent(e);
1055 }
1056
1057 public void mousePressed(MouseEvent e) {
1058 checkEvent(e);
1059 }
1060
1061 public void mouseReleased(MouseEvent e) {
1062 checkEvent(e);
1063 }
1064
1065 private void checkEvent(MouseEvent e) {
1066 if (e.isPopupTrigger()) {
1067 TableColumnModel colModel = table.getColumnModel();
1068 int index = colModel.getColumnIndexAtX(e.getX());
1069 int modelIndex = colModel.getColumn(index).getModelIndex();
1070
1071 if ((modelIndex + 1) == ChainsawColumns.INDEX_TIMESTAMP_COL_NAME) {
1072 dateFormatChangePopup.show(e.getComponent(), e.getX(), e.getY());
1073 }
1074 }
1075 }
1076 });
1077
1078
1079
1080
1081 JPanel upperPanel = new JPanel();
1082 upperPanel.setLayout(new BoxLayout(upperPanel, BoxLayout.X_AXIS));
1083 upperPanel.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 0));
1084
1085 final JLabel filterLabel = new JLabel("Refine focus on: ");
1086 filterLabel.setFont(filterLabel.getFont().deriveFont(Font.BOLD));
1087
1088 upperPanel.add(filterLabel);
1089 upperPanel.add(Box.createHorizontalStrut(3));
1090 upperPanel.add(filterCombo);
1091 upperPanel.add(Box.createHorizontalStrut(3));
1092
1093 final JTextField filterText =(JTextField) filterCombo.getEditor().getEditorComponent();
1094 final JTextField findText =(JTextField) findCombo.getEditor().getEditorComponent();
1095
1096
1097
1098 final JButton removeFilterButton = new JButton(" Remove ");
1099
1100 removeFilterButton.setToolTipText("Click here to remove the selected expression from the list");
1101 removeFilterButton.addActionListener(
1102 new AbstractAction() {
1103 public void actionPerformed(ActionEvent e){
1104 Object selectedItem = filterCombo.getSelectedItem();
1105 if (e.getSource() == removeFilterButton && selectedItem != null && !selectedItem.toString().trim().equals("")){
1106
1107 int index = filterCombo.getSelectedIndex();
1108 filterText.setText(null);
1109 filterCombo.setSelectedIndex(-1);
1110 filterCombo.removeItemAt(index);
1111 if (!(findCombo.getSelectedItem() != null && findCombo.getSelectedItem().equals(selectedItem))) {
1112
1113 ((AutoFilterComboBox.AutoFilterComboBoxModel)findCombo.getModel()).removeElement(selectedItem);
1114 }
1115 }
1116 }
1117 }
1118 );
1119 upperPanel.add(removeFilterButton);
1120
1121 upperPanel.add(Box.createHorizontalStrut(25));
1122
1123 final JLabel findLabel = new JLabel("Find: ");
1124 findLabel.setFont(filterLabel.getFont().deriveFont(Font.BOLD));
1125
1126 upperPanel.add(findLabel);
1127 upperPanel.add(Box.createHorizontalStrut(3));
1128
1129 upperPanel.add(findCombo);
1130 upperPanel.add(Box.createHorizontalStrut(3));
1131
1132 Action findNextAction = getFindNextAction();
1133 Action findPreviousAction = getFindPreviousAction();
1134
1135 JButton findNextButton = new SmallButton(findNextAction);
1136 findNextButton.setText("");
1137 findNextButton.getActionMap().put(
1138 findNextAction.getValue(Action.NAME), findNextAction);
1139 findNextButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
1140 (KeyStroke) findNextAction.getValue(Action.ACCELERATOR_KEY),
1141 findNextAction.getValue(Action.NAME));
1142
1143 JButton findPreviousButton = new SmallButton(findPreviousAction);
1144 findPreviousButton.setText("");
1145 findPreviousButton.getActionMap().put(
1146 findPreviousAction.getValue(Action.NAME), findPreviousAction);
1147 findPreviousButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
1148 (KeyStroke) findPreviousAction.getValue(Action.ACCELERATOR_KEY),
1149 findPreviousAction.getValue(Action.NAME));
1150
1151 upperPanel.add(findNextButton);
1152
1153 upperPanel.add(findPreviousButton);
1154 upperPanel.add(Box.createHorizontalStrut(3));
1155
1156
1157 final JButton removeFindButton = new JButton(" Remove ");
1158 removeFindButton.setToolTipText("Click here to remove the selected expression from the list");
1159 removeFindButton.addActionListener(
1160 new AbstractAction() {
1161 public void actionPerformed(ActionEvent e){
1162 Object selectedItem = findCombo.getSelectedItem();
1163 if (e.getSource() == removeFindButton && selectedItem != null && !selectedItem.toString().trim().equals("")){
1164
1165 int index = findCombo.getSelectedIndex();
1166 findText.setText(null);
1167 findCombo.setSelectedIndex(-1);
1168 findCombo.removeItemAt(index);
1169 if (!(filterCombo.getSelectedItem() != null && filterCombo.getSelectedItem().equals(selectedItem))) {
1170
1171 ((AutoFilterComboBox.AutoFilterComboBoxModel)filterCombo.getModel()).removeElement(selectedItem);
1172 }
1173 }
1174 }
1175 }
1176 );
1177 upperPanel.add(removeFindButton);
1178
1179
1180 Action findFocusAction = new AbstractAction() {
1181 public void actionPerformed(ActionEvent actionEvent) {
1182 findCombo.requestFocus();
1183 }
1184 };
1185
1186 Action filterFocusAction = new AbstractAction() {
1187 public void actionPerformed(ActionEvent actionEvent) {
1188 filterCombo.requestFocus();
1189 }
1190 };
1191
1192 Action findClearAction = new AbstractAction() {
1193 public void actionPerformed(ActionEvent actionEvent) {
1194 findCombo.setSelectedIndex(-1);
1195 findNext();
1196 }
1197 };
1198
1199 Action filterClearAction = new AbstractAction() {
1200 public void actionPerformed(ActionEvent actionEvent) {
1201 setRefineFocusText("");
1202 filterCombo.refilter();
1203 }
1204 };
1205
1206
1207 KeyStroke ksFindFocus =
1208 KeyStroke.getKeyStroke(KeyEvent.VK_F, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1209 KeyStroke ksFilterFocus =
1210 KeyStroke.getKeyStroke(KeyEvent.VK_R, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1211 KeyStroke ksFindClear =
1212 KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.SHIFT_MASK |Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1213 KeyStroke ksFilterClear =
1214 KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.SHIFT_MASK | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1215
1216 getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ksFindFocus, "FindFocus");
1217 getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ksFilterFocus, "FilterFocus");
1218 getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ksFindClear, "FindClear");
1219 getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ksFilterClear, "FilterClear");
1220
1221 getActionMap().put("FindFocus", findFocusAction);
1222 getActionMap().put("FilterFocus", filterFocusAction);
1223 getActionMap().put("FindClear", findClearAction);
1224 getActionMap().put("FilterClear", filterClearAction);
1225
1226
1227
1228
1229 detail = new JEditorPane(ChainsawConstants.DETAIL_CONTENT_TYPE, "");
1230 detail.setEditable(false);
1231
1232 detailPaneUpdater = new DetailPaneUpdater();
1233
1234
1235 addFocusListener(new FocusListener() {
1236
1237 public void focusGained(FocusEvent e) {
1238 detailPaneUpdater.updateDetailPane();
1239 }
1240
1241 public void focusLost(FocusEvent e) {
1242
1243 }
1244 });
1245 findMarkerRule = ExpressionRule.getRule("prop." + ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE + " exists");
1246
1247 tableModel.addTableModelListener(new TableModelListener() {
1248 public void tableChanged(TableModelEvent e) {
1249 int currentRow = table.getSelectedRow();
1250 if (e.getFirstRow() <= currentRow && e.getLastRow() >= currentRow) {
1251
1252 detailPaneUpdater.setAndUpdateSelectedRow(table.getSelectedRow());
1253 }
1254 }
1255 });
1256 addPropertyChangeListener("detailPaneConversionPattern", detailPaneUpdater);
1257
1258 searchPane = new JScrollPane(searchTable);
1259 searchPane.getVerticalScrollBar().setUnitIncrement(ChainsawConstants.DEFAULT_ROW_HEIGHT * 2);
1260 searchPane.setPreferredSize(new Dimension(900, 50));
1261
1262
1263 detailPane = new JScrollPane(detail);
1264 detailPane.setPreferredSize(new Dimension(900, 50));
1265
1266 detailPanel.add(detailPane, BorderLayout.CENTER);
1267
1268 JPanel eventsAndStatusPanel = new JPanel(new BorderLayout());
1269
1270 eventsPane = new JScrollPane(table);
1271 eventsPane.getVerticalScrollBar().setUnitIncrement(ChainsawConstants.DEFAULT_ROW_HEIGHT * 2);
1272
1273 eventsAndStatusPanel.add(eventsPane, BorderLayout.CENTER);
1274
1275 Integer scrollBarWidth = (Integer) UIManager.get("ScrollBar.width");
1276
1277 JPanel rightPanel = new JPanel();
1278 rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.Y_AXIS));
1279
1280 JPanel rightThumbNailPanel = new JPanel();
1281 rightThumbNailPanel.setLayout(new BoxLayout(rightThumbNailPanel, BoxLayout.Y_AXIS));
1282 rightThumbNailPanel.add(Box.createVerticalStrut(scrollBarWidth.intValue()));
1283 colorizedEventAndSearchMatchThumbnail = new ColorizedEventAndSearchMatchThumbnail();
1284 rightThumbNailPanel.add(colorizedEventAndSearchMatchThumbnail);
1285 rightThumbNailPanel.add(Box.createVerticalStrut(scrollBarWidth.intValue()));
1286 rightPanel.add(rightThumbNailPanel);
1287
1288 if (scrollBarWidth != null) {
1289 rightThumbNailPanel.setPreferredSize(new Dimension(scrollBarWidth.intValue() -4, -1));
1290 }
1291 eventsAndStatusPanel.add(rightPanel, BorderLayout.EAST);
1292
1293 JPanel leftPanel = new JPanel();
1294 leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.Y_AXIS));
1295
1296 JPanel leftThumbNailPanel = new JPanel();
1297 leftThumbNailPanel.setLayout(new BoxLayout(leftThumbNailPanel, BoxLayout.Y_AXIS));
1298 leftThumbNailPanel.add(Box.createVerticalStrut(scrollBarWidth.intValue()));
1299 eventTimeDeltaMatchThumbnail = new EventTimeDeltaMatchThumbnail();
1300 leftThumbNailPanel.add(eventTimeDeltaMatchThumbnail);
1301 leftThumbNailPanel.add(Box.createVerticalStrut(scrollBarWidth.intValue()));
1302 leftPanel.add(leftThumbNailPanel);
1303
1304
1305 if (scrollBarWidth != null) {
1306 leftThumbNailPanel.setPreferredSize(new Dimension(scrollBarWidth.intValue() -4, -1));
1307 }
1308 eventsAndStatusPanel.add(leftPanel, BorderLayout.WEST);
1309
1310 final JPanel statusLabelPanel = new JPanel();
1311 statusLabelPanel.setLayout(new BorderLayout());
1312
1313 statusLabelPanel.add(upperPanel, BorderLayout.CENTER);
1314 eventsAndStatusPanel.add(statusLabelPanel, BorderLayout.NORTH);
1315
1316
1317
1318
1319 detailToolbar = new JToolBar(SwingConstants.HORIZONTAL);
1320 detailToolbar.setFloatable(false);
1321
1322 final LayoutEditorPane layoutEditorPane = new LayoutEditorPane();
1323 final JDialog layoutEditorDialog =
1324 new JDialog((JFrame) null, "Pattern Editor");
1325 layoutEditorDialog.getContentPane().add(layoutEditorPane);
1326 layoutEditorDialog.setSize(640, 480);
1327
1328 layoutEditorPane.addCancelActionListener(
1329 new ActionListener() {
1330 public void actionPerformed(ActionEvent e) {
1331 layoutEditorDialog.setVisible(false);
1332 }
1333 });
1334
1335 layoutEditorPane.addOkActionListener(
1336 new ActionListener() {
1337 public void actionPerformed(ActionEvent e) {
1338 setDetailPaneConversionPattern(
1339 layoutEditorPane.getConversionPattern());
1340 layoutEditorDialog.setVisible(false);
1341 }
1342 });
1343
1344 Action copyToRefineFocusAction = new AbstractAction("Set 'refine focus' field") {
1345 public void actionPerformed(ActionEvent e) {
1346 String selectedText = detail.getSelectedText();
1347 if (selectedText == null || selectedText.equals("")) {
1348
1349 return;
1350 }
1351 filterText.setText("msg ~= '" + selectedText + "'");
1352 }
1353 };
1354
1355 Action copyToSearchAction = new AbstractAction("Find next") {
1356 public void actionPerformed(ActionEvent e) {
1357 String selectedText = detail.getSelectedText();
1358 if (selectedText == null || selectedText.equals("")) {
1359
1360 return;
1361 }
1362 findCombo.setSelectedItem("msg ~= '" + selectedText + "'");
1363 findNext();
1364 }
1365 };
1366
1367 Action editDetailAction =
1368 new AbstractAction(
1369 "Edit...", new ImageIcon(ChainsawIcons.ICON_EDIT_RECEIVER)) {
1370 public void actionPerformed(ActionEvent e) {
1371 layoutEditorPane.setConversionPattern(
1372 getDetailPaneConversionPattern());
1373
1374 Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
1375 Point p =
1376 new Point(
1377 ((int) ((size.getWidth() / 2)
1378 - (layoutEditorDialog.getSize().getWidth() / 2))),
1379 ((int) ((size.getHeight() / 2)
1380 - (layoutEditorDialog.getSize().getHeight() / 2))));
1381 layoutEditorDialog.setLocation(p);
1382
1383 layoutEditorDialog.setVisible(true);
1384 }
1385 };
1386
1387 editDetailAction.putValue(
1388 Action.SHORT_DESCRIPTION,
1389 "opens a Dialog window to Edit the Pattern Layout text");
1390
1391 final SmallButton editDetailButton = new SmallButton(editDetailAction);
1392 editDetailButton.setText(null);
1393 detailToolbar.add(Box.createHorizontalGlue());
1394 detailToolbar.add(editDetailButton);
1395 detailToolbar.addSeparator();
1396 detailToolbar.add(Box.createHorizontalStrut(5));
1397
1398 Action closeDetailAction =
1399 new AbstractAction(null, LineIconFactory.createCloseIcon()) {
1400 public void actionPerformed(ActionEvent arg0) {
1401 preferenceModel.setDetailPaneVisible(false);
1402 }
1403 };
1404
1405 closeDetailAction.putValue(
1406 Action.SHORT_DESCRIPTION, "Hides the Detail Panel");
1407
1408 SmallButton closeDetailButton = new SmallButton(closeDetailAction);
1409 detailToolbar.add(closeDetailButton);
1410
1411 detailPanel.add(detailToolbar, BorderLayout.NORTH);
1412
1413 lowerPanel = new JSplitPane(JSplitPane.VERTICAL_SPLIT, eventsAndStatusPanel, detailPanel);
1414
1415 dividerSize = lowerPanel.getDividerSize();
1416 lowerPanel.setDividerLocation(-1);
1417
1418 lowerPanel.setResizeWeight(1.0);
1419 lowerPanel.setBorder(null);
1420 lowerPanel.setContinuousLayout(true);
1421
1422 JPopupMenu editDetailPopupMenu = new JPopupMenu();
1423
1424 editDetailPopupMenu.add(copyToRefineFocusAction);
1425 editDetailPopupMenu.add(copyToSearchAction);
1426 editDetailPopupMenu.addSeparator();
1427
1428 editDetailPopupMenu.add(editDetailAction);
1429 editDetailPopupMenu.addSeparator();
1430
1431 final ButtonGroup layoutGroup = new ButtonGroup();
1432
1433 JRadioButtonMenuItem defaultLayoutRadio =
1434 new JRadioButtonMenuItem(
1435 new AbstractAction("Set to Default Layout") {
1436 public void actionPerformed(ActionEvent e) {
1437 setDetailPaneConversionPattern(
1438 DefaultLayoutFactory.getDefaultPatternLayout());
1439 }
1440 });
1441
1442 JRadioButtonMenuItem fullLayoutRadio =
1443 new JRadioButtonMenuItem(
1444 new AbstractAction("Set to Full Layout") {
1445 public void actionPerformed(ActionEvent e) {
1446 setDetailPaneConversionPattern(
1447 DefaultLayoutFactory.getFullPatternLayout());
1448 }
1449 });
1450
1451 editDetailPopupMenu.add(defaultLayoutRadio);
1452 editDetailPopupMenu.add(fullLayoutRadio);
1453
1454 layoutGroup.add(defaultLayoutRadio);
1455 layoutGroup.add(fullLayoutRadio);
1456 defaultLayoutRadio.setSelected(true);
1457
1458 JRadioButtonMenuItem tccLayoutRadio =
1459 new JRadioButtonMenuItem(
1460 new AbstractAction("Set to TCCLayout") {
1461 public void actionPerformed(ActionEvent e) {
1462 setDetailPaneConversionPattern(
1463 PatternLayout.TTCC_CONVERSION_PATTERN);
1464 }
1465 });
1466 editDetailPopupMenu.add(tccLayoutRadio);
1467 layoutGroup.add(tccLayoutRadio);
1468
1469 PopupListener editDetailPopupListener =
1470 new PopupListener(editDetailPopupMenu);
1471 detail.addMouseListener(editDetailPopupListener);
1472
1473
1474
1475
1476 nameTreeAndMainPanelSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, logTreePanel, lowerPanel);
1477 nameTreeAndMainPanelSplit.setDividerLocation(-1);
1478
1479 add(nameTreeAndMainPanelSplit, BorderLayout.CENTER);
1480
1481 if (isLogTreeVisible()) {
1482 showLogTreePanel();
1483 } else {
1484 hideLogTreePanel();
1485 }
1486
1487
1488
1489
1490 class BestFit extends JMenuItem {
1491 public BestFit() {
1492 super("Best fit column");
1493 addActionListener(
1494 new ActionListener() {
1495 public void actionPerformed(ActionEvent evt) {
1496 if (currentPoint != null) {
1497 int column = currentTable.columnAtPoint(currentPoint);
1498 int maxWidth = getMaxColumnWidth(column);
1499 currentTable.getColumnModel().getColumn(column).setPreferredWidth(
1500 maxWidth);
1501 }
1502 }
1503 });
1504 }
1505 }
1506
1507 class ColorPanel extends JMenuItem {
1508 public ColorPanel() {
1509 super("Color settings...");
1510 setIcon(ChainsawIcons.ICON_PREFERENCES);
1511 addActionListener(
1512 new ActionListener() {
1513 public void actionPerformed(ActionEvent evt) {
1514 showColorPreferences();
1515 }
1516 });
1517 }
1518 }
1519
1520 class LogPanelPreferences extends JMenuItem {
1521 public LogPanelPreferences() {
1522 super("Tab Preferences...");
1523 setIcon(ChainsawIcons.ICON_PREFERENCES);
1524 addActionListener(
1525 new ActionListener() {
1526 public void actionPerformed(ActionEvent evt) {
1527 showPreferences();
1528 }
1529 });
1530 }
1531 }
1532
1533 class FocusOn extends JMenuItem {
1534 public FocusOn() {
1535 super("Set 'refine focus' field to value under pointer");
1536 addActionListener(
1537 new ActionListener() {
1538 public void actionPerformed(ActionEvent evt) {
1539 if (currentPoint != null) {
1540 String operator = "==";
1541 int column = currentTable.columnAtPoint(currentPoint);
1542 int row = currentTable.rowAtPoint(currentPoint);
1543 String colName = currentTable.getColumnName(column).toUpperCase();
1544 String value = getValueOf(row, column);
1545
1546 if (columnNameKeywordMap.containsKey(colName)) {
1547 filterText.setText(
1548 columnNameKeywordMap.get(colName).toString() + " " + operator
1549 + " '" + value + "'");
1550 }
1551 }
1552 }
1553 });
1554 }
1555 }
1556
1557 class DefineAddCustomFilter extends JMenuItem {
1558 public DefineAddCustomFilter() {
1559 super("Add value under pointer to 'refine focus' field");
1560 addActionListener(
1561 new ActionListener() {
1562 public void actionPerformed(ActionEvent evt) {
1563 if (currentPoint != null) {
1564 String operator = "==";
1565 int column = currentTable.columnAtPoint(currentPoint);
1566 int row = currentTable.rowAtPoint(currentPoint);
1567 String value = getValueOf(row, column);
1568 String colName = currentTable.getColumnName(column).toUpperCase();
1569
1570 if (columnNameKeywordMap.containsKey(colName)) {
1571 filterText.setText(
1572 filterText.getText() + " && "
1573 + columnNameKeywordMap.get(colName).toString() + " "
1574 + operator + " '" + value + "'");
1575 }
1576
1577 }
1578 }
1579 });
1580 }
1581 }
1582
1583 class DefineAddCustomFind extends JMenuItem {
1584 public DefineAddCustomFind() {
1585 super("Add value under pointer to 'find' field");
1586 addActionListener(
1587 new ActionListener() {
1588 public void actionPerformed(ActionEvent evt) {
1589 if (currentPoint != null) {
1590 String operator = "==";
1591 int column = currentTable.columnAtPoint(currentPoint);
1592 int row = currentTable.rowAtPoint(currentPoint);
1593 String value = getValueOf(row, column);
1594 String colName = currentTable.getColumnName(column).toUpperCase();
1595
1596 if (columnNameKeywordMap.containsKey(colName)) {
1597 findCombo.setSelectedItem(
1598 findText.getText() + " && "
1599 + columnNameKeywordMap.get(colName).toString() + " "
1600 + operator + " '" + value + "'");
1601 findNext();
1602 }
1603 }
1604 }
1605 });
1606 }
1607 }
1608
1609 class BuildColorRule extends JMenuItem {
1610 public BuildColorRule() {
1611 super("Define color rule for value under pointer");
1612 addActionListener(
1613 new ActionListener() {
1614 public void actionPerformed(ActionEvent evt) {
1615 if (currentPoint != null) {
1616 String operator = "==";
1617 int column = currentTable.columnAtPoint(currentPoint);
1618 int row = currentTable.rowAtPoint(currentPoint);
1619 String colName = currentTable.getColumnName(column).toUpperCase();
1620 String value = getValueOf(row, column);
1621
1622 if (columnNameKeywordMap.containsKey(colName)) {
1623 Color c = JColorChooser.showDialog(getRootPane(), "Choose a color", Color.red);
1624 if (c != null) {
1625 String expression = columnNameKeywordMap.get(colName).toString() + " " + operator + " '" + value + "'";
1626 colorizer.addRule(ChainsawConstants.DEFAULT_COLOR_RULE_NAME, new ColorRule(expression,
1627 ExpressionRule.getRule(expression), c, ChainsawConstants.COLOR_DEFAULT_FOREGROUND));
1628 }
1629 }
1630 }
1631 }
1632 });
1633 }
1634 }
1635
1636 final JPopupMenu mainPopup = new JPopupMenu();
1637 final JPopupMenu searchPopup = new JPopupMenu();
1638
1639 class ClearFocus extends AbstractAction {
1640 public ClearFocus() {
1641 super("Clear 'refine focus' field");
1642 }
1643 public void actionPerformed(ActionEvent e) {
1644 filterText.setText(null);
1645 tableRuleMediator.setFilterRule(null);
1646 searchRuleMediator.setFilterRule(null);
1647 }
1648 }
1649
1650 class CopySelection extends AbstractAction {
1651 public CopySelection() {
1652 super("Copy selection to clipboard");
1653 }
1654
1655 public void actionPerformed(ActionEvent e) {
1656 if (currentTable == null) {
1657 return;
1658 }
1659 int start = currentTable.getSelectionModel().getMinSelectionIndex();
1660 int end = currentTable.getSelectionModel().getMaxSelectionIndex();
1661 StringBuffer result = new StringBuffer();
1662 for (int row=start;row<end+1;row++) {
1663 for (int column=0;column<currentTable.getColumnCount();column++) {
1664 result.append(getValueOf(row, column));
1665 if (column != (currentTable.getColumnCount() - 1)) {
1666 result.append(" - ");
1667 }
1668 }
1669 result.append(System.getProperty("line.separator"));
1670 }
1671 StringSelection selection = new StringSelection(result.toString());
1672 Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
1673 clipboard.setContents(selection, null);
1674 }
1675 }
1676
1677 class CopyField extends AbstractAction {
1678 public CopyField() {
1679 super("Copy value under pointer to clipboard");
1680 }
1681
1682 public void actionPerformed(ActionEvent e) {
1683 if (currentPoint != null && currentTable != null) {
1684 int column = currentTable.columnAtPoint(currentPoint);
1685 int row = currentTable.rowAtPoint(currentPoint);
1686 String value = getValueOf(row, column);
1687 StringSelection selection = new StringSelection(value);
1688 Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
1689 clipboard.setContents(selection, null);
1690 }
1691 }
1692 }
1693 final JMenuItem menuItemToggleDock = new JMenuItem("Undock/dock");
1694
1695 dockingAction =
1696 new AbstractAction("Undock") {
1697 public void actionPerformed(ActionEvent evt) {
1698 if (isDocked()) {
1699 undock();
1700 } else {
1701 dock();
1702 }
1703 }
1704 };
1705 dockingAction.putValue(
1706 Action.SMALL_ICON, new ImageIcon(ChainsawIcons.UNDOCK));
1707 menuItemToggleDock.setAction(dockingAction);
1708
1709
1710
1711
1712 mainPopup.add(new FocusOn());
1713 searchPopup.add(new FocusOn());
1714 mainPopup.add(new DefineAddCustomFilter());
1715 searchPopup.add(new DefineAddCustomFilter());
1716 mainPopup.add(new ClearFocus());
1717 searchPopup.add(new ClearFocus());
1718
1719 mainPopup.add(new JSeparator());
1720 searchPopup.add(new JSeparator());
1721
1722 class Search extends JMenuItem {
1723 public Search() {
1724 super("Find value under pointer");
1725
1726 addActionListener(
1727 new ActionListener() {
1728 public void actionPerformed(ActionEvent evt) {
1729 if (currentPoint != null) {
1730 String operator = "==";
1731 int column = currentTable.columnAtPoint(currentPoint);
1732 int row = currentTable.rowAtPoint(currentPoint);
1733 String colName = currentTable.getColumnName(column).toUpperCase();
1734 String value = getValueOf(row, column);
1735 if (columnNameKeywordMap.containsKey(colName)) {
1736 findCombo.setSelectedItem(
1737 columnNameKeywordMap.get(colName).toString() + " " + operator
1738 + " '" + value + "'");
1739 findNext();
1740 }
1741 }
1742 }
1743 });
1744 }
1745 }
1746
1747 class ClearSearch extends AbstractAction {
1748 public ClearSearch() {
1749 super("Clear find field");
1750 }
1751 public void actionPerformed(ActionEvent e) {
1752 findCombo.setSelectedItem(null);
1753 updateFindRule(null);
1754 }
1755 }
1756
1757 mainPopup.add(new Search());
1758 searchPopup.add(new Search());
1759 mainPopup.add(new DefineAddCustomFind());
1760 searchPopup.add(new DefineAddCustomFind());
1761 mainPopup.add(new ClearSearch());
1762 searchPopup.add(new ClearSearch());
1763
1764 mainPopup.add(new JSeparator());
1765 searchPopup.add(new JSeparator());
1766
1767 class DisplayNormalTimes extends JMenuItem {
1768 public DisplayNormalTimes() {
1769 super("Hide relative times");
1770 addActionListener(
1771 new ActionListener() {
1772 public void actionPerformed(ActionEvent e) {
1773 if (currentPoint != null) {
1774 ((TableColorizingRenderer)currentTable.getDefaultRenderer(Object.class)).setUseNormalTimes();
1775 ((ChainsawCyclicBufferTableModel)currentTable.getModel()).reFilter();
1776 setEnabled(true);
1777 }
1778 }
1779 });
1780 }
1781 }
1782
1783 class DisplayRelativeTimesToRowUnderCursor extends JMenuItem {
1784 public DisplayRelativeTimesToRowUnderCursor() {
1785 super("Show times relative to this event");
1786 addActionListener(
1787 new ActionListener() {
1788 public void actionPerformed(ActionEvent e) {
1789 if (currentPoint != null) {
1790 int row = currentTable.rowAtPoint(currentPoint);
1791 ChainsawCyclicBufferTableModel cyclicBufferTableModel = (ChainsawCyclicBufferTableModel) currentTable.getModel();
1792 LoggingEventWrapper loggingEventWrapper = cyclicBufferTableModel.getRow(row);
1793 if (loggingEventWrapper != null)
1794 {
1795 ((TableColorizingRenderer)currentTable.getDefaultRenderer(Object.class)).setUseRelativeTimes(loggingEventWrapper.getLoggingEvent().getTimeStamp());
1796 cyclicBufferTableModel.reFilter();
1797 }
1798 setEnabled(true);
1799 }
1800 }
1801 });
1802 }
1803 }
1804
1805 class DisplayRelativeTimesToPreviousRow extends JMenuItem {
1806 public DisplayRelativeTimesToPreviousRow() {
1807 super("Show times relative to previous rows");
1808 addActionListener(
1809 new ActionListener() {
1810 public void actionPerformed(ActionEvent e) {
1811 if (currentPoint != null) {
1812 ((TableColorizingRenderer)currentTable.getDefaultRenderer(Object.class)).setUseRelativeTimesToPreviousRow();
1813 ((ChainsawCyclicBufferTableModel)currentTable.getModel()).reFilter();
1814 setEnabled(true);
1815 }
1816 }
1817 });
1818 }
1819 }
1820
1821 mainPopup.add(new DisplayRelativeTimesToRowUnderCursor());
1822 searchPopup.add(new DisplayRelativeTimesToRowUnderCursor());
1823 mainPopup.add(new DisplayRelativeTimesToPreviousRow());
1824 searchPopup.add(new DisplayRelativeTimesToPreviousRow());
1825 mainPopup.add(new DisplayNormalTimes());
1826 searchPopup.add(new DisplayNormalTimes());
1827 mainPopup.add(new JSeparator());
1828 searchPopup.add(new JSeparator());
1829
1830 mainPopup.add(new BuildColorRule());
1831 searchPopup.add(new BuildColorRule());
1832 mainPopup.add(new JSeparator());
1833 searchPopup.add(new JSeparator());
1834 mainPopup.add(new CopyField());
1835 mainPopup.add(new CopySelection());
1836 searchPopup.add(new CopyField());
1837 searchPopup.add(new CopySelection());
1838 mainPopup.add(new JSeparator());
1839 searchPopup.add(new JSeparator());
1840
1841 mainPopup.add(menuItemToggleDetails);
1842 mainPopup.add(menuItemLoggerTree);
1843 mainToggleToolTips = new ToggleToolTips();
1844 searchToggleToolTips = new ToggleToolTips();
1845 mainPopup.add(mainToggleToolTips);
1846 searchPopup.add(searchToggleToolTips);
1847
1848 mainPopup.add(new JSeparator());
1849
1850 mainPopup.add(menuItemToggleDock);
1851
1852 mainPopup.add(new BestFit());
1853 searchPopup.add(new BestFit());
1854
1855 mainPopup.add(new JSeparator());
1856
1857 mainPopup.add(new ColorPanel());
1858 searchPopup.add(new ColorPanel());
1859 mainPopup.add(new LogPanelPreferences());
1860 searchPopup.add(new LogPanelPreferences());
1861
1862 final PopupListener mainTablePopupListener = new PopupListener(mainPopup);
1863 eventsPane.addMouseListener(mainTablePopupListener);
1864 table.addMouseListener(mainTablePopupListener);
1865
1866 table.addMouseListener(new MouseListener(){
1867 public void mouseClicked(MouseEvent mouseEvent) {
1868 checkMultiSelect(mouseEvent);
1869 }
1870
1871 public void mousePressed(MouseEvent mouseEvent) {
1872 checkMultiSelect(mouseEvent);
1873 }
1874
1875 public void mouseReleased(MouseEvent mouseEvent) {
1876 checkMultiSelect(mouseEvent);
1877 }
1878
1879 public void mouseEntered(MouseEvent mouseEvent) {
1880 checkMultiSelect(mouseEvent);
1881 }
1882
1883 public void mouseExited(MouseEvent mouseEvent) {
1884 checkMultiSelect(mouseEvent);
1885 }
1886
1887 private void checkMultiSelect(MouseEvent mouseEvent) {
1888 if (mouseEvent.isAltDown()) {
1889 table.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
1890 } else {
1891 table.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
1892 }
1893 }
1894 });
1895
1896
1897 searchTable.addMouseListener(new MouseListener(){
1898 public void mouseClicked(MouseEvent mouseEvent) {
1899 checkMultiSelect(mouseEvent);
1900 }
1901
1902 public void mousePressed(MouseEvent mouseEvent) {
1903 checkMultiSelect(mouseEvent);
1904 }
1905
1906 public void mouseReleased(MouseEvent mouseEvent) {
1907 checkMultiSelect(mouseEvent);
1908 }
1909
1910 public void mouseEntered(MouseEvent mouseEvent) {
1911 checkMultiSelect(mouseEvent);
1912 }
1913
1914 public void mouseExited(MouseEvent mouseEvent) {
1915 checkMultiSelect(mouseEvent);
1916 }
1917
1918 private void checkMultiSelect(MouseEvent mouseEvent) {
1919 if (mouseEvent.isAltDown()) {
1920 searchTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
1921 } else {
1922 searchTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
1923 }
1924 }
1925 });
1926
1927
1928 final PopupListener searchTablePopupListener = new PopupListener(searchPopup);
1929 searchPane.addMouseListener(searchTablePopupListener);
1930 searchTable.addMouseListener(searchTablePopupListener);
1931 }
1932
1933 private String getValueOf(int row, int column) {
1934 if (currentTable == null) {
1935 return "";
1936 }
1937
1938 Object o = currentTable.getValueAt(row, column);
1939
1940 if (o instanceof Date) {
1941 return TIMESTAMP_DATE_FORMAT.format((Date)o);
1942 }
1943
1944 if (o instanceof String) {
1945 return (String)o;
1946 }
1947
1948 if (o instanceof Level) {
1949 return o.toString();
1950 }
1951
1952 if (o instanceof String[]) {
1953 String value = "";
1954
1955 String[] ti = (String[])o;
1956 if (ti.length > 0 && (!(ti.length == 1 && ti[0].equals("")))) {
1957 LoggingEventWrapper loggingEventWrapper = ((ChainsawCyclicBufferTableModel)(currentTable.getModel())).getRow(row);
1958 value = loggingEventWrapper.getLoggingEvent().getMessage().toString();
1959 for (int i=0;i<((String[])o).length;i++) {
1960 value = value + "\n" + ((String[]) o)[i];
1961 }
1962 }
1963 return value;
1964 }
1965 return "";
1966 }
1967
1968 private Action getFindNextAction() {
1969 final Action action =
1970 new AbstractAction("Find next") {
1971 public void actionPerformed(ActionEvent e) {
1972 findNext();
1973 }
1974 };
1975
1976
1977 action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("F3"));
1978 action.putValue(
1979 Action.SHORT_DESCRIPTION,
1980 "Find the next occurrence of the rule from the current row");
1981 action.putValue(Action.SMALL_ICON, new ImageIcon(ChainsawIcons.DOWN));
1982
1983 return action;
1984 }
1985
1986 private Action getFindPreviousAction() {
1987 final Action action =
1988 new AbstractAction("Find previous") {
1989 public void actionPerformed(ActionEvent e) {
1990 findPrevious();
1991 }
1992 };
1993
1994
1995 action.putValue(
1996 Action.ACCELERATOR_KEY,
1997 KeyStroke.getKeyStroke(KeyEvent.VK_F3, InputEvent.SHIFT_MASK));
1998 action.putValue(
1999 Action.SHORT_DESCRIPTION,
2000 "Find the previous occurrence of the rule from the current row");
2001 action.putValue(Action.SMALL_ICON, new ImageIcon(ChainsawIcons.UP));
2002
2003 return action;
2004 }
2005
2006 private void buildCombo(final AutoFilterComboBox combo, boolean isFiltering, final AutoFilterComboBox.AutoFilterComboBoxModel otherModel) {
2007
2008 combo.addItem("LEVEL == TRACE");
2009 combo.addItem("LEVEL >= DEBUG");
2010 combo.addItem("LEVEL >= INFO");
2011 combo.addItem("LEVEL >= WARN");
2012 combo.addItem("LEVEL >= ERROR");
2013 combo.addItem("LEVEL == FATAL");
2014
2015 final JTextField filterText =(JTextField) combo.getEditor().getEditorComponent();
2016 if (isFiltering) {
2017 filterText.getDocument().addDocumentListener(new DelayedTextDocumentListener(filterText));
2018 }
2019 filterText.setToolTipText("Enter an expression - right click or ctrl-space for menu - press enter to add to list");
2020 filterText.addKeyListener(new ExpressionRuleContext(filterModel, filterText));
2021
2022 if (combo.getEditor().getEditorComponent() instanceof JTextField) {
2023 combo.addActionListener(
2024 new AbstractAction() {
2025 public void actionPerformed(ActionEvent e) {
2026 if (e.getActionCommand().equals("comboBoxEdited")) {
2027 try {
2028
2029 Object item = combo.getSelectedItem();
2030 if (item != null && !item.toString().trim().equals("")) {
2031 ExpressionRule.getRule(item.toString());
2032
2033 combo.insertItemAt(item, 0);
2034 otherModel.insertElementAt(item, 0);
2035 }
2036
2037 filterText.setBackground(UIManager.getColor("TextField.background"));
2038 } catch (IllegalArgumentException iae) {
2039
2040
2041 filterText.setToolTipText(iae.getMessage());
2042 filterText.setBackground(ChainsawConstants.INVALID_EXPRESSION_BACKGROUND);
2043 }
2044 }
2045 }
2046 });
2047 }
2048 }
2049
2050
2051
2052
2053
2054
2055
2056 public boolean isScrollToBottom() {
2057 return preferenceModel.isScrollToBottom();
2058 }
2059
2060 public void setRefineFocusText(String refineFocusText) {
2061 final JTextField filterText =(JTextField) filterCombo.getEditor().getEditorComponent();
2062 filterText.setText(refineFocusText);
2063 }
2064
2065 public String getRefineFocusText() {
2066 final JTextField filterText =(JTextField) filterCombo.getEditor().getEditorComponent();
2067 return filterText.getText();
2068 }
2069
2070
2071
2072
2073 public void toggleScrollToBottom() {
2074 preferenceModel.setScrollToBottom(!preferenceModel.isScrollToBottom());
2075 }
2076
2077 private void scrollToBottom() {
2078
2079 EventQueue.invokeLater(new Runnable()
2080 {
2081 public void run() {
2082 int scrollRow = tableModel.getRowCount() - 1;
2083 table.scrollToRow(scrollRow);
2084 }
2085 });
2086 }
2087
2088 public void scrollToTop() {
2089 EventQueue.invokeLater(new Runnable() {
2090 public void run() {
2091 if (tableModel.getRowCount() > 1) {
2092 table.scrollToRow(0);
2093 }
2094 }
2095 });
2096 }
2097
2098
2099
2100
2101
2102
2103
2104
2105 public String getNamespace() {
2106 return getIdentifier();
2107 }
2108
2109
2110
2111
2112
2113
2114
2115
2116 public String getInterestedIdentifier() {
2117 return getIdentifier();
2118 }
2119
2120
2121
2122
2123
2124
2125
2126
2127 public void receiveEventBatch(String ident, final List events) {
2128
2129 SwingHelper.invokeOnEDT(new Runnable() {
2130 public void run() {
2131
2132
2133
2134 if (isPaused()) {
2135 return;
2136 }
2137 final int selectedRow = table.getSelectedRow();
2138 final int startingRow = table.getRowCount();
2139 final LoggingEventWrapper selectedEvent;
2140 if (selectedRow >= 0) {
2141 selectedEvent = tableModel.getRow(selectedRow);
2142 } else {
2143 selectedEvent = null;
2144 }
2145
2146 final int startingSearchRow = searchTable.getRowCount();
2147
2148 boolean rowAdded = false;
2149 boolean searchRowAdded = false;
2150
2151 int addedRowCount = 0;
2152 int searchAddedRowCount = 0;
2153
2154 for (Iterator iter = events.iterator(); iter.hasNext();) {
2155
2156 LoggingEvent event = (LoggingEvent)iter.next();
2157
2158 LoggingEventWrapper loggingEventWrapper1 = new LoggingEventWrapper(event);
2159
2160 if (clearTableExpressionRule != null && clearTableExpressionRule.evaluate(event, null)) {
2161 logger.info("clear table expression matched - clearing table - matching event msg - " + event.getMessage());
2162 clearEvents();
2163 }
2164
2165 updateOtherModels(event);
2166 boolean isCurrentRowAdded = tableModel.isAddRow(loggingEventWrapper1);
2167 if (isCurrentRowAdded) {
2168 addedRowCount++;
2169 }
2170 rowAdded = rowAdded || isCurrentRowAdded;
2171
2172
2173 LoggingEventWrapper loggingEventWrapper2 = new LoggingEventWrapper(loggingEventWrapper1);
2174 boolean isSearchCurrentRowAdded = searchModel.isAddRow(loggingEventWrapper2);
2175 if (isSearchCurrentRowAdded) {
2176 searchAddedRowCount++;
2177 }
2178 searchRowAdded = searchRowAdded || isSearchCurrentRowAdded;
2179 }
2180
2181 if (rowAdded) {
2182 tableModel.fireTableEvent(startingRow, startingRow + addedRowCount, addedRowCount);
2183 }
2184 if (searchRowAdded) {
2185 searchModel.fireTableEvent(startingSearchRow, startingSearchRow + searchAddedRowCount, searchAddedRowCount);
2186 }
2187
2188
2189 tableModel.notifyCountListeners();
2190
2191 if (rowAdded) {
2192 if (tableModel.isSortEnabled()) {
2193 tableModel.sort();
2194 }
2195
2196
2197 detailPaneUpdater.setSelectedRow(table.getSelectedRow());
2198 }
2199
2200 if (searchRowAdded) {
2201 if (searchModel.isSortEnabled()) {
2202 searchModel.sort();
2203 }
2204 }
2205
2206 if (!isScrollToBottom() && selectedEvent != null) {
2207 final int newIndex = tableModel.getRowIndex(selectedEvent);
2208 if (newIndex >= 0) {
2209
2210 table.setRowSelectionInterval(newIndex, newIndex);
2211 }
2212 }
2213 }
2214 });
2215 }
2216
2217
2218
2219
2220
2221
2222
2223
2224 public void loadSettings(LoadSettingsEvent event) {
2225
2226 File xmlFile = null;
2227 try {
2228 xmlFile = new File(SettingsManager.getInstance().getSettingsDirectory(), URLEncoder.encode(identifier, "UTF-8") + ".xml");
2229 } catch (UnsupportedEncodingException e) {
2230 e.printStackTrace();
2231 }
2232
2233 if (xmlFile.exists()) {
2234 XStream stream = buildXStreamForLogPanelPreference();
2235 ObjectInputStream in = null;
2236 try {
2237 FileReader r = new FileReader(xmlFile);
2238 in = stream.createObjectInputStream(r);
2239 LogPanelPreferenceModel storedPrefs = (LogPanelPreferenceModel)in.readObject();
2240 lowerPanelDividerLocation = in.readInt();
2241 int treeDividerLocation = in.readInt();
2242 String conversionPattern = in.readObject().toString();
2243 Point p = (Point)in.readObject();
2244 Dimension d = (Dimension)in.readObject();
2245
2246 int versionNumber = 0;
2247 try {
2248 versionNumber = in.readInt();
2249 } catch (EOFException eof){
2250 }
2251
2252 Vector savedVector;
2253
2254
2255 if (versionNumber > 0) {
2256 savedVector = (Vector) in.readObject();
2257 for(int i = 0 ; i < savedVector.size() ; i++){
2258 Object item = savedVector.get(i);
2259
2260 filterCombo.insertItemAt(item, 0);
2261 findCombo.insertItemAt(item, 0);
2262 }
2263 if (versionNumber > 1) {
2264
2265 int index = 0;
2266 String columnOrder = event.getSetting(TABLE_COLUMN_ORDER);
2267 StringTokenizer tok = new StringTokenizer(columnOrder, ",");
2268 while (tok.hasMoreElements()) {
2269 String element = tok.nextElement().toString().trim().toUpperCase();
2270 TableColumn column = new TableColumn(index++);
2271 column.setHeaderValue(element);
2272 preferenceModel.addColumn(column);
2273 }
2274
2275 TableColumnModel columnModel = table.getColumnModel();
2276
2277 while (columnModel.getColumnCount() > 0) {
2278 columnModel.removeColumn(columnModel.getColumn(0));
2279 }
2280
2281 for (Iterator iter = preferenceModel.getVisibleColumnOrder().iterator();iter.hasNext();) {
2282 TableColumn col = (TableColumn)iter.next();
2283 columnModel.addColumn(col);
2284 }
2285
2286 TableColumnModel searchColumnModel = searchTable.getColumnModel();
2287
2288 while (searchColumnModel.getColumnCount() > 0) {
2289 searchColumnModel.removeColumn(searchColumnModel.getColumn(0));
2290 }
2291
2292 for (Iterator iter = preferenceModel.getVisibleColumnOrder().iterator();iter.hasNext();) {
2293 TableColumn col = (TableColumn)iter.next();
2294 searchColumnModel.addColumn(col);
2295 }
2296
2297 preferenceModel.apply(storedPrefs);
2298 } else {
2299 loadDefaultColumnSettings(event);
2300 }
2301
2302
2303 tableModel.setCyclic(preferenceModel.isCyclic());
2304 searchModel.setCyclic(preferenceModel.isCyclic());
2305 lowerPanel.setDividerLocation(lowerPanelDividerLocation);
2306 nameTreeAndMainPanelSplit.setDividerLocation(treeDividerLocation);
2307 detailLayout.setConversionPattern(conversionPattern);
2308 if (p.x != 0 && p.y != 0) {
2309 undockedFrame.setLocation(p.x, p.y);
2310 undockedFrame.setSize(d);
2311 } else {
2312 undockedFrame.setLocation(0, 0);
2313 undockedFrame.setSize(new Dimension(1024, 768));
2314 }
2315 } else {
2316 loadDefaultColumnSettings(event);
2317 }
2318 } catch (Exception e) {
2319 e.printStackTrace();
2320 loadDefaultColumnSettings(event);
2321
2322 } finally {
2323 if (in != null) {
2324 try {
2325 in.close();
2326 } catch (IOException ioe) {}
2327 }
2328 }
2329 } else {
2330
2331 loadDefaultColumnSettings(event);
2332 }
2333
2334 tableModel.setCyclic(preferenceModel.isCyclic());
2335 searchModel.setCyclic(preferenceModel.isCyclic());
2336 logTreePanel.ignore(preferenceModel.getHiddenLoggers());
2337 logTreePanel.setHiddenExpression(preferenceModel.getHiddenExpression());
2338 logTreePanel.setAlwaysDisplayExpression(preferenceModel.getAlwaysDisplayExpression());
2339 if (preferenceModel.getClearTableExpression() != null) {
2340 try {
2341 clearTableExpressionRule = ExpressionRule.getRule(preferenceModel.getClearTableExpression());
2342 } catch (Exception e) {
2343 clearTableExpressionRule = null;
2344 }
2345 }
2346
2347
2348 colorizer.loadColorSettings(identifier);
2349 }
2350
2351
2352
2353
2354
2355
2356
2357
2358 public void saveSettings(SaveSettingsEvent event) {
2359 File xmlFile = null;
2360 try {
2361 xmlFile = new File(SettingsManager.getInstance().getSettingsDirectory(), URLEncoder.encode(identifier, "UTF-8") + ".xml");
2362 } catch (UnsupportedEncodingException e) {
2363 e.printStackTrace();
2364
2365 return;
2366 }
2367
2368 preferenceModel.setHiddenLoggers(new HashSet(logTreePanel.getHiddenSet()));
2369 preferenceModel.setHiddenExpression(logTreePanel.getHiddenExpression());
2370 preferenceModel.setAlwaysDisplayExpression(logTreePanel.getAlwaysDisplayExpression());
2371 List visibleOrder = new ArrayList();
2372 Enumeration cols = table.getColumnModel().getColumns();
2373 while (cols.hasMoreElements()) {
2374 TableColumn c = (TableColumn)cols.nextElement();
2375 visibleOrder.add(c);
2376 }
2377 preferenceModel.setVisibleColumnOrder(visibleOrder);
2378
2379
2380 XStream stream = buildXStreamForLogPanelPreference();
2381 ObjectOutputStream s = null;
2382 try {
2383 FileWriter w = new FileWriter(xmlFile);
2384 s = stream.createObjectOutputStream(w);
2385 s.writeObject(preferenceModel);
2386 if (isDetailPanelVisible) {
2387
2388 s.writeInt(lowerPanel.getDividerLocation());
2389 } else {
2390
2391 s.writeInt(lowerPanelDividerLocation);
2392 }
2393 s.writeInt(nameTreeAndMainPanelSplit.getDividerLocation());
2394 s.writeObject(detailLayout.getConversionPattern());
2395 s.writeObject(undockedFrame.getLocation());
2396 s.writeObject(undockedFrame.getSize());
2397
2398 s.writeInt(LOG_PANEL_SERIALIZATION_VERSION_NUMBER);
2399
2400 Vector combinedVector = new Vector();
2401 combinedVector.addAll(filterCombo.getModelData());
2402 combinedVector.addAll(findCombo.getModelData());
2403
2404 s.writeObject(combinedVector);
2405 } catch (Exception ex) {
2406 ex.printStackTrace();
2407
2408 } finally {
2409 if (s != null) {
2410 try {
2411 s.close();
2412 } catch (IOException ioe) {}
2413 }
2414 }
2415
2416
2417 colorizer.saveColorSettings(identifier);
2418 }
2419
2420 private XStream buildXStreamForLogPanelPreference() {
2421 XStream stream = new XStream(new DomDriver());
2422 stream.registerConverter(new TableColumnConverter());
2423 return stream;
2424 }
2425
2426
2427
2428
2429 void showPreferences() {
2430
2431 centerAndSetVisible(logPanelPreferencesFrame);
2432 }
2433
2434 public static void centerAndSetVisible(Window window) {
2435 Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
2436 window.setLocation(new Point((screenDimension.width / 2) - (window.getSize().width / 2),
2437 (screenDimension.height / 2) - (window.getSize().height / 2)));
2438 window.setVisible(true);
2439 }
2440
2441
2442
2443
2444 void showColorPreferences() {
2445 colorPanel.loadLogPanelColorizers();
2446 colorFrame.pack();
2447 centerAndSetVisible(colorFrame);
2448 }
2449
2450
2451
2452
2453 void toggleDetailVisible() {
2454 preferenceModel.setDetailPaneVisible(
2455 !preferenceModel.isDetailPaneVisible());
2456 }
2457
2458
2459
2460
2461
2462
2463 boolean isDetailVisible() {
2464 return preferenceModel.isDetailPaneVisible();
2465 }
2466
2467 boolean isSearchResultsVisible() {
2468 return preferenceModel.isSearchResultsVisible();
2469 }
2470
2471
2472
2473
2474 void toggleLogTreeVisible() {
2475 preferenceModel.setLogTreePanelVisible(
2476 !preferenceModel.isLogTreePanelVisible());
2477 }
2478
2479
2480
2481
2482
2483
2484 boolean isLogTreeVisible() {
2485 return preferenceModel.isLogTreePanelVisible();
2486 }
2487
2488
2489
2490
2491
2492
2493 List getEvents() {
2494 return tableModel.getAllEvents();
2495 }
2496
2497
2498
2499
2500
2501
2502 List getFilteredEvents() {
2503 return tableModel.getFilteredEvents();
2504 }
2505
2506 List getMatchingEvents(Rule rule) {
2507 return tableModel.getMatchingEvents(rule);
2508 }
2509
2510
2511
2512
2513 void clearEvents() {
2514 clearModel();
2515 }
2516
2517
2518
2519
2520
2521
2522 String getIdentifier() {
2523 return identifier;
2524 }
2525
2526
2527
2528
2529
2530 void undock() {
2531 final int row = table.getSelectedRow();
2532 setDocked(false);
2533 externalPanel.removeAll();
2534
2535 externalPanel.add(undockedToolbar, BorderLayout.NORTH);
2536 externalPanel.add(nameTreeAndMainPanelSplit, BorderLayout.CENTER);
2537 externalPanel.setDocked(false);
2538 undockedFrame.pack();
2539
2540 undockedFrame.setVisible(true);
2541 dockingAction.putValue(Action.NAME, "Dock");
2542 dockingAction.putValue(Action.SMALL_ICON, ChainsawIcons.ICON_DOCK);
2543 if (row > -1) {
2544 EventQueue.invokeLater(new Runnable() {
2545 public void run() {
2546 table.scrollToRow(row);
2547 }
2548 });
2549 }
2550 }
2551
2552
2553
2554
2555
2556
2557 void addEventCountListener(EventCountListener l) {
2558 tableModel.addEventCountListener(l);
2559 }
2560
2561
2562
2563
2564
2565
2566 boolean isPaused() {
2567 return paused;
2568 }
2569
2570
2571
2572
2573
2574
2575 void setPaused(boolean paused) {
2576 boolean oldValue = this.paused;
2577 this.paused = paused;
2578 firePropertyChange("paused", oldValue, paused);
2579 }
2580
2581
2582
2583
2584
2585
2586
2587 int setSelectedEvent(int eventNumber) {
2588 int row = tableModel.locate(ExpressionRule.getRule("prop.log4jid == " + eventNumber), 0, true);
2589 if (row > -1) {
2590 preferenceModel.setScrollToBottom(false);
2591
2592 table.scrollToRow(row);
2593 }
2594 return row;
2595 }
2596
2597
2598
2599
2600
2601
2602 void addPreferencePropertyChangeListener(PropertyChangeListener listener) {
2603 preferenceModel.addPropertyChangeListener(listener);
2604 }
2605
2606
2607
2608
2609
2610 void toggleCyclic() {
2611 boolean toggledCyclic = !preferenceModel.isCyclic();
2612
2613 preferenceModel.setCyclic(toggledCyclic);
2614 tableModel.setCyclic(toggledCyclic);
2615 searchModel.setCyclic(toggledCyclic);
2616 }
2617
2618
2619
2620
2621
2622
2623 boolean isCyclic() {
2624 return preferenceModel.isCyclic();
2625 }
2626
2627 public void updateFindRule(String ruleText) {
2628 if ((ruleText == null) || (ruleText.trim().equals(""))) {
2629 findRule = null;
2630 tableModel.updateEventsWithFindRule(null);
2631 colorizer.setFindRule(null);
2632 tableRuleMediator.setFindRule(null);
2633 searchRuleMediator.setFindRule(null);
2634
2635 findCombo.setBackground(UIManager.getColor("TextField.background"));
2636 findCombo.setToolTipText(
2637 "Enter an expression - right click or ctrl-space for menu - press enter to add to list");
2638 currentSearchMatchCount = 0;
2639 currentFindRuleText = null;
2640 statusBar.setSearchMatchCount(currentSearchMatchCount, getIdentifier());
2641
2642 if (isSearchResultsVisible()) {
2643 hideSearchResults();
2644 }
2645 } else {
2646
2647 preferenceModel.setScrollToBottom(false);
2648 if(ruleText.equals(currentFindRuleText)) {
2649
2650 return;
2651 }
2652 currentFindRuleText = ruleText;
2653 try {
2654 final JTextField findText =(JTextField) findCombo.getEditor().getEditorComponent();
2655 findText.setToolTipText(
2656 "Enter an expression - right click or ctrl-space for menu - press enter to add to list");
2657 findRule = ExpressionRule.getRule(ruleText);
2658 currentSearchMatchCount = tableModel.updateEventsWithFindRule(findRule);
2659 searchModel.updateEventsWithFindRule(findRule);
2660 colorizer.setFindRule(findRule);
2661 tableRuleMediator.setFindRule(findRule);
2662 searchRuleMediator.setFindRule(findRule);
2663
2664 findText.setBackground(UIManager.getColor("TextField.background"));
2665 statusBar.setSearchMatchCount(currentSearchMatchCount, getIdentifier());
2666 if (isSearchResultsVisible()) {
2667 showSearchResults();
2668 }
2669 } catch (IllegalArgumentException re) {
2670 findRule = null;
2671 final JTextField findText =(JTextField) findCombo.getEditor().getEditorComponent();
2672 findText.setToolTipText(re.getMessage());
2673 findText.setBackground(ChainsawConstants.INVALID_EXPRESSION_BACKGROUND);
2674 colorizer.setFindRule(null);
2675 tableRuleMediator.setFindRule(null);
2676 searchRuleMediator.setFindRule(null);
2677 tableModel.updateEventsWithFindRule(null);
2678 searchModel.updateEventsWithFindRule(null);
2679 currentSearchMatchCount = 0;
2680 statusBar.setSearchMatchCount(currentSearchMatchCount, getIdentifier());
2681
2682 if (isSearchResultsVisible()) {
2683 hideSearchResults();
2684 }
2685 }
2686 }
2687 }
2688
2689 private void hideSearchResults() {
2690 if (searchResultsDisplayed) {
2691 detailPanel.removeAll();
2692 JPanel leftSpacePanel = new JPanel();
2693 Integer scrollBarWidth = (Integer) UIManager.get("ScrollBar.width");
2694 leftSpacePanel.setPreferredSize(new Dimension(scrollBarWidth.intValue() -4, -1));
2695
2696 JPanel rightSpacePanel = new JPanel();
2697 rightSpacePanel.setPreferredSize(new Dimension(scrollBarWidth.intValue() -4, -1));
2698
2699 detailPanel.add(detailToolbar, BorderLayout.NORTH);
2700 detailPanel.add(detailPane, BorderLayout.CENTER);
2701
2702 detailPanel.add(leftSpacePanel, BorderLayout.WEST);
2703 detailPanel.add(rightSpacePanel, BorderLayout.EAST);
2704
2705 detailPanel.revalidate();
2706 detailPanel.repaint();
2707
2708 searchResultsDisplayed = false;
2709
2710 if (!isDetailVisible()) {
2711 hideDetailPane();
2712 }
2713 }
2714 }
2715
2716 private void showSearchResults() {
2717 if (isSearchResultsVisible() && !searchResultsDisplayed && findRule != null) {
2718
2719 detailPanel.removeAll();
2720 detailPanel.add(searchPane, BorderLayout.CENTER);
2721 Integer scrollBarWidth = (Integer) UIManager.get("ScrollBar.width");
2722 JPanel leftSpacePanel = new JPanel();
2723 leftSpacePanel.setPreferredSize(new Dimension(scrollBarWidth.intValue() -4, -1));
2724 JPanel rightSpacePanel = new JPanel();
2725 rightSpacePanel.setPreferredSize(new Dimension(scrollBarWidth.intValue() -4, -1));
2726 detailPanel.add(leftSpacePanel, BorderLayout.WEST);
2727 detailPanel.add(rightSpacePanel, BorderLayout.EAST);
2728 detailPanel.revalidate();
2729 detailPanel.repaint();
2730
2731 searchResultsDisplayed = true;
2732
2733 if (!isDetailVisible()) {
2734 showDetailPane();
2735 }
2736 }
2737 }
2738
2739
2740
2741
2742 private void showDetailPane() {
2743 if (!isDetailPanelVisible) {
2744 lowerPanel.setDividerSize(dividerSize);
2745 if (lowerPanelDividerLocation == 0) {
2746 lowerPanel.setDividerLocation(DEFAULT_DETAIL_SPLIT_LOCATION);
2747 lowerPanelDividerLocation = lowerPanel.getDividerLocation();
2748 } else {
2749 lowerPanel.setDividerLocation(lowerPanelDividerLocation);
2750 }
2751 detailPanel.setVisible(true);
2752 detailPanel.repaint();
2753 lowerPanel.repaint();
2754 isDetailPanelVisible = true;
2755 }
2756 }
2757
2758
2759
2760
2761 private void hideDetailPane() {
2762
2763 if (isDetailPanelVisible) {
2764 lowerPanelDividerLocation = lowerPanel.getDividerLocation();
2765 }
2766 lowerPanel.setDividerSize(0);
2767 detailPanel.setVisible(false);
2768 lowerPanel.repaint();
2769 isDetailPanelVisible = false;
2770 }
2771
2772
2773
2774
2775 private void showLogTreePanel() {
2776 nameTreeAndMainPanelSplit.setDividerSize(dividerSize);
2777 nameTreeAndMainPanelSplit.setDividerLocation(
2778 lastLogTreePanelSplitLocation);
2779 logTreePanel.setVisible(true);
2780 nameTreeAndMainPanelSplit.repaint();
2781 }
2782
2783
2784
2785
2786 private void hideLogTreePanel() {
2787
2788 int currentSize = nameTreeAndMainPanelSplit.getWidth() - nameTreeAndMainPanelSplit.getDividerSize() - 1;
2789
2790 if (currentSize > 0) {
2791 lastLogTreePanelSplitLocation =
2792 (double) nameTreeAndMainPanelSplit.getDividerLocation() / currentSize;
2793 }
2794 nameTreeAndMainPanelSplit.setDividerSize(0);
2795 logTreePanel.setVisible(false);
2796 nameTreeAndMainPanelSplit.repaint();
2797 }
2798
2799
2800
2801
2802
2803
2804 private JToolBar createDockwindowToolbar() {
2805 final JToolBar toolbar = new JToolBar();
2806 toolbar.setFloatable(false);
2807
2808 final Action dockPauseAction =
2809 new AbstractAction("Pause") {
2810 public void actionPerformed(ActionEvent evt) {
2811 setPaused(!isPaused());
2812 }
2813 };
2814
2815 dockPauseAction.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_P));
2816 dockPauseAction.putValue(
2817 Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("F12"));
2818 dockPauseAction.putValue(
2819 Action.SHORT_DESCRIPTION,
2820 "Halts the display, while still allowing events to stream in the background");
2821 dockPauseAction.putValue(
2822 Action.SMALL_ICON, new ImageIcon(ChainsawIcons.PAUSE));
2823
2824 final SmallToggleButton dockPauseButton =
2825 new SmallToggleButton(dockPauseAction);
2826 dockPauseButton.setText("");
2827
2828 dockPauseButton.getModel().setSelected(isPaused());
2829
2830 addPropertyChangeListener(
2831 "paused",
2832 new PropertyChangeListener() {
2833 public void propertyChange(PropertyChangeEvent evt) {
2834 dockPauseButton.getModel().setSelected(isPaused());
2835 }
2836 });
2837 toolbar.add(dockPauseButton);
2838
2839 Action dockShowPrefsAction =
2840 new AbstractAction("") {
2841 public void actionPerformed(ActionEvent arg0) {
2842 showPreferences();
2843 }
2844 };
2845
2846 dockShowPrefsAction.putValue(
2847 Action.SHORT_DESCRIPTION, "Define preferences...");
2848 dockShowPrefsAction.putValue(
2849 Action.SMALL_ICON, ChainsawIcons.ICON_PREFERENCES);
2850
2851 toolbar.add(new SmallButton(dockShowPrefsAction));
2852
2853 Action dockToggleLogTreeAction =
2854 new AbstractAction() {
2855 public void actionPerformed(ActionEvent e) {
2856 toggleLogTreeVisible();
2857 }
2858 };
2859
2860 dockToggleLogTreeAction.putValue(Action.SHORT_DESCRIPTION, "Toggles the Logger Tree Pane");
2861 dockToggleLogTreeAction.putValue("enabled", Boolean.TRUE);
2862 dockToggleLogTreeAction.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_T));
2863 dockToggleLogTreeAction.putValue(
2864 Action.ACCELERATOR_KEY,
2865 KeyStroke.getKeyStroke(KeyEvent.VK_T, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
2866 dockToggleLogTreeAction.putValue(
2867 Action.SMALL_ICON, new ImageIcon(ChainsawIcons.WINDOW_ICON));
2868
2869 final SmallToggleButton toggleLogTreeButton =
2870 new SmallToggleButton(dockToggleLogTreeAction);
2871 preferenceModel.addPropertyChangeListener("logTreePanelVisible", new PropertyChangeListener() {
2872 public void propertyChange(PropertyChangeEvent evt) {
2873 toggleLogTreeButton.setSelected(preferenceModel.isLogTreePanelVisible());
2874 }
2875 });
2876
2877 toggleLogTreeButton.setSelected(isLogTreeVisible());
2878 toolbar.add(toggleLogTreeButton);
2879 toolbar.addSeparator();
2880
2881 final Action undockedClearAction =
2882 new AbstractAction("Clear") {
2883 public void actionPerformed(ActionEvent arg0) {
2884 clearModel();
2885 }
2886 };
2887
2888 undockedClearAction.putValue(
2889 Action.SMALL_ICON, new ImageIcon(ChainsawIcons.DELETE));
2890 undockedClearAction.putValue(
2891 Action.SHORT_DESCRIPTION, "Removes all the events from the current view");
2892
2893 final SmallButton dockClearButton = new SmallButton(undockedClearAction);
2894 dockClearButton.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
2895 KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2896 undockedClearAction.getValue(Action.NAME));
2897 dockClearButton.getActionMap().put(
2898 undockedClearAction.getValue(Action.NAME), undockedClearAction);
2899
2900 dockClearButton.setText("");
2901 toolbar.add(dockClearButton);
2902 toolbar.addSeparator();
2903
2904 Action dockToggleScrollToBottomAction =
2905 new AbstractAction("Toggles Scroll to Bottom") {
2906 public void actionPerformed(ActionEvent e) {
2907 toggleScrollToBottom();
2908 }
2909 };
2910
2911 dockToggleScrollToBottomAction.putValue(Action.SHORT_DESCRIPTION, "Toggles Scroll to Bottom");
2912 dockToggleScrollToBottomAction.putValue("enabled", Boolean.TRUE);
2913 dockToggleScrollToBottomAction.putValue(
2914 Action.SMALL_ICON, new ImageIcon(ChainsawIcons.SCROLL_TO_BOTTOM));
2915
2916 final SmallToggleButton toggleScrollToBottomButton =
2917 new SmallToggleButton(dockToggleScrollToBottomAction);
2918 preferenceModel.addPropertyChangeListener("scrollToBottom", new PropertyChangeListener() {
2919 public void propertyChange(PropertyChangeEvent evt) {
2920 toggleScrollToBottomButton.setSelected(isScrollToBottom());
2921 }
2922 });
2923
2924 toggleScrollToBottomButton.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
2925 KeyStroke.getKeyStroke(KeyEvent.VK_B, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2926 dockToggleScrollToBottomAction.getValue(Action.NAME));
2927 toggleScrollToBottomButton.getActionMap().put(
2928 dockToggleScrollToBottomAction.getValue(Action.NAME), dockToggleScrollToBottomAction);
2929
2930 toggleScrollToBottomButton.setSelected(isScrollToBottom());
2931 toggleScrollToBottomButton.setText("");
2932 toolbar.add(toggleScrollToBottomButton);
2933 toolbar.addSeparator();
2934
2935 findCombo.addActionListener(new ActionListener(){
2936 public void actionPerformed(ActionEvent e) {
2937
2938 if (e.getActionCommand().equalsIgnoreCase("comboBoxEdited")) {
2939 findNext();
2940 }
2941 }
2942 });
2943 Action redockAction =
2944 new AbstractAction("", ChainsawIcons.ICON_DOCK) {
2945 public void actionPerformed(ActionEvent arg0) {
2946 dock();
2947 }
2948 };
2949
2950 redockAction.putValue(
2951 Action.SHORT_DESCRIPTION,
2952 "Docks this window back with the main Chainsaw window");
2953
2954 SmallButton redockButton = new SmallButton(redockAction);
2955 toolbar.add(redockButton);
2956
2957 return toolbar;
2958 }
2959
2960
2961
2962
2963 protected void updateStatusBar() {
2964 SwingHelper.invokeOnEDT(
2965 new Runnable() {
2966 public void run() {
2967 statusBar.setSelectedLine(
2968 table.getSelectedRow() + 1, tableModel.getRowCount(),
2969 tableModel.size(), getIdentifier());
2970 statusBar.setSearchMatchCount(currentSearchMatchCount, getIdentifier());
2971 }
2972 });
2973 }
2974
2975
2976
2977
2978
2979
2980 private void setDetailPaneConversionPattern(String conversionPattern) {
2981 String oldPattern = getDetailPaneConversionPattern();
2982 (detailLayout).setConversionPattern(conversionPattern);
2983 firePropertyChange(
2984 "detailPaneConversionPattern", oldPattern,
2985 getDetailPaneConversionPattern());
2986 }
2987
2988
2989
2990
2991
2992
2993 private String getDetailPaneConversionPattern() {
2994 return (detailLayout).getConversionPattern();
2995 }
2996
2997
2998
2999
3000 private void clearModel() {
3001 previousLastIndex = -1;
3002 tableModel.clearModel();
3003 searchModel.clearModel();
3004
3005 synchronized (detail) {
3006 detailPaneUpdater.setSelectedRow(-1);
3007 detail.notify();
3008 }
3009
3010 statusBar.setNothingSelected();
3011 }
3012
3013 public void findNextColorizedEvent() {
3014 EventQueue.invokeLater(new Runnable() {
3015 public void run() {
3016 final int nextRow = tableModel.findColoredRow(table.getSelectedRow() + 1, true);
3017 if (nextRow > -1) {
3018 table.scrollToRow(nextRow);
3019 }
3020 }
3021 });
3022 }
3023
3024 public void findPreviousColorizedEvent() {
3025 EventQueue.invokeLater(new Runnable() {
3026 public void run() {
3027 final int previousRow = tableModel.findColoredRow(table.getSelectedRow() - 1, false);
3028 if (previousRow > -1) {
3029 table.scrollToRow(previousRow);
3030 }
3031 }
3032 });
3033 }
3034
3035
3036
3037
3038
3039
3040 public void findNext() {
3041 Object item = findCombo.getSelectedItem();
3042 updateFindRule(item == null ? null: item.toString());
3043
3044 if (findRule != null) {
3045 EventQueue.invokeLater(new Runnable() {
3046 public void run() {
3047 final JTextField findText =(JTextField) findCombo.getEditor().getEditorComponent();
3048 try {
3049 int filteredEventsSize = getFilteredEvents().size();
3050 int startRow = table.getSelectedRow() + 1;
3051 if (startRow > filteredEventsSize - 1) {
3052 startRow = 0;
3053 }
3054
3055 final int nextRow = tableModel.locate(findRule, startRow, true);
3056
3057 if (nextRow > -1) {
3058 table.scrollToRow(nextRow);
3059 findText.setToolTipText("Enter an expression - right click or ctrl-space for menu - press enter to add to list");
3060 }
3061 findText.setBackground(UIManager.getColor("TextField.background"));
3062 } catch (IllegalArgumentException iae) {
3063 findText.setToolTipText(iae.getMessage());
3064 findText.setBackground(ChainsawConstants.INVALID_EXPRESSION_BACKGROUND);
3065 colorizer.setFindRule(null);
3066 tableRuleMediator.setFindRule(null);
3067 searchRuleMediator.setFindRule(null);
3068 }
3069 }
3070 });
3071 }
3072 }
3073
3074
3075
3076
3077
3078
3079 public void findPrevious() {
3080 Object item = findCombo.getSelectedItem();
3081 updateFindRule(item == null ? null: item.toString());
3082
3083 if (findRule != null) {
3084 EventQueue.invokeLater(new Runnable() {
3085 public void run() {
3086 final JTextField findText =(JTextField) findCombo.getEditor().getEditorComponent();
3087 try {
3088 int startRow = table.getSelectedRow() - 1;
3089 int filteredEventsSize = getFilteredEvents().size();
3090 if (startRow < 0) {
3091 startRow = filteredEventsSize - 1;
3092 }
3093 final int previousRow = tableModel.locate(findRule, startRow, false);
3094
3095 if (previousRow > -1) {
3096 table.scrollToRow(previousRow);
3097 findCombo.setToolTipText("Enter an expression - right click or ctrl-space for menu - press enter to add to list");
3098 }
3099 findText.setBackground(UIManager.getColor("TextField.background"));
3100 } catch (IllegalArgumentException iae) {
3101 findText.setToolTipText(iae.getMessage());
3102 findText.setBackground(ChainsawConstants.INVALID_EXPRESSION_BACKGROUND);
3103 }
3104 }
3105 });
3106 }
3107 }
3108
3109
3110
3111
3112
3113 private void dock() {
3114
3115 final int row = table.getSelectedRow();
3116 setDocked(true);
3117 undockedFrame.setVisible(false);
3118 removeAll();
3119
3120 add(nameTreeAndMainPanelSplit, BorderLayout.CENTER);
3121 externalPanel.setDocked(true);
3122 dockingAction.putValue(Action.NAME, "Undock");
3123 dockingAction.putValue(Action.SMALL_ICON, ChainsawIcons.ICON_UNDOCK);
3124 if (row > -1) {
3125 EventQueue.invokeLater(new Runnable() {
3126 public void run() {
3127 table.scrollToRow(row);
3128 }
3129 });
3130 }
3131 }
3132
3133
3134
3135
3136
3137
3138 private void loadDefaultColumnSettings(LoadSettingsEvent event) {
3139 String columnOrder = event.getSetting(TABLE_COLUMN_ORDER);
3140
3141 TableColumnModel columnModel = table.getColumnModel();
3142 TableColumnModel searchColumnModel = searchTable.getColumnModel();
3143
3144 Map columnNameMap = new HashMap();
3145 Map searchColumnNameMap = new HashMap();
3146
3147 for (int i = 0; i < columnModel.getColumnCount(); i++) {
3148 columnNameMap.put(table.getColumnName(i).toUpperCase(), columnModel.getColumn(i));
3149 }
3150
3151 for (int i = 0; i < searchColumnModel.getColumnCount(); i++) {
3152 searchColumnNameMap.put(searchTable.getColumnName(i).toUpperCase(), searchColumnModel.getColumn(i));
3153 }
3154
3155 int index = 0;
3156 StringTokenizer tok = new StringTokenizer(columnOrder, ",");
3157 List sortedColumnList = new ArrayList();
3158
3159
3160
3161
3162
3163
3164 while (tok.hasMoreElements()) {
3165 String element = tok.nextElement().toString().trim().toUpperCase();
3166 TableColumn column = (TableColumn) columnNameMap.get(element);
3167
3168 if (column != null) {
3169 sortedColumnList.add(column);
3170 table.removeColumn(column);
3171 searchTable.removeColumn(column);
3172 }
3173 }
3174 preferenceModel.setDetailPaneVisible(event.asBoolean("detailPaneVisible"));
3175 preferenceModel.setLogTreePanelVisible(event.asBoolean("logTreePanelVisible"));
3176 preferenceModel.setHighlightSearchMatchText(event.asBoolean("highlightSearchMatchText"));
3177 preferenceModel.setWrapMessage(event.asBoolean("wrapMessage"));
3178 preferenceModel.setSearchResultsVisible(event.asBoolean("searchResultsVisible"));
3179
3180 for (Iterator iter = sortedColumnList.iterator(); iter.hasNext();) {
3181 TableColumn element = (TableColumn) iter.next();
3182 if (preferenceModel.addColumn(element)) {
3183 if (!applicationPreferenceModel.isDefaultColumnsSet() || applicationPreferenceModel.isDefaultColumnsSet() &&
3184 applicationPreferenceModel.getDefaultColumnNames().contains(element.getHeaderValue())) {
3185 table.addColumn(element);
3186 searchTable.addColumn(element);
3187 preferenceModel.setColumnVisible(element.getHeaderValue().toString(), true);
3188 }
3189 }
3190 }
3191
3192 String columnWidths = event.getSetting(TABLE_COLUMN_WIDTHS);
3193
3194 tok = new StringTokenizer(columnWidths, ",");
3195 index = 0;
3196
3197 while (tok.hasMoreElements()) {
3198 String element = (String) tok.nextElement();
3199
3200 try {
3201 int width = Integer.parseInt(element);
3202
3203 if (index > (columnModel.getColumnCount() - 1)) {
3204 logger.warn(
3205 "loadsettings - failed attempt to set width for index " + index
3206 + ", width " + element);
3207 } else {
3208 columnModel.getColumn(index).setPreferredWidth(width);
3209 searchColumnModel.getColumn(index).setPreferredWidth(width);
3210 }
3211
3212 index++;
3213 } catch (NumberFormatException e) {
3214 logger.error("Error decoding a Table width", e);
3215 }
3216 }
3217 undockedFrame.setSize(getSize());
3218 undockedFrame.setLocation(getBounds().x, getBounds().y);
3219
3220 repaint();
3221 }
3222
3223
3224
3225
3226
3227
3228
3229
3230 private int getMaxColumnWidth(int index) {
3231 FontMetrics metrics = getGraphics().getFontMetrics();
3232 int longestWidth =
3233 metrics.stringWidth(" " + table.getColumnName(index) + " ")
3234 + (2 * table.getColumnModel().getColumnMargin());
3235
3236 for (int i = 0, j = tableModel.getRowCount(); i < j; i++) {
3237 Component c =
3238 renderer.getTableCellRendererComponent(
3239 table, table.getValueAt(i, index), false, false, i, index);
3240
3241 if (c instanceof JLabel) {
3242 longestWidth =
3243 Math.max(longestWidth, metrics.stringWidth(((JLabel) c).getText()));
3244 }
3245 }
3246
3247 return longestWidth + 5;
3248 }
3249
3250 private String getToolTipTextForEvent(LoggingEventWrapper loggingEventWrapper) {
3251 StringBuffer buf = new StringBuffer();
3252 buf.append(detailLayout.getHeader()).append(detailLayout.format(loggingEventWrapper.getLoggingEvent())).append(detailLayout.getFooter());
3253 return buf.toString();
3254 }
3255
3256
3257
3258
3259
3260
3261
3262 private void updateOtherModels(LoggingEvent event) {
3263
3264
3265
3266
3267 tableModel.addLoggerName(event.getLoggerName());
3268
3269 filterModel.processNewLoggingEvent(event);
3270 }
3271
3272 public void findNextMarker() {
3273 EventQueue.invokeLater(new Runnable() {
3274 public void run() {
3275 int startRow = table.getSelectedRow() + 1;
3276 int filteredEventsSize = getFilteredEvents().size();
3277 if (startRow > filteredEventsSize - 1) {
3278 startRow = 0;
3279 }
3280 final int nextRow = tableModel.locate(findMarkerRule, startRow, true);
3281
3282 if (nextRow > -1) {
3283 table.scrollToRow(nextRow);
3284 }
3285 }
3286 });
3287 }
3288
3289 public void findPreviousMarker() {
3290 EventQueue.invokeLater(new Runnable() {
3291 public void run() {
3292 int startRow = table.getSelectedRow() - 1;
3293 int filteredEventsSize = getFilteredEvents().size();
3294 if (startRow < 0) {
3295 startRow = filteredEventsSize - 1;
3296 }
3297 final int previousRow = tableModel.locate(findMarkerRule, startRow, false);
3298
3299 if (previousRow > -1) {
3300 table.scrollToRow(previousRow);
3301 }
3302 }
3303 });
3304 }
3305
3306 public void clearAllMarkers() {
3307
3308 tableModel.removePropertyFromEvents(ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE);
3309 }
3310
3311 public void toggleMarker() {
3312 int row = table.getSelectedRow();
3313 if (row != -1) {
3314 LoggingEventWrapper loggingEventWrapper = tableModel.getRow(row);
3315 if (loggingEventWrapper != null) {
3316 Object marker = loggingEventWrapper.getLoggingEvent().getProperty(ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE);
3317 if (marker == null) {
3318 loggingEventWrapper.setProperty(ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE, "set");
3319 } else {
3320 loggingEventWrapper.removeProperty(ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE);
3321 }
3322
3323 tableModel.fireRowUpdated(row, (marker == null));
3324 }
3325 }
3326 }
3327
3328 public void layoutComponents()
3329 {
3330 if (preferenceModel.isDetailPaneVisible()) {
3331 showDetailPane();
3332 } else {
3333 hideDetailPane();
3334 }
3335 }
3336
3337 public void setFindText(String findText) {
3338 findCombo.setSelectedItem(findText);
3339 findNext();
3340 }
3341
3342 public String getFindText() {
3343 Object selectedItem = findCombo.getSelectedItem();
3344 if (selectedItem == null) {
3345 return "";
3346 }
3347 return selectedItem.toString();
3348 }
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358 private final class DelayedTextDocumentListener
3359 implements DocumentListener {
3360 private static final long CHECK_PERIOD = 1000;
3361 private final JTextField textField;
3362 private long lastTimeStamp = System.currentTimeMillis();
3363 private final Thread delayThread;
3364 private final String defaultToolTip;
3365 private String lastText = "";
3366
3367 private DelayedTextDocumentListener(final JTextField textFeld) {
3368 super();
3369 this.textField = textFeld;
3370 this.defaultToolTip = textFeld.getToolTipText();
3371
3372 this.delayThread =
3373 new Thread(
3374 new Runnable() {
3375 public void run() {
3376 while (true) {
3377 try {
3378 Thread.sleep(CHECK_PERIOD);
3379 } catch (InterruptedException e) {
3380 }
3381
3382 if (
3383 (System.currentTimeMillis() - lastTimeStamp) < CHECK_PERIOD) {
3384
3385
3386
3387 } else if (
3388 (System.currentTimeMillis() - lastTimeStamp) < (2 * CHECK_PERIOD)) {
3389
3390
3391
3392 if (!(textFeld.getText().trim().equals(lastText.trim()))) {
3393 lastText = textFeld.getText();
3394 EventQueue.invokeLater(new Runnable()
3395 {
3396 public void run()
3397 {
3398 setFilter();
3399 }
3400 });
3401 }
3402 } else {
3403
3404
3405
3406 }
3407 }
3408 }
3409 });
3410
3411 delayThread.setPriority(Thread.MIN_PRIORITY);
3412 delayThread.start();
3413 }
3414
3415
3416
3417
3418
3419
3420 public void insertUpdate(DocumentEvent e) {
3421 notifyChange();
3422 }
3423
3424
3425
3426
3427
3428
3429 public void removeUpdate(DocumentEvent e) {
3430 notifyChange();
3431 }
3432
3433
3434
3435
3436
3437
3438 public void changedUpdate(DocumentEvent e) {
3439 notifyChange();
3440 }
3441
3442
3443
3444
3445 private void notifyChange() {
3446 this.lastTimeStamp = System.currentTimeMillis();
3447 }
3448
3449
3450
3451
3452 private void setFilter() {
3453 if (textField.getText().trim().equals("")) {
3454
3455 textField.setBackground(UIManager.getColor("TextField.background"));
3456 tableRuleMediator.setFilterRule(null);
3457 searchRuleMediator.setFilterRule(null);
3458 textField.setToolTipText(defaultToolTip);
3459 if (findRule != null) {
3460 currentSearchMatchCount=tableModel.getSearchMatchCount();
3461 statusBar.setSearchMatchCount(currentSearchMatchCount, getIdentifier());
3462 }
3463 } else {
3464 try {
3465 tableRuleMediator.setFilterRule(ExpressionRule.getRule(textField.getText()));
3466 searchRuleMediator.setFilterRule(ExpressionRule.getRule(textField.getText()));
3467 textField.setToolTipText(defaultToolTip);
3468 if (findRule != null) {
3469 currentSearchMatchCount=tableModel.getSearchMatchCount();
3470 statusBar.setSearchMatchCount(currentSearchMatchCount, getIdentifier());
3471 }
3472
3473 textField.setBackground(UIManager.getColor("TextField.background"));
3474 } catch (IllegalArgumentException iae) {
3475
3476 textField.setToolTipText(iae.getMessage());
3477 textField.setBackground(ChainsawConstants.INVALID_EXPRESSION_BACKGROUND);
3478 if (findRule != null) {
3479 currentSearchMatchCount=tableModel.getSearchMatchCount();
3480 statusBar.setSearchMatchCount(currentSearchMatchCount, getIdentifier());
3481 }
3482 }
3483 }
3484 }
3485 }
3486
3487 private final class TableMarkerListener extends MouseAdapter {
3488 private JTable markerTable;
3489 private EventContainer markerEventContainer;
3490 private EventContainer otherMarkerEventContainer;
3491
3492 private TableMarkerListener(JTable markerTable, EventContainer markerEventContainer, EventContainer otherMarkerEventContainer) {
3493 this.markerTable = markerTable;
3494 this.markerEventContainer = markerEventContainer;
3495 this.otherMarkerEventContainer = otherMarkerEventContainer;
3496 }
3497
3498 public void mouseClicked(MouseEvent evt) {
3499 if (evt.getClickCount() == 2) {
3500 int row = markerTable.rowAtPoint(evt.getPoint());
3501 if (row != -1) {
3502 LoggingEventWrapper loggingEventWrapper = markerEventContainer.getRow(row);
3503 if (loggingEventWrapper != null) {
3504 Object marker = loggingEventWrapper.getLoggingEvent().getProperty(ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE);
3505 if (marker == null) {
3506 loggingEventWrapper.setProperty(ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE, "set");
3507 } else {
3508 loggingEventWrapper.removeProperty(ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE);
3509 }
3510
3511 markerEventContainer.fireRowUpdated(row, (marker == null));
3512 otherMarkerEventContainer.fireRowUpdated(otherMarkerEventContainer.getRowIndex(loggingEventWrapper), (marker == null));
3513 }
3514 }
3515 }
3516 }
3517 }
3518
3519
3520
3521
3522 private final class TableColumnDetailMouseListener extends MouseMotionAdapter {
3523 private int currentRow = -1;
3524 private JTable detailTable;
3525 private EventContainer detailEventContainer;
3526
3527 private TableColumnDetailMouseListener(JTable detailTable, EventContainer detailEventContainer) {
3528 this.detailTable = detailTable;
3529 this.detailEventContainer = detailEventContainer;
3530 }
3531
3532
3533
3534
3535
3536
3537 public void mouseMoved(MouseEvent evt) {
3538 currentPoint = evt.getPoint();
3539 currentTable = detailTable;
3540
3541 if (preferenceModel.isToolTips()) {
3542 int row = detailTable.rowAtPoint(evt.getPoint());
3543
3544 if ((row == currentRow) || (row == -1)) {
3545 return;
3546 }
3547
3548 currentRow = row;
3549
3550 LoggingEventWrapper event = detailEventContainer.getRow(currentRow);
3551
3552 if (event != null) {
3553 String toolTipText = getToolTipTextForEvent(event);
3554 detailTable.setToolTipText(toolTipText);
3555 }
3556 } else {
3557 detailTable.setToolTipText(null);
3558 }
3559 }
3560 }
3561
3562
3563
3564 private class ChainsawTableColumnModelListener implements TableColumnModelListener {
3565 private JSortTable modelListenerTable;
3566
3567 private ChainsawTableColumnModelListener(JSortTable modelListenerTable) {
3568 this.modelListenerTable = modelListenerTable;
3569 }
3570
3571 public void columnAdded(TableColumnModelEvent e) {
3572
3573 }
3574
3575
3576
3577
3578
3579
3580 public void columnRemoved(TableColumnModelEvent e) {
3581 modelListenerTable.updateSortedColumn();
3582 }
3583
3584
3585
3586
3587
3588
3589 public void columnMoved(TableColumnModelEvent e) {
3590 modelListenerTable.updateSortedColumn();
3591 }
3592
3593
3594
3595
3596
3597
3598 public void columnMarginChanged(ChangeEvent e) {
3599 }
3600
3601
3602
3603
3604
3605
3606 public void columnSelectionChanged(ListSelectionEvent e) {
3607 }
3608 }
3609
3610
3611
3612
3613
3614 private class DetailPaneUpdater implements PropertyChangeListener {
3615 private int selectedRow = -1;
3616 int lastRow = -1;
3617 private DetailPaneUpdater() {
3618 }
3619
3620
3621
3622
3623
3624
3625 private void setSelectedRow(int row) {
3626 selectedRow = row;
3627 updateDetailPane();
3628 }
3629
3630 private void setAndUpdateSelectedRow(int row) {
3631 selectedRow = row;
3632 updateDetailPane(true);
3633 }
3634
3635 private void updateDetailPane() {
3636 updateDetailPane(false);
3637 }
3638
3639
3640
3641 private void updateDetailPane(boolean force) {
3642
3643
3644
3645
3646
3647 if (!preferenceModel.isDetailPaneVisible()) {
3648 return;
3649 }
3650
3651 LoggingEventWrapper loggingEventWrapper = null;
3652 if (force || (selectedRow != -1 && (lastRow != selectedRow))) {
3653 loggingEventWrapper = tableModel.getRow(selectedRow);
3654
3655 if (loggingEventWrapper != null) {
3656 final StringBuffer buf = new StringBuffer();
3657 buf.append(detailLayout.getHeader())
3658 .append(detailLayout.format(loggingEventWrapper.getLoggingEvent())).append(
3659 detailLayout.getFooter());
3660 if (buf.length() > 0) {
3661 try {
3662 final Document doc = detail.getEditorKit().createDefaultDocument();
3663 detail.getEditorKit().read(new StringReader(buf.toString()), doc, 0);
3664
3665 SwingHelper.invokeOnEDT(new Runnable() {
3666 public void run() {
3667 detail.setDocument(doc);
3668 JTextComponentFormatter.applySystemFontAndSize(detail);
3669 detail.setCaretPosition(0);
3670 lastRow = selectedRow;
3671 }
3672 });
3673 } catch (Exception e) {}
3674 }
3675 }
3676 }
3677
3678 if (loggingEventWrapper == null && (lastRow != selectedRow)) {
3679 try {
3680 final Document doc = detail.getEditorKit().createDefaultDocument();
3681 detail.getEditorKit().read(new StringReader("<html>Nothing selected</html>"), doc, 0);
3682 SwingHelper.invokeOnEDT(new Runnable() {
3683 public void run() {
3684 detail.setDocument(doc);
3685 JTextComponentFormatter.applySystemFontAndSize(detail);
3686 detail.setCaretPosition(0);
3687 lastRow = selectedRow;
3688 }
3689 });
3690 } catch (Exception e) {}
3691 }
3692 }
3693
3694
3695
3696
3697
3698
3699 public void propertyChange(PropertyChangeEvent arg0) {
3700 SwingUtilities.invokeLater(
3701 new Runnable() {
3702 public void run() {
3703 updateDetailPane(true);
3704 }
3705 });
3706 }
3707 }
3708 private class ThrowableDisplayMouseAdapter extends MouseAdapter {
3709 private JTable throwableTable;
3710 private EventContainer throwableEventContainer;
3711 final JDialog detailDialog;
3712 final JEditorPane detailArea;
3713 public ThrowableDisplayMouseAdapter(JTable throwableTable, EventContainer throwableEventContainer) {
3714 this.throwableTable = throwableTable;
3715 this.throwableEventContainer = throwableEventContainer;
3716
3717 detailDialog = new JDialog((JFrame) null, true);
3718 Container container = detailDialog.getContentPane();
3719 detailArea = new JEditorPane();
3720 JTextComponentFormatter.applySystemFontAndSize(detailArea);
3721 detailArea.setEditable(false);
3722 Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
3723 detailArea.setPreferredSize(new Dimension(screenDimension.width / 2, screenDimension.height / 2));
3724 container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS));
3725 container.add(new JScrollPane(detailArea));
3726
3727 detailDialog.pack();
3728 }
3729 public void mouseClicked(MouseEvent e)
3730 {
3731 TableColumn column = throwableTable.getColumnModel().getColumn(throwableTable.columnAtPoint(e.getPoint()));
3732 if (!column.getHeaderValue().toString().toUpperCase().equals(ChainsawColumns.getColumnName(ChainsawColumns.INDEX_THROWABLE_COL_NAME))) {
3733 return;
3734 }
3735
3736 LoggingEventWrapper loggingEventWrapper = throwableEventContainer.getRow(throwableTable.getSelectedRow());
3737
3738
3739 String[] ti = loggingEventWrapper.getLoggingEvent().getThrowableStrRep();
3740 if (ti != null && ti.length > 0 && (!(ti.length == 1 && ti[0].equals("")))) {
3741 detailDialog.setTitle(throwableTable.getColumnName(throwableTable.getSelectedColumn()) + " detail...");
3742 StringBuffer buf = new StringBuffer();
3743 buf.append(loggingEventWrapper.getLoggingEvent().getMessage());
3744 buf.append("\n");
3745 for (int i = 0; i < ti.length; i++) {
3746 buf.append(ti[i]).append("\n ");
3747 }
3748
3749 detailArea.setText(buf.toString());
3750 SwingHelper.invokeOnEDT(new Runnable() {
3751 public void run() {
3752 centerAndSetVisible(detailDialog);
3753 }
3754 });
3755 }
3756 }
3757 }
3758
3759 private class MarkerCellEditor implements TableCellEditor {
3760 JTable currentTable;
3761 JTextField textField = new JTextField();
3762 Set cellEditorListeners = new HashSet();
3763 private LoggingEventWrapper currentLoggingEventWrapper;
3764 private final Object mutex = new Object();
3765
3766 public Object getCellEditorValue()
3767 {
3768 return textField.getText();
3769 }
3770
3771 public boolean isCellEditable(EventObject anEvent)
3772 {
3773 return true;
3774 }
3775
3776 public boolean shouldSelectCell(EventObject anEvent)
3777 {
3778 textField.selectAll();
3779 return true;
3780 }
3781
3782 public boolean stopCellEditing()
3783 {
3784 if (textField.getText().trim().equals("")) {
3785 currentLoggingEventWrapper.removeProperty(ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE);
3786 } else {
3787 currentLoggingEventWrapper.setProperty(ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE, textField.getText());
3788 }
3789
3790 tableModel.fireRowUpdated(tableModel.getRowIndex(currentLoggingEventWrapper), true);
3791 int index = searchModel.getRowIndex(currentLoggingEventWrapper);
3792 if (index > -1) {
3793 searchModel.fireRowUpdated(index, true);
3794 }
3795
3796 ChangeEvent event = new ChangeEvent(currentTable);
3797 Set cellEditorListenersCopy;
3798 synchronized(mutex) {
3799 cellEditorListenersCopy = new HashSet(cellEditorListeners);
3800 }
3801
3802 for (Iterator iter = cellEditorListenersCopy.iterator();iter.hasNext();) {
3803 ((CellEditorListener)iter.next()).editingStopped(event);
3804 }
3805 currentLoggingEventWrapper = null;
3806 currentTable = null;
3807
3808 return true;
3809 }
3810
3811 public void cancelCellEditing()
3812 {
3813 Set cellEditorListenersCopy;
3814 synchronized(mutex) {
3815 cellEditorListenersCopy = new HashSet(cellEditorListeners);
3816 }
3817
3818 ChangeEvent event = new ChangeEvent(currentTable);
3819 for (Iterator iter = cellEditorListenersCopy.iterator();iter.hasNext();) {
3820 ((CellEditorListener)iter.next()).editingCanceled(event);
3821 }
3822 currentLoggingEventWrapper = null;
3823 currentTable = null;
3824 }
3825
3826 public void addCellEditorListener(CellEditorListener l)
3827 {
3828 synchronized(mutex) {
3829 cellEditorListeners.add(l);
3830 }
3831 }
3832
3833 public void removeCellEditorListener(CellEditorListener l)
3834 {
3835 synchronized(mutex) {
3836 cellEditorListeners.remove(l);
3837 }
3838 }
3839
3840 public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)
3841 {
3842 currentTable = table;
3843 currentLoggingEventWrapper =((EventContainer) table.getModel()).getRow(row);
3844 if (currentLoggingEventWrapper != null) {
3845 textField.setText(currentLoggingEventWrapper.getLoggingEvent().getProperty(ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE));
3846 textField.selectAll();
3847 }
3848 else {
3849 textField.setText("");
3850 }
3851 return textField;
3852 }
3853 }
3854
3855 private class EventTimeDeltaMatchThumbnail extends AbstractEventMatchThumbnail {
3856 public EventTimeDeltaMatchThumbnail() {
3857 super();
3858 initializeLists();
3859 }
3860
3861 boolean primaryMatches(ThumbnailLoggingEventWrapper wrapper) {
3862 String millisDelta = wrapper.loggingEventWrapper.getLoggingEvent().getProperty(ChainsawConstants.MILLIS_DELTA_COL_NAME_LOWERCASE);
3863 if (millisDelta != null && !millisDelta.trim().equals("")) {
3864 long millisDeltaLong = Long.parseLong(millisDelta);
3865
3866 return millisDeltaLong >= 1000;
3867 }
3868 return false;
3869 }
3870
3871 boolean secondaryMatches(ThumbnailLoggingEventWrapper wrapper) {
3872
3873 return false;
3874 }
3875
3876 private void initializeLists() {
3877 secondaryList.clear();
3878 primaryList.clear();
3879
3880 int i=0;
3881 for (Iterator iter = tableModel.getFilteredEvents().iterator();iter.hasNext();) {
3882 LoggingEventWrapper loggingEventWrapper = (LoggingEventWrapper) iter.next();
3883 ThumbnailLoggingEventWrapper wrapper = new ThumbnailLoggingEventWrapper(i, loggingEventWrapper);
3884 i++;
3885
3886 if (primaryMatches(wrapper)) {
3887 primaryList.add(wrapper);
3888 }
3889 }
3890 revalidate();
3891 repaint();
3892 }
3893
3894 public void paintComponent(Graphics g) {
3895 super.paintComponent(g);
3896
3897 int rowCount = table.getRowCount();
3898 if (rowCount == 0) {
3899 return;
3900 }
3901
3902
3903 int height = eventsPane.getHeight();
3904 int maxHeight = Math.min(maxEventHeight, (height / rowCount));
3905 int minHeight = Math.max(1, maxHeight);
3906 int componentHeight = height - minHeight;
3907 int eventHeight = minHeight;
3908
3909
3910 for (Iterator iter = primaryList.iterator();iter.hasNext();) {
3911 ThumbnailLoggingEventWrapper wrapper = (ThumbnailLoggingEventWrapper)iter.next();
3912 if (primaryMatches(wrapper)) {
3913 float ratio = (wrapper.rowNum / (float)rowCount);
3914
3915 int verticalLocation = (int) (componentHeight * ratio);
3916
3917 int startX = 1;
3918 int width = getWidth() - (startX * 2);
3919
3920 String millisDelta = wrapper.loggingEventWrapper.getLoggingEvent().getProperty(ChainsawConstants.MILLIS_DELTA_COL_NAME_LOWERCASE);
3921 long millisDeltaLong = Long.parseLong(millisDelta);
3922 long delta = Math.min(ChainsawConstants.MILLIS_DELTA_RENDERING_HEIGHT_MAX, Math.max(0, (long) (millisDeltaLong * ChainsawConstants.MILLIS_DELTA_RENDERING_FACTOR)));
3923 float widthMaxMillisDeltaRenderRatio = ((float)width / ChainsawConstants.MILLIS_DELTA_RENDERING_HEIGHT_MAX);
3924 int widthToUse = Math.max(2, (int)(delta * widthMaxMillisDeltaRenderRatio));
3925 eventHeight = Math.min(maxEventHeight, eventHeight + 3);
3926
3927 drawEvent(applicationPreferenceModel.getDeltaColor(), (verticalLocation - eventHeight + 1), eventHeight, g, startX, widthToUse);
3928
3929 }
3930 }
3931 }
3932 }
3933
3934
3935 private class ColorizedEventAndSearchMatchThumbnail extends AbstractEventMatchThumbnail {
3936 public ColorizedEventAndSearchMatchThumbnail() {
3937 super();
3938 configureColors();
3939 }
3940
3941 boolean primaryMatches(ThumbnailLoggingEventWrapper wrapper) {
3942 return !wrapper.loggingEventWrapper.getColorRuleBackground().equals(ChainsawConstants.COLOR_DEFAULT_BACKGROUND);
3943 }
3944
3945 boolean secondaryMatches(ThumbnailLoggingEventWrapper wrapper) {
3946 return wrapper.loggingEventWrapper.isSearchMatch();
3947 }
3948
3949 private void configureColors() {
3950 secondaryList.clear();
3951 primaryList.clear();
3952
3953 int i=0;
3954 for (Iterator iter = tableModel.getFilteredEvents().iterator();iter.hasNext();) {
3955 LoggingEventWrapper loggingEventWrapper = (LoggingEventWrapper) iter.next();
3956 ThumbnailLoggingEventWrapper wrapper = new ThumbnailLoggingEventWrapper(i, loggingEventWrapper);
3957 if (secondaryMatches(wrapper)) {
3958 secondaryList.add(wrapper);
3959 }
3960 i++;
3961
3962 if (primaryMatches(wrapper)) {
3963 primaryList.add(wrapper);
3964 }
3965 }
3966 revalidate();
3967 repaint();
3968 }
3969
3970 public void paintComponent(Graphics g) {
3971 super.paintComponent(g);
3972
3973 int rowCount = table.getRowCount();
3974 if (rowCount == 0) {
3975 return;
3976 }
3977
3978
3979 int height = eventsPane.getHeight();
3980 int maxHeight = Math.min(maxEventHeight, (height / rowCount));
3981 int minHeight = Math.max(1, maxHeight);
3982 int componentHeight = height - minHeight;
3983 int eventHeight = minHeight;
3984
3985
3986 for (Iterator iter = primaryList.iterator();iter.hasNext();) {
3987 ThumbnailLoggingEventWrapper wrapper = (ThumbnailLoggingEventWrapper)iter.next();
3988 if (!wrapper.loggingEventWrapper.getColorRuleBackground().equals(ChainsawConstants.COLOR_DEFAULT_BACKGROUND)) {
3989 if (wrapper.loggingEventWrapper.getLoggingEvent().getLevel().toInt() < Level.WARN.toInt() && wrapper.loggingEventWrapper.getLoggingEvent().getProperty(ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE) == null) {
3990 float ratio = (wrapper.rowNum / (float)rowCount);
3991
3992 int verticalLocation = (int) (componentHeight * ratio);
3993
3994 int startX = 1;
3995 int width = getWidth() - (startX * 2);
3996
3997 drawEvent(wrapper.loggingEventWrapper.getColorRuleBackground(), verticalLocation, eventHeight, g, startX, width);
3998
3999 }
4000 }
4001 }
4002
4003
4004 for (Iterator iter = primaryList.iterator();iter.hasNext();) {
4005 ThumbnailLoggingEventWrapper wrapper = (ThumbnailLoggingEventWrapper)iter.next();
4006 if (!wrapper.loggingEventWrapper.getColorRuleBackground().equals(ChainsawConstants.COLOR_DEFAULT_BACKGROUND)) {
4007 if (wrapper.loggingEventWrapper.getLoggingEvent().getLevel().toInt() >= Level.WARN.toInt() || wrapper.loggingEventWrapper.getLoggingEvent().getProperty(ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE) != null) {
4008 float ratio = (wrapper.rowNum / (float)rowCount);
4009
4010 int verticalLocation = (int) (componentHeight * ratio);
4011
4012 int startX = 1;
4013 int width = getWidth() - (startX * 2);
4014
4015
4016
4017 eventHeight = Math.min(maxEventHeight, eventHeight + 3);
4018
4019
4020 drawEvent(wrapper.loggingEventWrapper.getColorRuleBackground(), (verticalLocation - eventHeight + 1), eventHeight, g, startX, width);
4021
4022 }
4023 }
4024 }
4025
4026 for (Iterator iter = secondaryList.iterator();iter.hasNext();) {
4027 ThumbnailLoggingEventWrapper wrapper = (ThumbnailLoggingEventWrapper)iter.next();
4028 float ratio = (wrapper.rowNum / (float)rowCount);
4029
4030 int verticalLocation = (int) (componentHeight * ratio);
4031
4032 int startX = 1;
4033 int width = getWidth() - (startX * 2);
4034 width = (width / 2);
4035
4036
4037 drawEvent(Color.BLACK, verticalLocation, eventHeight, g, startX, width);
4038
4039 }
4040 }
4041 }
4042
4043 abstract class AbstractEventMatchThumbnail extends JPanel {
4044 protected List primaryList = new ArrayList();
4045 protected List secondaryList = new ArrayList();
4046 protected final int maxEventHeight = 6;
4047
4048 AbstractEventMatchThumbnail() {
4049 super();
4050 addMouseMotionListener(new MouseMotionAdapter() {
4051 public void mouseMoved(MouseEvent e) {
4052 if (preferenceModel.isThumbnailBarToolTips()) {
4053 int yPosition = e.getPoint().y;
4054 ThumbnailLoggingEventWrapper event = getEventWrapperAtPosition(yPosition);
4055 if (event != null) {
4056 setToolTipText(getToolTipTextForEvent(event.loggingEventWrapper));
4057 }
4058 } else {
4059 setToolTipText(null);
4060 }
4061 }
4062 });
4063
4064 addMouseListener(new MouseAdapter(){
4065 public void mouseClicked(MouseEvent e)
4066 {
4067 int yPosition = e.getPoint().y;
4068 ThumbnailLoggingEventWrapper event = getEventWrapperAtPosition(yPosition);
4069
4070 if (event != null) {
4071 int id = Integer.parseInt(event.loggingEventWrapper.getLoggingEvent().getProperty("log4jid"));
4072 setSelectedEvent(id);
4073 }
4074 }
4075 });
4076
4077 tableModel.addTableModelListener(new TableModelListener(){
4078 public void tableChanged(TableModelEvent e) {
4079 int firstRow = e.getFirstRow();
4080
4081 int lastRow = Math.min(e.getLastRow(), table.getRowCount() - 1);
4082
4083 if (firstRow < 0 || lastRow < 0) {
4084 primaryList.clear();
4085 secondaryList.clear();
4086 }
4087
4088
4089
4090 List displayedEvents = tableModel.getFilteredEvents();
4091 if (e.getType() == TableModelEvent.INSERT) {
4092
4093 for (int i=firstRow;i<lastRow;i++) {
4094 LoggingEventWrapper event = (LoggingEventWrapper)displayedEvents.get(i);
4095 ThumbnailLoggingEventWrapper wrapper = new ThumbnailLoggingEventWrapper(i, event);
4096 if (secondaryMatches(wrapper)) {
4097 secondaryList.add(wrapper);
4098
4099 }
4100 if (primaryMatches(wrapper)) {
4101
4102 primaryList.add(wrapper);
4103 }
4104
4105 }
4106
4107
4108
4109 } else if (e.getType() == TableModelEvent.DELETE) {
4110
4111
4112 for (Iterator iter = secondaryList.iterator();iter.hasNext();) {
4113 ThumbnailLoggingEventWrapper wrapper = (ThumbnailLoggingEventWrapper)iter.next();
4114 if ((wrapper.rowNum >= firstRow) && (wrapper.rowNum <= lastRow)) {
4115
4116 iter.remove();
4117 }
4118 }
4119 for (Iterator iter = primaryList.iterator();iter.hasNext();) {
4120 ThumbnailLoggingEventWrapper wrapper = (ThumbnailLoggingEventWrapper)iter.next();
4121 if ((wrapper.rowNum >= firstRow) && (wrapper.rowNum <= lastRow)) {
4122
4123 iter.remove();
4124 }
4125 }
4126
4127
4128
4129 } else if (e.getType() == TableModelEvent.UPDATE) {
4130
4131
4132 for (Iterator iter = secondaryList.iterator();iter.hasNext();) {
4133 ThumbnailLoggingEventWrapper wrapper = (ThumbnailLoggingEventWrapper)iter.next();
4134 if ((wrapper.rowNum >= firstRow) && (wrapper.rowNum <= lastRow)) {
4135
4136 iter.remove();
4137 }
4138 }
4139 for (Iterator iter = primaryList.iterator();iter.hasNext();) {
4140 ThumbnailLoggingEventWrapper wrapper = (ThumbnailLoggingEventWrapper)iter.next();
4141 if ((wrapper.rowNum >= firstRow) && (wrapper.rowNum <= lastRow)) {
4142
4143 iter.remove();
4144 }
4145 }
4146
4147
4148 for (int i=firstRow;i<=lastRow;i++) {
4149 LoggingEventWrapper event = (LoggingEventWrapper)displayedEvents.get(i);
4150 ThumbnailLoggingEventWrapper wrapper = new ThumbnailLoggingEventWrapper(i, event);
4151
4152
4153 if (primaryMatches(wrapper)) {
4154
4155 primaryList.add(wrapper);
4156 } else {
4157 primaryList.remove(wrapper);
4158 }
4159
4160 if (secondaryMatches(wrapper)) {
4161
4162
4163 secondaryList.add(wrapper);
4164 } else {
4165 secondaryList.remove(wrapper);
4166 }
4167 }
4168
4169 }
4170 revalidate();
4171 repaint();
4172
4173 EventQueue.invokeLater(new Runnable() {
4174 public void run() {
4175 if (isScrollToBottom()) {
4176 scrollToBottom();
4177 }
4178 }});
4179 }
4180 });
4181 }
4182
4183 abstract boolean primaryMatches(ThumbnailLoggingEventWrapper wrapper);
4184
4185 abstract boolean secondaryMatches(ThumbnailLoggingEventWrapper wrapper);
4186
4187
4188
4189
4190
4191 protected ThumbnailLoggingEventWrapper getEventWrapperAtPosition(int yPosition) {
4192 int rowCount = table.getRowCount();
4193
4194
4195 int height = eventsPane.getHeight();
4196
4197 yPosition = Math.max(yPosition, 0);
4198
4199
4200 if (yPosition >= height) {
4201 yPosition = height;
4202 }
4203
4204
4205 float ratio = (float) yPosition / height;
4206 int rowToSelect = Math.round(rowCount * ratio);
4207
4208 ThumbnailLoggingEventWrapper event = getClosestRow(rowToSelect);
4209 return event;
4210 }
4211
4212 private ThumbnailLoggingEventWrapper getClosestRow(int rowToSelect) {
4213 ThumbnailLoggingEventWrapper closestRow = null;
4214 int rowDelta = Integer.MAX_VALUE;
4215 for (Iterator iter = secondaryList.iterator();iter.hasNext();) {
4216 ThumbnailLoggingEventWrapper event = (ThumbnailLoggingEventWrapper) iter.next();
4217 int newRowDelta = Math.abs(rowToSelect - event.rowNum);
4218 if (newRowDelta < rowDelta) {
4219 closestRow = event;
4220 rowDelta = newRowDelta;
4221 }
4222 }
4223 for (Iterator iter = primaryList.iterator();iter.hasNext();) {
4224 ThumbnailLoggingEventWrapper event = (ThumbnailLoggingEventWrapper) iter.next();
4225 int newRowDelta = Math.abs(rowToSelect - event.rowNum);
4226 if (newRowDelta < rowDelta) {
4227 closestRow = event;
4228 rowDelta = newRowDelta;
4229 }
4230 }
4231 return closestRow;
4232 }
4233
4234 public Point getToolTipLocation(MouseEvent event) {
4235
4236 return new Point(event.getX(), event.getY() + 30);
4237 }
4238
4239 protected void drawEvent(Color newColor, int verticalLocation, int eventHeight, Graphics g, int x, int width) {
4240
4241
4242 int y = verticalLocation + (eventHeight / 2);
4243 Color oldColor = g.getColor();
4244 g.setColor(newColor);
4245 g.fillRect(x, y, width, eventHeight);
4246 if (eventHeight >= 3) {
4247 g.setColor(newColor.darker());
4248 g.drawRect(x, y, width, eventHeight);
4249 }
4250 g.setColor(oldColor);
4251 }
4252 }
4253
4254 class ThumbnailLoggingEventWrapper {
4255 int rowNum;
4256 LoggingEventWrapper loggingEventWrapper;
4257 public ThumbnailLoggingEventWrapper(int rowNum, LoggingEventWrapper loggingEventWrapper) {
4258 this.rowNum = rowNum;
4259 this.loggingEventWrapper = loggingEventWrapper;
4260 }
4261
4262 public String toString() {
4263 return "event - rownum: " + rowNum + ", level: " + loggingEventWrapper.getLoggingEvent().getLevel();
4264 }
4265
4266 public boolean equals(Object o) {
4267 if (this == o) {
4268 return true;
4269 }
4270 if (o == null || getClass() != o.getClass()) {
4271 return false;
4272 }
4273
4274 ThumbnailLoggingEventWrapper that = (ThumbnailLoggingEventWrapper) o;
4275
4276 if (loggingEventWrapper != null ? !loggingEventWrapper.equals(that.loggingEventWrapper) : that.loggingEventWrapper != null) {
4277 return false;
4278 }
4279
4280 return true;
4281 }
4282
4283 public int hashCode() {
4284 return loggingEventWrapper != null ? loggingEventWrapper.hashCode() : 0;
4285 }
4286 }
4287
4288 class AutoFilterComboBox extends JComboBox {
4289 private boolean bypassFiltering;
4290 private List allEntries = new ArrayList();
4291 private List displayedEntries = new ArrayList();
4292 private AutoFilterComboBoxModel model = new AutoFilterComboBoxModel();
4293
4294 private final JTextField textField = new JTextField();
4295 private String lastTextToMatch;
4296
4297 public AutoFilterComboBox() {
4298 textField.setPreferredSize(getPreferredSize());
4299 setModel(model);
4300 setEditor(new AutoFilterEditor());
4301 ((JTextField)getEditor().getEditorComponent()).getDocument().addDocumentListener(new AutoFilterDocumentListener());
4302 setEditable(true);
4303 addPopupMenuListener(new PopupMenuListenerImpl());
4304 }
4305
4306 public Vector getModelData() {
4307
4308 Vector vector = new Vector();
4309 for (Iterator iter = allEntries.iterator();iter.hasNext();) {
4310 vector.insertElementAt(iter.next(), 0);
4311 }
4312 return vector;
4313 }
4314
4315 private void refilter() {
4316
4317 String textToMatch = getEditor().getItem().toString();
4318 if (bypassFiltering || (lastTextToMatch != null && lastTextToMatch.equals(textToMatch))) {
4319 return;
4320 }
4321 lastTextToMatch = textToMatch;
4322 bypassFiltering = true;
4323 model.removeAllElements();
4324 List entriesCopy = new ArrayList(allEntries);
4325 for (Iterator iter = entriesCopy.iterator();iter.hasNext();) {
4326 String thisEntry = iter.next().toString();
4327 if (thisEntry.toLowerCase(Locale.ENGLISH).contains(textToMatch.toLowerCase())) {
4328 model.addElement(thisEntry);
4329 }
4330 }
4331 bypassFiltering = false;
4332
4333 if (displayedEntries.size() > 0 && !textToMatch.equals("")) {
4334 showPopup();
4335 } else {
4336 hidePopup();
4337 }
4338 }
4339
4340 class AutoFilterEditor implements ComboBoxEditor {
4341 public Component getEditorComponent() {
4342 return textField;
4343 }
4344
4345 public void setItem(Object item) {
4346 if (bypassFiltering) {
4347 return;
4348 }
4349 bypassFiltering = true;
4350 if (item == null) {
4351 textField.setText("");
4352 } else {
4353 textField.setText(item.toString());
4354 }
4355 bypassFiltering = false;
4356 }
4357
4358 public Object getItem() {
4359 return textField.getText();
4360 }
4361
4362 public void selectAll() {
4363 textField.selectAll();
4364 }
4365
4366 public void addActionListener(ActionListener listener) {
4367 textField.addActionListener(listener);
4368 }
4369
4370 public void removeActionListener(ActionListener listener) {
4371 textField.removeActionListener(listener);
4372 }
4373 }
4374
4375 class AutoFilterDocumentListener implements DocumentListener {
4376 public void insertUpdate(DocumentEvent e) {
4377 refilter();
4378 }
4379
4380 public void removeUpdate(DocumentEvent e) {
4381 refilter();
4382 }
4383
4384 public void changedUpdate(DocumentEvent e) {
4385 refilter();
4386 }
4387 }
4388
4389 class AutoFilterComboBoxModel extends AbstractListModel implements MutableComboBoxModel {
4390 private Object selectedItem;
4391
4392 public void addElement(Object obj) {
4393
4394 bypassFiltering = true;
4395
4396 boolean entryExists = !allEntries.contains(obj);
4397 if (entryExists) {
4398 allEntries.add(obj);
4399 }
4400 displayedEntries.add(obj);
4401 if (!entryExists) {
4402 fireIntervalAdded(this, displayedEntries.size() - 1, displayedEntries.size());
4403 }
4404 bypassFiltering = false;
4405 }
4406
4407 public void removeElement(Object obj) {
4408 int index = displayedEntries.indexOf(obj);
4409 if (index != -1) {
4410 removeElementAt(index);
4411 }
4412 }
4413
4414 public void insertElementAt(Object obj, int index) {
4415
4416 if (allEntries.contains(obj)) {
4417 return;
4418 }
4419 bypassFiltering = true;
4420 displayedEntries.add(index, obj);
4421 allEntries.add(index, obj);
4422 fireIntervalAdded(this, index, index);
4423 bypassFiltering = false;
4424 refilter();
4425 }
4426
4427 public void removeElementAt(int index) {
4428 bypassFiltering = true;
4429
4430 Object obj = displayedEntries.get(index);
4431 allEntries.remove(obj);
4432 displayedEntries.remove(obj);
4433 fireIntervalRemoved(this, index, index);
4434 bypassFiltering = false;
4435 refilter();
4436 }
4437
4438 public void setSelectedItem(Object item) {
4439 if ((selectedItem != null && !selectedItem.equals(item)) || selectedItem == null && item != null) {
4440 selectedItem = item;
4441 fireContentsChanged(this, -1, -1);
4442 }
4443 }
4444
4445 public Object getSelectedItem() {
4446 return selectedItem;
4447 }
4448
4449 public int getSize() {
4450 return displayedEntries.size();
4451 }
4452
4453 public Object getElementAt(int index) {
4454 if (index >= 0 && index < displayedEntries.size()) {
4455 return displayedEntries.get(index);
4456 }
4457 return null;
4458 }
4459
4460 public void removeAllElements() {
4461 bypassFiltering = true;
4462 int displayedEntrySize = displayedEntries.size();
4463 if (displayedEntrySize > 0) {
4464 displayedEntries.clear();
4465
4466 fireIntervalRemoved(this, 0, displayedEntrySize - 1);
4467 }
4468 bypassFiltering = false;
4469 }
4470
4471 public void showAllElements() {
4472
4473 removeAllElements();
4474 bypassFiltering = true;
4475 displayedEntries.addAll(allEntries);
4476 if (displayedEntries.size() > 0) {
4477 fireIntervalAdded(this, 0, displayedEntries.size() - 1);
4478 }
4479 bypassFiltering = false;
4480 }
4481 }
4482
4483 private class PopupMenuListenerImpl implements PopupMenuListener {
4484 private boolean willBecomeVisible = false;
4485
4486 public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
4487 bypassFiltering = true;
4488 ((JComboBox)e.getSource()).setSelectedIndex(-1);
4489 bypassFiltering = false;
4490 if (!willBecomeVisible) {
4491
4492 if (displayedEntries.contains(textField.getText())) {
4493 model.showAllElements();
4494 }
4495
4496
4497
4498 JComboBox list = (JComboBox) e.getSource();
4499 willBecomeVisible = true;
4500 try {
4501 list.getUI().setPopupVisible(list, true);
4502 } finally {
4503 willBecomeVisible = false;
4504 }
4505 }
4506 }
4507
4508 public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
4509
4510 }
4511
4512 public void popupMenuCanceled(PopupMenuEvent e) {
4513
4514 }
4515 }
4516 }
4517
4518 class ToggleToolTips extends JCheckBoxMenuItem {
4519 public ToggleToolTips() {
4520 super("Show ToolTips", new ImageIcon(ChainsawIcons.TOOL_TIP));
4521 addActionListener(
4522 new ActionListener() {
4523 public void actionPerformed(ActionEvent evt) {
4524 preferenceModel.setToolTips(isSelected());
4525 }
4526 });
4527 }
4528 }
4529 }