package esmska.gui; import esmska.Context; import esmska.data.Icons; import esmska.data.Log; import esmska.utils.L10N; import esmska.utils.MiscUtils; import java.awt.Component; import java.awt.Image; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.WindowEvent; import java.awt.event.WindowFocusListener; import java.text.DateFormat; import java.util.ArrayList; import java.util.ResourceBundle; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.AbstractAction; import javax.swing.AbstractListModel; import javax.swing.GroupLayout; import javax.swing.GroupLayout.Alignment; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JScrollPane; import javax.swing.KeyStroke; import javax.swing.LayoutStyle.ComponentPlacement; import javax.swing.ListCellRenderer; import javax.swing.SwingConstants; import javax.swing.WindowConstants; import org.openide.awt.Mnemonics; /** Display log records * * @author ripper */ public class LogFrame extends javax.swing.JFrame { private static final Logger logger = Logger.getLogger(LogFrame.class.getName()); private static final ResourceBundle l10n = L10N.l10nBundle; private static final DateFormat timeFormat = DateFormat.getTimeInstance(DateFormat.MEDIUM); private Log log = Log.getInstance(); private LogListModel logModel = new LogListModel(); /** Creates new form LogFrame */ public LogFrame() { initComponents(); this.getRootPane().setDefaultButton(closeButton); //set window images ArrayList<Image> images = new ArrayList<Image>(); images.add(Icons.get("log-16.png").getImage()); images.add(Icons.get("log-32.png").getImage()); images.add(Icons.get("log-48.png").getImage()); setIconImages(images); //close on Ctrl+W String command = "close"; getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke( KeyEvent.VK_W, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), command); getRootPane().getActionMap().put(command, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { closeButtonActionPerformed(e); } }); selectLastRecord(); } /** select last log record in GUI */ private void selectLastRecord() { logList.clearSelection(); int index = logModel.getSize() - 1; logList.setSelectedIndex(index); logList.ensureIndexIsVisible(index); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { jScrollPane1 = new JScrollPane(); logList = new JList(); closeButton = new JButton(); clearButton = new JButton(); copyButton = new JButton(); setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); setTitle(l10n.getString("LogFrame.title")); // NOI18N addWindowFocusListener(new WindowFocusListener() { public void windowGainedFocus(WindowEvent evt) { formWindowGainedFocus(evt); } public void windowLostFocus(WindowEvent evt) { } }); logList.setModel(logModel); logList.setCellRenderer(new LogRenderer()); jScrollPane1.setViewportView(logList); closeButton.setIcon(new ImageIcon(getClass().getResource("/esmska/resources/close-22.png"))); // NOI18N Mnemonics.setLocalizedText(closeButton, l10n.getString("Close_")); closeButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { closeButtonActionPerformed(evt); } }); clearButton.setIcon(new ImageIcon(getClass().getResource("/esmska/resources/clear-22.png"))); // NOI18N Mnemonics.setLocalizedText(clearButton, l10n.getString("LogFrame.clearButton.text")); clearButton.setToolTipText(l10n.getString("LogFrame.clearButton.toolTipText")); // NOI18N clearButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { clearButtonActionPerformed(evt); } }); copyButton.setIcon(new ImageIcon(getClass().getResource("/esmska/resources/copy-22.png"))); // NOI18N Mnemonics.setLocalizedText(copyButton, l10n.getString("CopyToClipboard_")); copyButton.setToolTipText(l10n.getString("LogFrame.copyButton.toolTipText")); // NOI18N copyButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { copyButtonActionPerformed(evt); } }); GroupLayout layout = new GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(Alignment.LEADING) .addComponent(jScrollPane1, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 549, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addComponent(clearButton) .addPreferredGap(ComponentPlacement.RELATED) .addComponent(copyButton) .addPreferredGap(ComponentPlacement.RELATED, 206, Short.MAX_VALUE) .addComponent(closeButton))) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(Alignment.LEADING) .addGroup(Alignment.TRAILING, layout.createSequentialGroup() .addContainerGap() .addComponent(jScrollPane1, GroupLayout.DEFAULT_SIZE, 258, Short.MAX_VALUE) .addPreferredGap(ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(Alignment.LEADING) .addGroup(layout.createParallelGroup(Alignment.BASELINE) .addComponent(closeButton) .addComponent(clearButton)) .addComponent(copyButton)) .addContainerGap()) ); layout.linkSize(SwingConstants.VERTICAL, new Component[] {clearButton, closeButton, copyButton}); pack(); }// </editor-fold>//GEN-END:initComponents private void closeButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed this.setVisible(false); this.dispose(); }//GEN-LAST:event_closeButtonActionPerformed private void clearButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_clearButtonActionPerformed log.clearRecords(); //the last record is also shown in mainframe's status bar //if someone wants to remove all records, he also probably wants to //delete that one too (privacy concerns) Context.mainFrame.getStatusPanel().setStatusMessage(null, null, null, false); }//GEN-LAST:event_clearButtonActionPerformed private void copyButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_copyButtonActionPerformed try { logger.fine("Copying logs to clipboard"); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); StringBuilder builder = new StringBuilder(); for (Log.Record record : log.getRecords()) { builder.append("["); builder.append(timeFormat.format(record.getTime())); builder.append("] "); builder.append(record.getMessage().replaceAll("<.*?>","")); builder.append("\n"); } Transferable text = new StringSelection(builder.toString()); clipboard.setContents(text, null); } catch (IllegalStateException ex) { logger.log(Level.WARNING, "System clipboard not available", ex); } }//GEN-LAST:event_copyButtonActionPerformed private void formWindowGainedFocus(WindowEvent evt) {//GEN-FIRST:event_formWindowGainedFocus closeButton.requestFocusInWindow(); }//GEN-LAST:event_formWindowGainedFocus /** Model for contact list */ private class LogListModel extends AbstractListModel { private int oldSize = getSize(); public LogListModel() { //listen for changes in log and fire events accordingly log.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { switch (e.getID()) { case Log.ACTION_ADD_RECORD: fireContentsChanged(LogListModel.this, 0, getSize()); break; case Log.ACTION_REMOVE_RECORD: case Log.ACTION_CLEAR_RECORDS: fireIntervalRemoved(LogListModel.this, 0, oldSize); break; default: logger.warning("Unknown action event type"); assert false : "Unknown action event type"; } oldSize = getSize(); selectLastRecord(); } }); } @Override public int getSize() { return log.size(); } @Override public Log.Record getElementAt(int index) { return log.getRecords().get(index); } } /** Renderer for records in log list */ private class LogRenderer implements ListCellRenderer { private final ListCellRenderer lafRenderer = new JList().getCellRenderer(); @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { Component c = lafRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); Log.Record record = (Log.Record)value; //display message and time String text = "[" + timeFormat.format(record.getTime()) + "] " + record.getMessage(); ((JLabel)c).setText("<html>" + MiscUtils.escapeHtml(text) + "</html>"); //add record icon ((JLabel)c).setIcon(record.getIcon() != null ? record.getIcon() : Icons.STATUS_BLANK); return c; } } // Variables declaration - do not modify//GEN-BEGIN:variables private JButton clearButton; private JButton closeButton; private JButton copyButton; private JScrollPane jScrollPane1; private JList logList; // End of variables declaration//GEN-END:variables }