package com.ibm.nmon.gui.util; import java.awt.BorderLayout; import java.awt.Toolkit; import javax.swing.AbstractAction; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.ItemListener; import java.awt.event.ItemEvent; import java.util.logging.Logger; import java.util.logging.LogRecord; import java.util.logging.Level; import java.util.logging.Handler; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JLabel; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JRootPane; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.KeyStroke; import javax.swing.TransferHandler; import javax.swing.ImageIcon; import javax.swing.SwingUtilities; import com.ibm.nmon.gui.Styles; import com.ibm.nmon.gui.main.NMONVisualizerGui; import com.ibm.nmon.util.BasicFormatter; public final class LogViewerDialog extends JFrame { private static final long serialVersionUID = 2036301168126084250L; public static final ImageIcon LOG_ICON = Styles.buildIcon("page_error.png"); private final JComboBox<Level> levels; private final JTextArea log; public LogViewerDialog(NMONVisualizerGui gui) { super("Application Log"); setResizable(true); setIconImage(LOG_ICON.getImage()); // there should only be one instance of this class per application // hide this dialog instead of disposing setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE); log = new JTextArea(); log.setColumns(100); log.setRows(30); log.setEditable(false); JScrollPane scroller = new JScrollPane(log); scroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); scroller.setBorder(Styles.DOUBLE_LINE_BORDER); JLabel logLevel = new JLabel("Log Level:"); logLevel.setFont(Styles.LABEL); // logLevel.setBorder(Styles.CONTENT_BORDER); levels = new JComboBox<Level>(new Level[] { Level.SEVERE, Level.WARNING, Level.INFO, Level.FINE, Level.FINEST, Level.OFF }); levels.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { // note, not setting the root logger level // all 3rd party logging will remain set to the default Logger.getLogger("com.ibm.nmon").setLevel((Level) e.getItem()); } }); AbstractAction clearAction = new AbstractAction() { private static final long serialVersionUID = 2136102234176694095L; @Override public void actionPerformed(ActionEvent e) { log.setText(""); } }; JButton clear = new JButton("Clear"); clear.setIcon(Styles.CLEAR_ICON); clear.addActionListener(clearAction); JButton copyAll = new JButton("Copy All"); copyAll.setIcon(Styles.COPY_ICON); copyAll.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { log.selectAll(); log.getTransferHandler().exportToClipboard(log, Toolkit.getDefaultToolkit().getSystemClipboard(), TransferHandler.COPY); } }); ((JComponent) getComponent(0)).getActionMap().put("clear", clearAction); ((JComponent) getComponent(0)).getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, InputEvent.CTRL_DOWN_MASK), "clear"); JPanel header = new JPanel(); header.add(logLevel); header.add(levels); // use temp panels to keep buttons from expanding to fill the entire area JPanel footer = new JPanel(new BorderLayout()); JPanel temp = new JPanel(); temp.add(clear); footer.add(temp, BorderLayout.CENTER); temp = new JPanel(); temp.add(copyAll); footer.add(temp, BorderLayout.LINE_START); // add a spacer to ensure the clear button is actually centered JPanel spacer = new JPanel(); spacer.setPreferredSize(copyAll.getPreferredSize()); temp = new JPanel(); temp.add(spacer); footer.add(temp, BorderLayout.LINE_END); add(header, BorderLayout.PAGE_START); add(scroller, BorderLayout.CENTER); add(footer, BorderLayout.PAGE_END); pack(); configureLogging(); } protected JRootPane createRootPane() { JRootPane rootPane = super.createRootPane(); rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "ESCAPE"); rootPane.getActionMap().put("ESCAPE", new AbstractAction() { private static final long serialVersionUID = 5405906817147819455L; @Override public void actionPerformed(ActionEvent e) { setVisible(false); } }); return rootPane; } private void configureLogging() { Logger root = Logger.getLogger(""); levels.setSelectedItem(root.getLevel()); // remove all existing handlers and add one that logs to this class for (Handler handler : root.getHandlers()) { root.removeHandler(handler); } root.addHandler(new LogHandler()); } private class LogHandler extends Handler { LogHandler() { setFormatter(new BasicFormatter()); } @Override public void publish(LogRecord record) { if (isLoggable(record)) { SwingUtilities.invokeLater(new QueuedLog(getFormatter().format(record))); } } @Override public void flush() {} @Override public void close() {} } // helper class to ensure log events are added to the text area in the Swing event thread private class QueuedLog implements Runnable { private final String toLog; QueuedLog(String toLog) { this.toLog = toLog; } @Override public void run() { log.append(toLog); } } }