package net.sourceforge.jnlp.util.logging; import java.awt.Color; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.IOException; import java.util.Observable; import java.util.Observer; import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Pattern; import javax.swing.ButtonGroup; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultHighlighter; import javax.swing.text.Document; import javax.swing.text.PlainDocument; import javax.swing.text.html.HTMLDocument; import net.sourceforge.jnlp.runtime.JNLPRuntime; import net.sourceforge.jnlp.util.logging.headers.ObservableMessagesProvider; public class ConsoleOutputPane extends javax.swing.JPanel implements Observer { @Override public synchronized void update(Observable o, Object arg) { if (!autorefresh.isSelected()) { statistics.setText(model.createStatisticHint()); return; } boolean passed = model.shouldUpdate(); if (!passed) { statistics.setText(model.createStatisticHint()); return; } if (sortBy.getSelectedIndex() == 0) { //no sort, we can just update updatePane(false); } else { refreshPane(); } } private ConsoleOutputPaneModel model; private int lastPostion; //index of search private DefaultHighlighter.DefaultHighlightPainter searchHighligh = new DefaultHighlighter.DefaultHighlightPainter(Color.blue); private Object lastSearchTag; public ConsoleOutputPane(ObservableMessagesProvider dataProvider) { model = new ConsoleOutputPaneModel(dataProvider); initComponents(); regExFilter.setText(ConsoleOutputPaneModel.defaultPattern.pattern()); if (!LogConfig.getLogConfig().isEnableHeaders()) { showHeaders.setSelected(false); } if (JNLPRuntime.isWebstartApplication()) { showPlugin.setSelected(false); showPreInit.setSelected(false); showPostInit.setSelected(false); showIncomplete.setSelected(false); showComplete.setSelected(false); showPlugin.setEnabled(false); showPreInit.setEnabled(false); showPostInit.setEnabled(false); showIncomplete.setEnabled(false); showComplete.setEnabled(false); } regExFilter.getDocument().addDocumentListener(new DocumentListener() { @Override public void insertUpdate(DocumentEvent e) { colorize(); } @Override public void removeUpdate(DocumentEvent e) { colorize(); } @Override public void changedUpdate(DocumentEvent e) { colorize(); } private void colorize() { try { String s = regExFilter.getText(); Pattern p = Pattern.compile(s); model.lastValidPattern = p; regExLabel.setForeground(Color.green); } catch (Exception ex) { regExLabel.setForeground(Color.red); } } }); regExFilter.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(final MouseEvent e) { java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { try { if (e.getButton() != MouseEvent.BUTTON3) { insertChars.setVisible(false); return; } insertChars.setLocation(e.getXOnScreen(), e.getYOnScreen()); insertChars.setVisible(!insertChars.isVisible()); } catch (Exception ex) { OutputController.getLogger().log(ex); } } }); } }); regExFilter.addKeyListener(new KeyAdapter() { @Override public void keyPressed(final KeyEvent e) { if (e.getKeyCode() != KeyEvent.VK_CONTEXT_MENU) { return; } java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { try{ insertChars.setLocation(regExFilter.getLocationOnScreen()); insertChars.setVisible(!insertChars.isVisible()); } catch (Exception ex) { OutputController.getLogger().log(ex); } } }); } }); ButtonGroup matches = new ButtonGroup(); matches.add(match); matches.add(notMatch); showHideActionPerformed(null); updateModel(); refreshPane(); } private ActionListener createDefaultAction() { return new ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { refreshAction(evt); } }; } ActionListener defaultActionSingleton = createDefaultAction(); private ActionListener getDefaultActionSingleton() { return defaultActionSingleton; } private synchronized void refreshPane() { if (highLight.isSelected()) { jEditorPane1.setContentType("text/html"); } else { jEditorPane1.setContentType("text/plain"); } model.lastUpdateIndex = 0; updatePane(true); } /** * when various threads update (and it can be)underlying jeditorpane * simultanouskly, then it can lead to unpredictible issues synchroisation * is doen in invoe later */ private AtomicBoolean done = new AtomicBoolean(true); private synchronized void updatePane(final boolean reset) { if (!done.get()) { return; } done.set(false); java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { try { refreshPaneBody(reset); } catch (Exception ex) { OutputController.getLogger().log(ex); } finally { done.set(true); } } }); } private synchronized void refreshPaneBody(final boolean reset) throws BadLocationException, IOException { if (reset) { jEditorPane1.setText(model.importList(0)); } else { String s = model.importList(); if (highLight.isSelected()) { HTMLDocument orig = (HTMLDocument) jEditorPane1.getDocument(); if (revertSort.isSelected()) { orig.insertAfterEnd(orig.getRootElements()[0].getElement(0)/*body*/, s); } else { orig.insertBeforeEnd(orig.getRootElements()[0], s); } } else { if (revertSort.isSelected()) { jEditorPane1.setText(s + jEditorPane1.getText()); } else { jEditorPane1.setText(jEditorPane1.getText() + s); } } } jEditorPane1.setCaretPosition(0); //jEditorPane1.repaint(); if (mark.isSelected()) { markActionPerformed(null); } statistics.setText(model.createStatisticHint()); } @SuppressWarnings("unchecked") private void initComponents() { jPanel2 = new javax.swing.JPanel(); showHeaders = new javax.swing.JCheckBox(); showUser = new javax.swing.JCheckBox(); sortCopyAll = new javax.swing.JCheckBox(); showOrigin = new javax.swing.JCheckBox(); showLevel = new javax.swing.JCheckBox(); showDate = new javax.swing.JCheckBox(); showThread1 = new javax.swing.JCheckBox(); showThread2 = new javax.swing.JCheckBox(); showMessage = new javax.swing.JCheckBox(); showOut = new javax.swing.JCheckBox(); showErr = new javax.swing.JCheckBox(); showJava = new javax.swing.JCheckBox(); showPlugin = new javax.swing.JCheckBox(); showPreInit = new javax.swing.JCheckBox(); sortByLabel = new javax.swing.JLabel(); regExLabel = new javax.swing.JCheckBox(); sortBy = new javax.swing.JComboBox(); searchLabel = new javax.swing.JLabel(); autorefresh = new javax.swing.JCheckBox(); refresh = new javax.swing.JButton(); apply = new javax.swing.JButton(); regExFilter = new javax.swing.JTextField(); //this is crucial, otherwie PalinDocument implementatin is repalcing all \n by space ((PlainDocument) regExFilter.getDocument()).getDocumentProperties().remove("filterNewlines"); copyPlain = new javax.swing.JButton(); copyRich = new javax.swing.JButton(); next = new javax.swing.JButton(); previous = new javax.swing.JButton(); search = new javax.swing.JTextField(); caseSensitive = new javax.swing.JCheckBox(); showIncomplete = new javax.swing.JCheckBox(); highLight = new javax.swing.JCheckBox(); wordWrap = new javax.swing.JCheckBox(); showDebug = new javax.swing.JCheckBox(); showInfo = new javax.swing.JCheckBox(); showCode = new javax.swing.JCheckBox(); statistics = new javax.swing.JLabel(); showPostInit = new javax.swing.JCheckBox(); showComplete = new javax.swing.JCheckBox(); match = new javax.swing.JRadioButton(); notMatch = new javax.swing.JRadioButton(); revertSort = new javax.swing.JCheckBox(); mark = new javax.swing.JCheckBox(); jScrollPane1 = new javax.swing.JScrollPane(); jEditorPane1 = new javax.swing.JTextPane(); showHide = new javax.swing.JButton(); sortCopyAll.setSelected(true); sortCopyAll.setText("sort copy all by date"); sortCopyAll.setToolTipText("The sort by date is a bit more time consuming, but most natural for posting purposes"); showHeaders.setSelected(true); showHeaders.setText("Show headers:"); showHeaders.addActionListener(getDefaultActionSingleton()); showUser.setSelected(true); showUser.setText("user"); showUser.addActionListener(getDefaultActionSingleton()); showOrigin.setSelected(true); showOrigin.setText("origin"); showOrigin.addActionListener(getDefaultActionSingleton()); showLevel.setSelected(true); showLevel.setText("level"); showLevel.addActionListener(getDefaultActionSingleton()); showDate.setSelected(true); showDate.setText("date"); showDate.addActionListener(getDefaultActionSingleton()); showThread1.setSelected(true); showThread1.setText("thread 1"); showThread1.addActionListener(getDefaultActionSingleton()); showThread2.setSelected(true); showThread2.setText("thread 2"); showThread2.addActionListener(getDefaultActionSingleton()); showMessage.setSelected(true); showMessage.setText("Show messages"); showMessage.addActionListener(getDefaultActionSingleton()); showOut.setSelected(true); showOut.setText("std. Out"); showOut.addActionListener(getDefaultActionSingleton()); showErr.setSelected(true); showErr.setText("std. Err"); showErr.addActionListener(getDefaultActionSingleton()); showJava.setSelected(true); showJava.setText("java"); showJava.addActionListener(getDefaultActionSingleton()); showPlugin.setSelected(true); showPlugin.setText("plugin"); showPlugin.addActionListener(getDefaultActionSingleton()); showPreInit.setSelected(true); showPreInit.setText("pre-init"); showPreInit.setToolTipText("plugin only"); showPreInit.addActionListener(getDefaultActionSingleton()); sortByLabel.setText("Sort by:"); regExLabel.setText("Regular expression filter:"); regExLabel.addActionListener(getDefaultActionSingleton()); sortBy.setModel(new javax.swing.DefaultComboBoxModel(new String[]{"As arrived (no sort)", "user", "origin", "level", "date", "code", "thread1", "thread2", "message"})); sortBy.addActionListener(getDefaultActionSingleton()); searchLabel.setText("Search:"); autorefresh.setSelected(true); autorefresh.setText("auto refresh"); refresh.setText("refresh"); refresh.addActionListener(getDefaultActionSingleton()); apply.setText("Apply"); apply.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { model.usedPattern = model.lastValidPattern; refreshAction(evt); } }); regExFilter.setText(".*"); copyPlain.setText("Copy all (plain)"); copyPlain.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { copyPlainActionPerformed(evt); } }); copyRich.setText("Copy all (rich)"); copyRich.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { copyRichActionPerformed(evt); } }); next.setText("next>>>"); next.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { nextActionPerformed(evt); } }); previous.setText("<<= 0; index--) { String subMatch = document.getText(index, find.length()); if ((caseSensitive.isSelected() && find.equals(subMatch)) || (!caseSensitive.isSelected() && find.equalsIgnoreCase(subMatch))) { if (lastSearchTag != null) { jEditorPane1.getHighlighter().removeHighlight(lastSearchTag); } lastSearchTag = jEditorPane1.getHighlighter().addHighlight(index, index + find.length(), searchHighligh); jEditorPane1.setCaretPosition(index); lastPostion = index - find.length() - 1; return; } } lastPostion = document.getLength() - find.length() - 1; } catch (BadLocationException ex) { OutputController.getLogger().log(ex); } } private void nextActionPerformed(java.awt.event.ActionEvent evt) { try { Document document = jEditorPane1.getDocument(); String find = search.getText(); if (find.length() == 0) { lastPostion = 0; return; } for (int index = lastPostion; index + find.length() < document.getLength(); index++) { String subMatch = document.getText(index, find.length()); if ((caseSensitive.isSelected() && find.equals(subMatch)) || (!caseSensitive.isSelected() && find.equalsIgnoreCase(subMatch))) { if (lastSearchTag != null) { jEditorPane1.getHighlighter().removeHighlight(lastSearchTag); } lastSearchTag = jEditorPane1.getHighlighter().addHighlight(index, index + find.length(), searchHighligh); jEditorPane1.setCaretPosition(index); lastPostion = index + 1; return; } } lastPostion = 0; } catch (BadLocationException ex) { OutputController.getLogger().log(ex); } } private void showHideActionPerformed(java.awt.event.ActionEvent evt) { if (jPanel2.isVisible()) { jPanel2.setVisible(false); showHide.setText("Show controls"); } else { jPanel2.setVisible(true); showHide.setText("Hide"); } } private void copyPlainActionPerformed(java.awt.event.ActionEvent evt) { fillClipBoard(false, sortCopyAll.isSelected()); } private void copyRichActionPerformed(java.awt.event.ActionEvent evt) { fillClipBoard(true, sortCopyAll.isSelected()); } private void fillClipBoard(boolean mark, boolean forceSort){ StringSelection stringSelection ; if (forceSort){ stringSelection = new StringSelection(model.importList(mark, 0, 4/*date*/)); } else { stringSelection = new StringSelection(model.importList(mark, 0)); } Clipboard clpbrd = Toolkit.getDefaultToolkit().getSystemClipboard(); clpbrd.setContents(stringSelection, null); } public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { JFrame dialog = new JFrame(); dialog.setSize(800, 600); dialog.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); ObservableMessagesProvider producer = new ConsoleOutputPaneModel.TestMessagesProvider(); ConsoleOutputPane jPanel1 = new ConsoleOutputPane(producer); producer.getObservable().addObserver(jPanel1); dialog.getContentPane().add(jPanel1, java.awt.BorderLayout.CENTER); dialog.pack(); dialog.setVisible(true); } }); } private void updateModel() { model.highLight = highLight.isSelected(); model.matchPattern = match.isSelected(); model.regExLabel = regExLabel.isSelected(); model.revertSort = revertSort.isSelected(); model.showCode = showCode.isSelected(); model.showComplete = showComplete.isSelected(); model.showDate = showDate.isSelected(); model.showDebug = showDebug.isSelected(); model.showErr = showErr.isSelected(); model.showHeaders = showHeaders.isSelected(); model.showIncomplete = showIncomplete.isSelected(); model.showInfo = showInfo.isSelected(); model.showJava = showJava.isSelected(); model.showLevel = showLevel.isSelected(); model.showMessage = showMessage.isSelected(); model.showOrigin = showOrigin.isSelected(); model.showOut = showOut.isSelected(); model.showPlugin = showPlugin.isSelected(); model.showPostInit = showPostInit.isSelected(); model.showPreInit = showPreInit.isSelected(); model.showThread1 = showThread1.isSelected(); model.showThread2 = showThread2.isSelected(); model.showUser = showUser.isSelected(); model.sortBy = sortBy.getSelectedIndex(); model.wordWrap = wordWrap.isSelected(); } private javax.swing.JButton apply; private javax.swing.JCheckBox autorefresh; private javax.swing.JCheckBox caseSensitive; private javax.swing.JButton copyPlain; private javax.swing.JButton copyRich; private javax.swing.JCheckBox highLight; private javax.swing.JEditorPane jEditorPane1; private javax.swing.JPanel jPanel2; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JCheckBox mark; private javax.swing.JRadioButton match; private javax.swing.JButton next; private javax.swing.JRadioButton notMatch; private javax.swing.JButton previous; private javax.swing.JButton refresh; private javax.swing.JTextField regExFilter; private javax.swing.JCheckBox regExLabel; private javax.swing.JCheckBox revertSort; private javax.swing.JTextField search; private javax.swing.JLabel searchLabel; private javax.swing.JCheckBox showCode; private javax.swing.JCheckBox showComplete; private javax.swing.JCheckBox showDate; private javax.swing.JCheckBox showDebug; private javax.swing.JCheckBox showErr; private javax.swing.JCheckBox showHeaders; private javax.swing.JButton showHide; private javax.swing.JCheckBox showIncomplete; private javax.swing.JCheckBox showInfo; private javax.swing.JCheckBox showJava; private javax.swing.JCheckBox showLevel; private javax.swing.JCheckBox showMessage; private javax.swing.JCheckBox showOrigin; private javax.swing.JCheckBox showOut; private javax.swing.JCheckBox showPlugin; private javax.swing.JCheckBox showPostInit; private javax.swing.JCheckBox showPreInit; private javax.swing.JCheckBox showThread1; private javax.swing.JCheckBox showThread2; private javax.swing.JCheckBox showUser; private javax.swing.JCheckBox sortCopyAll; private javax.swing.JComboBox sortBy; private javax.swing.JLabel sortByLabel; private javax.swing.JLabel statistics; private javax.swing.JCheckBox wordWrap; private javax.swing.JPopupMenu insertChars; }