/**
* Setup a popup menu triggered for Timestamp column to allow time stamp
* format changes
*/
final JPopupMenu dateFormatChangePopup = new JPopupMenu();
final JRadioButtonMenuItem isoButton =
new JRadioButtonMenuItem(
new AbstractAction("Use ISO8601Format") {
public void actionPerformed(ActionEvent e) {
preferenceModel.setDateFormatPattern("ISO8601");
}
});
final JRadioButtonMenuItem simpleTimeButton =
new JRadioButtonMenuItem(
new AbstractAction("Use simple time") {
public void actionPerformed(ActionEvent e) {
preferenceModel.setDateFormatPattern("HH:mm:ss");
}
});
ButtonGroup dfBG = new ButtonGroup();
dfBG.add(isoButton);
dfBG.add(simpleTimeButton);
isoButton.setSelected(true);
dateFormatChangePopup.add(isoButton);
dateFormatChangePopup.add(simpleTimeButton);
final JCheckBoxMenuItem menuItemToggleToolTips =
new JCheckBoxMenuItem("Show ToolTips");
menuItemToggleToolTips.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent evt) {
preferenceModel.setToolTips(menuItemToggleToolTips.isSelected());
}
});
menuItemToggleToolTips.setIcon(new ImageIcon(ChainsawIcons.TOOL_TIP));
final JCheckBoxMenuItem menuItemLoggerTree =
new JCheckBoxMenuItem("Show Logger Tree panel");
menuItemLoggerTree.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
preferenceModel.setLogTreePanelVisible(
menuItemLoggerTree.isSelected());
}
});
menuItemLoggerTree.setIcon(new ImageIcon(ChainsawIcons.WINDOW_ICON));
final JCheckBoxMenuItem menuItemScrollBottom =
new JCheckBoxMenuItem("Scroll to bottom");
menuItemScrollBottom.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent evt) {
preferenceModel.setScrollToBottom(menuItemScrollBottom.isSelected());
}
});
menuItemScrollBottom.setIcon(
new ImageIcon(ChainsawIcons.SCROLL_TO_BOTTOM));
final JCheckBoxMenuItem menuItemToggleDetails =
new JCheckBoxMenuItem("Show Detail Pane");
menuItemToggleDetails.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
preferenceModel.setDetailPaneVisible(
menuItemToggleDetails.isSelected());
}
});
menuItemToggleDetails.setIcon(new ImageIcon(ChainsawIcons.INFO));
/*
* add preferencemodel listeners
*/
preferenceModel.addPropertyChangeListener(
"levelIcons",
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
renderer.setLevelUseIcons(
((Boolean) evt.getNewValue()).booleanValue());
table.tableChanged(new TableModelEvent(tableModel));
}
});
preferenceModel.addPropertyChangeListener(
"detailPaneVisible",
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
boolean newValue = ((Boolean) evt.getNewValue()).booleanValue();
if (newValue) {
showDetailPane();
} else {
hideDetailPane();
}
}
});
preferenceModel.addPropertyChangeListener(
"logTreePanelVisible",
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
boolean newValue = ((Boolean) evt.getNewValue()).booleanValue();
if (newValue) {
showLogTreePanel();
} else {
hideLogTreePanel();
}
}
});
preferenceModel.addPropertyChangeListener(
"toolTips",
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
renderer.setToolTipsVisible(
((Boolean) evt.getNewValue()).booleanValue());
}
});
preferenceModel.addPropertyChangeListener(
"visibleColumns",
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
TableColumnModel columnModel = table.getColumnModel();
for (int i = 0; i < columnModel.getColumnCount(); i++) {
TableColumn column = columnModel.getColumn(i);
if (
!preferenceModel.isColumnVisible(
column.getHeaderValue().toString())) {
columnModel.removeColumn(column);
}
}
Set columnSet = new HashSet();
Enumeration enumeration = columnModel.getColumns();
while (enumeration.hasMoreElements()) {
TableColumn column = (TableColumn) enumeration.nextElement();
columnSet.add(column.getHeaderValue());
}
for (
Iterator iter = ChainsawColumns.getColumnsNames().iterator();
iter.hasNext();) {
String column = (String) iter.next();
if (
preferenceModel.isColumnVisible(column)
&& !columnSet.contains(column)) {
TableColumn newCol =
new TableColumn(
ChainsawColumns.getColumnsNames().indexOf(column));
newCol.setHeaderValue(column);
columnModel.addColumn(newCol);
}
}
}
});
PropertyChangeListener datePrefsChangeListener =
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
LogPanelPreferenceModel model =
(LogPanelPreferenceModel) evt.getSource();
isoButton.setSelected(model.isUseISO8601Format());
simpleTimeButton.setSelected(
!model.isUseISO8601Format() && !model.isCustomDateFormat());
if (model.isUseISO8601Format()) {
renderer.setDateFormatter(new SimpleDateFormat(Constants.ISO8601_PATTERN));
} else {
renderer.setDateFormatter(
new SimpleDateFormat(model.getDateFormatPattern()));
}
table.tableChanged(new TableModelEvent(tableModel));
}
};
preferenceModel.addPropertyChangeListener(
"dateFormatPattern", datePrefsChangeListener);
preferenceModel.addPropertyChangeListener(
"dateFormatPattern", datePrefsChangeListener);
preferenceModel.addPropertyChangeListener(
"loggerPrecision",
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
LogPanelPreferenceModel model =
(LogPanelPreferenceModel) evt.getSource();
renderer.setLoggerPrecision(model.getLoggerPrecision());
table.tableChanged(new TableModelEvent(tableModel));
}
});
preferenceModel.addPropertyChangeListener(
"toolTips",
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
boolean value = ((Boolean) evt.getNewValue()).booleanValue();
menuItemToggleToolTips.setSelected(value);
}
});
preferenceModel.addPropertyChangeListener(
"logTreePanelVisible",
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
boolean value = ((Boolean) evt.getNewValue()).booleanValue();
menuItemLoggerTree.setSelected(value);
}
});
preferenceModel.addPropertyChangeListener(
"scrollToBottom",
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
boolean value = ((Boolean) evt.getNewValue()).booleanValue();
menuItemScrollBottom.setSelected(value);
scroll = value;
if (scroll) {
table.scrollToBottom(table.columnAtPoint(table.getVisibleRect().getLocation()));
}
}
});
preferenceModel.addPropertyChangeListener(
"detailPaneVisible",
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
boolean value = ((Boolean) evt.getNewValue()).booleanValue();
menuItemToggleDetails.setSelected(value);
}
});
/*
*End of preferenceModel listeners
*/
tableModel = new ChainsawCyclicBufferTableModel(cyclicBufferSize);
table = new JSortTable(tableModel);
//add a listener to update the 'refine focus'
tableModel.addNewKeyListener(new NewKeyListener() {
public void newKeyAdded(NewKeyEvent e) {
columnNameKeywordMap.put(e.getKey(), "PROP." + e.getKey());
}
});
/*
* Set the Display rule to use the mediator, the model will add itself as
* a property change listener and update itself when the rule changes.
*/
tableModel.setDisplayRule(ruleMediator);
tableModel.addEventCountListener(
new EventCountListener() {
public void eventCountChanged(int currentCount, int totalCount) {
if (LogPanel.this.isVisible()) {
statusBar.setSelectedLine(
table.getSelectedRow() + 1, currentCount, totalCount);
}
}
});
tableModel.addEventCountListener(
new EventCountListener() {
final NumberFormat formatter = NumberFormat.getPercentInstance();
boolean warning75 = false;
boolean warning100 = false;
public void eventCountChanged(int currentCount, int totalCount) {
if (tableModel.isCyclic()) {
double percent =
((double) totalCount) / ((ChainsawCyclicBufferTableModel) tableModel)
.getMaxSize();
String msg = null;
if ((percent > 0.75) && (percent < 1.0) && !warning75) {
msg =
"Warning :: " + formatter.format(percent) + " of the '"
+ getIdentifier() + "' buffer has been used";
warning75 = true;
} else if ((percent >= 1.0) && !warning100) {
msg =
"Warning :: " + formatter.format(percent) + " of the '"
+ getIdentifier()
+ "' buffer has been used. Older events are being discarded.";
warning100 = true;
}
if (msg != null) {
MessageCenter.getInstance().getLogger().info(msg);
}
}
}
});
/*
* Logger tree panel
*
*/
LogPanelLoggerTreeModel logTreeModel = new LogPanelLoggerTreeModel();
logTreePanel = new LoggerNameTreePanel(logTreeModel, preferenceModel);
tableModel.addLoggerNameListener(logTreeModel);
/**
* Set the LoggerRule to be the LoggerTreePanel, as this visual component
* is a rule itself, and the RuleMediator will automatically listen when
* it's rule state changes.
*/
ruleMediator.setLoggerRule(logTreePanel);
colorizer.setLoggerRule(logTreePanel.getLoggerColorRule());
/*
* Color rule frame and panel
*/
colorFrame.setTitle("'" + identifier + "' Color Filter");
colorFrame.setIconImage(
((ImageIcon) ChainsawIcons.ICON_PREFERENCES).getImage());
final ColorPanel colorPanel = new ColorPanel(colorizer, filterModel);
colorFrame.getContentPane().add(colorPanel);
colorPanel.setCloseActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
colorFrame.setVisible(false);
}
});
colorizer.addPropertyChangeListener(
"colorrule",
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (table != null) {
table.repaint();
}
}
});
/*
* Table definition. Actual construction is above (next to tablemodel)
*/
table.setRowHeight(20);
table.setShowGrid(false);
table.getColumnModel().addColumnModelListener(
new ChainsawTableColumnModelListener());
table.setAutoCreateColumnsFromModel(false);
table.addMouseMotionListener(new TableColumnDetailMouseListener());
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
//set valueisadjusting if holding down a key - don't process setdetail events
table.addKeyListener(
new KeyListener() {
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
synchronized (detail) {
table.getSelectionModel().setValueIsAdjusting(true);
detail.notify();
}
}
public void keyReleased(KeyEvent e) {
synchronized (detail) {
table.getSelectionModel().setValueIsAdjusting(false);
detail.notify();
}
}
});
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.getSelectionModel().addListSelectionListener(
new ListSelectionListener() {
public void valueChanged(ListSelectionEvent evt) {
if (
((evt.getFirstIndex() == evt.getLastIndex())
&& (evt.getFirstIndex() > 0)) || (evt.getValueIsAdjusting())) {
return;
}
boolean lastIndexOnLastRow = (evt.getLastIndex() == (table.getRowCount() - 1));
boolean lastIndexSame = (previousLastIndex == evt.getLastIndex());
/*
* when scroll-to-bottom is active, here is what events look like:
* rowcount-1: 227, last: 227, previous last: 191..first: 191
*
* when the user has unselected the bottom row, here is what the events look like:
* rowcount-1: 227, last: 227, previous last: 227..first: 222
*
* note: previouslast is set after it is evaluated in the bypass scroll check
*/
//System.out.println("rowcount: " + (table.getRowCount() - 1) + ", last: " + evt.getLastIndex() +", previous last: " + previousLastIndex + "..first: " + evt.getFirstIndex());
boolean bypassScrollSelection = (lastIndexOnLastRow && lastIndexSame && previousLastIndex != evt.getFirstIndex());
if (bypassScrollSelection && scroll && table.getRowCount() > 0) {
preferenceModel.setScrollToBottom(false);
}
previousLastIndex = evt.getLastIndex();
final ListSelectionModel lsm = (ListSelectionModel) evt.getSource();
if (lsm.isSelectionEmpty()) {
if (isVisible()) {
statusBar.setNothingSelected();
}
if (detail.getDocument().getDefaultRootElement() != null) {
detailPaneUpdater.setSelectedRow(-1);
}
} else {
if (table.getSelectedRow() > -1) {
int selectedRow = table.getSelectedRow();
if (isVisible()) {
updateStatusBar();
}
try {
if (tableModel.getRowCount() >= selectedRow) {
detailPaneUpdater.setSelectedRow(table.getSelectedRow());
} else {
detailPaneUpdater.setSelectedRow(-1);
}
} catch (Exception e) {
e.printStackTrace();
detailPaneUpdater.setSelectedRow(-1);
}
}
}
}
});
renderer = new TableColorizingRenderer(colorizer);
renderer.setToolTipsVisible(preferenceModel.isToolTips());
table.setDefaultRenderer(Object.class, renderer);
/*
* Throwable popup
*/
throwableRenderPanel = new ThrowableRenderPanel();
final JDialog detailDialog = new JDialog((JFrame) null, true);
Container container = detailDialog.getContentPane();
final JTextArea detailArea = new JTextArea(10, 40);
detailArea.setEditable(false);
container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS));
container.add(new JScrollPane(detailArea));
detailDialog.pack();
throwableRenderPanel.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
Object o = table.getValueAt(
table.getSelectedRow(), table.getSelectedColumn());
if (o == null) {
//no row selected - ignore
logger.debug("no row selected - unable to display throwable popup");
return;
}
detailDialog.setTitle(
table.getColumnName(table.getSelectedColumn()) + " detail...");
if (o instanceof String[]) {
StringBuffer buf = new StringBuffer();
String[] ti = (String[]) o;
buf.append(ti[0]).append("\n");
for (int i = 1; i < ti.length; i++) {
buf.append(ti[i]).append("\n ");
}
detailArea.setText(buf.toString());
} else {
detailArea.setText((o == null) ? "" : o.toString());
}
detailDialog.setLocation(lowerPanel.getLocationOnScreen());
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
detailDialog.setVisible(true);
}
});
}
});
/*
* We listen for new Key's coming in so we can get them automatically
* added as columns
*/
tableModel.addNewKeyListener(
new NewKeyListener() {
public void newKeyAdded(NewKeyEvent e) {
TableColumn col = new TableColumn(e.getNewModelIndex());
col.setHeaderValue(e.getKey());
table.addColumn(col);
}
});
tableModel.addPropertyChangeListener(
"cyclic",
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent arg0) {
if (tableModel.isCyclic()) {
MessageCenter.getInstance().getLogger().warn(
"Changed to Cyclic Mode. Maximum # events kept: "
+ tableModel.getMaxSize());
} else {
MessageCenter.getInstance().getLogger().warn(
"Changed to Unlimited Mode. Warning, you may run out of memory.");
}
}
});
table.getTableHeader().addMouseListener(
new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
checkEvent(e);
}
public void mousePressed(MouseEvent e) {
checkEvent(e);
}
public void mouseReleased(MouseEvent e) {
checkEvent(e);
}
private void checkEvent(MouseEvent e) {
if (e.isPopupTrigger()) {
TableColumnModel colModel = table.getColumnModel();
int index = colModel.getColumnIndexAtX(e.getX());
int modelIndex = colModel.getColumn(index).getModelIndex();
if ((modelIndex + 1) == ChainsawColumns.INDEX_TIMESTAMP_COL_NAME) {
dateFormatChangePopup.show(e.getComponent(), e.getX(), e.getY());
}
}
}
});
/*
* Upper panel definition
*/
JPanel upperPanel = new JPanel(new BorderLayout());
upperPanel.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 0));
final JLabel filterLabel = new JLabel("Refine focus on: ");
filterLabel.setFont(filterLabel.getFont().deriveFont(Font.BOLD));
JPanel upperLeftPanel =
new JPanel(new FlowLayout(FlowLayout.CENTER, 3, 0));
upperLeftPanel.add(filterLabel);
//hold a reference to the combobox model so that we can check to prevent duplicates
final Vector v = new Vector();
//add (hopefully useful) default filters
v.add("LEVEL == TRACE");
v.add("LEVEL == DEBUG");
v.add("LEVEL == INFO");
v.add("LEVEL == WARN");
v.add("LEVEL == ERROR");
v.add("LEVEL == FATAL");
final JComboBox filterCombo = new JComboBox(v);
filterCombo.setSelectedIndex(-1);
final JTextField filterText;
if (filterCombo.getEditor().getEditorComponent() instanceof JTextField) {
String comboToolTipText =
"Enter an expression, press enter to add to list";
filterText = (JTextField) filterCombo.getEditor().getEditorComponent();
filterText.setToolTipText(comboToolTipText);
filterText.addKeyListener(
new ExpressionRuleContext(filterModel, filterText));
filterText.getDocument().addDocumentListener(
new DelayedFilterTextDocumentListener(filterText));
filterCombo.setEditable(true);
filterCombo.addActionListener(
new AbstractAction() {
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("comboBoxEdited")) {
try {
//verify the expression is valid
ExpressionRule.getRule(
filterCombo.getSelectedItem().toString());
} catch (IllegalArgumentException iae) {
//don't add expressions that aren't valid
return;
}
//should be 'valid expression' check
if (!(v.contains(filterCombo.getSelectedItem()))) {
filterCombo.addItem(filterCombo.getSelectedItem());
}
}
}
});
upperPanel.add(filterCombo, BorderLayout.CENTER);
} else {
filterText = new JTextField();
filterText.setToolTipText("Enter an expression");
filterText.addKeyListener(
new ExpressionRuleContext(filterModel, filterText));
filterText.getDocument().addDocumentListener(
new DelayedFilterTextDocumentListener(filterText));
upperPanel.add(filterText, BorderLayout.CENTER);
}
upperPanel.add(upperLeftPanel, BorderLayout.WEST);
JPanel upperRightPanel =
new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
upperPanel.add(upperRightPanel, BorderLayout.EAST);
/*
* Detail pane definition
*/
detail = new JEditorPane(ChainsawConstants.DETAIL_CONTENT_TYPE, "");
detail.setEditable(false);
detailPaneUpdater = new DetailPaneUpdater();
addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
detailPaneUpdater.updateDetailPane();
}
public void focusLost(FocusEvent e) {
}
});
tableModel.addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent e) {
detailPaneUpdater.setSelectedRow(table.getSelectedRow());
}
});
addPropertyChangeListener(
"detailPaneConversionPattern", detailPaneUpdater);
final JScrollPane detailPane = new JScrollPane(detail);
detailPane.setPreferredSize(new Dimension(900, 50));
detailPanel.add(detailPane, BorderLayout.CENTER);
JPanel eventsAndStatusPanel = new JPanel(new BorderLayout());
final JScrollPane eventsPane = new JScrollPane(table);
eventsAndStatusPanel.add(eventsPane, BorderLayout.CENTER);
final JPanel statusLabelPanel = new JPanel();
statusLabelPanel.setLayout(new BorderLayout());
statusLabelPanel.add(upperPanel, BorderLayout.CENTER);
eventsAndStatusPanel.add(statusLabelPanel, BorderLayout.NORTH);
lowerPanel =
new JSplitPane(
JSplitPane.VERTICAL_SPLIT, eventsAndStatusPanel, detailPanel);
dividerSize = lowerPanel.getDividerSize();
lowerPanel.setDividerLocation(-1);
lowerPanel.setResizeWeight(1.0);
lowerPanel.setBorder(null);
lowerPanel.setContinuousLayout(true);
if (preferenceModel.isDetailPaneVisible()) {
showDetailPane();
} else {
hideDetailPane();
}
/*
* Detail panel layout editor
*/
final JToolBar detailToolbar = new JToolBar(SwingConstants.HORIZONTAL);
detailToolbar.setFloatable(false);
final LayoutEditorPane layoutEditorPane = new LayoutEditorPane();
final JDialog layoutEditorDialog =
new JDialog((JFrame) null, "Pattern Editor");
layoutEditorDialog.getContentPane().add(layoutEditorPane);
layoutEditorDialog.setSize(640, 480);
layoutEditorPane.addCancelActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
layoutEditorDialog.setVisible(false);
}
});
layoutEditorPane.addOkActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
setDetailPaneConversionPattern(
layoutEditorPane.getConversionPattern());
layoutEditorDialog.setVisible(false);
}
});
Action editDetailAction =
new AbstractAction(
"Edit...", new ImageIcon(ChainsawIcons.ICON_EDIT_RECEIVER)) {
public void actionPerformed(ActionEvent e) {
layoutEditorPane.setConversionPattern(
getDetailPaneConversionPattern());
Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
Point p =
new Point(
((int) ((size.getWidth() / 2)
- (layoutEditorDialog.getSize().getWidth() / 2))),
((int) ((size.getHeight() / 2)
- (layoutEditorDialog.getSize().getHeight() / 2))));
layoutEditorDialog.setLocation(p);
layoutEditorDialog.setVisible(true);
}
};
editDetailAction.putValue(
Action.SHORT_DESCRIPTION,
"opens a Dialog window to Edit the Pattern Layout text");
final SmallButton editDetailButton = new SmallButton(editDetailAction);
editDetailButton.setText(null);
detailToolbar.add(Box.createHorizontalGlue());
detailToolbar.add(editDetailButton);
detailToolbar.addSeparator();
detailToolbar.add(Box.createHorizontalStrut(5));
Action closeDetailAction =
new AbstractAction(null, LineIconFactory.createCloseIcon()) {
public void actionPerformed(ActionEvent arg0) {
preferenceModel.setDetailPaneVisible(false);
}
};
closeDetailAction.putValue(
Action.SHORT_DESCRIPTION, "Hides the Detail Panel");
SmallButton closeDetailButton = new SmallButton(closeDetailAction);
detailToolbar.add(closeDetailButton);
detailPanel.add(detailToolbar, BorderLayout.NORTH);
JPopupMenu editDetailPopupMenu = new JPopupMenu();
editDetailPopupMenu.add(editDetailAction);
editDetailPopupMenu.addSeparator();
final ButtonGroup layoutGroup = new ButtonGroup();
JRadioButtonMenuItem defaultLayoutRadio =
new JRadioButtonMenuItem(
new AbstractAction("Set to Default Layout") {
public void actionPerformed(ActionEvent e) {
setDetailPaneConversionPattern(
DefaultLayoutFactory.getDefaultPatternLayout());
}
});
editDetailPopupMenu.add(defaultLayoutRadio);
layoutGroup.add(defaultLayoutRadio);
defaultLayoutRadio.setSelected(true);
JRadioButtonMenuItem tccLayoutRadio =
new JRadioButtonMenuItem(
new AbstractAction("Set to TCCLayout") {
public void actionPerformed(ActionEvent e) {
setDetailPaneConversionPattern(
PatternLayout.TTCC_CONVERSION_PATTERN);
}