/* ViewerConsolePane.java created 2007-09-11
*
*/
package org.signalml.app.view.workspace;
import static org.signalml.app.util.i18n.SvarogI18n._;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import javax.swing.AbstractAction;
import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.signalml.app.util.IconUtils;
import org.signalml.app.util.logging.ViewerConsoleAppender;
import org.signalml.app.view.Console;
import org.signalml.app.view.common.dialogs.OptionPane;
/** ViewerConsolePane
*
*
* @author Michal Dobaczewski © 2007-2008 CC Otwarte Systemy Komputerowe Sp. z o.o.
*/
public class ViewerConsolePane extends JPanel implements Console {
private static final long serialVersionUID = 1L;
protected static final Logger logger = Logger.getLogger(ViewerConsolePane.class);
private JScrollPane scrollPane;
private PlainDocument document;
private JTextArea textArea;
private boolean scrollLock = false;
private int lockedCaretPosition = 0;
private ViewerFileChooser fileChooser;
private ViewerConsoleAppender consoleAppender;
public void initialize() {
setLayout(new BorderLayout());
setBorder(new EmptyBorder(3,3,3,3));
JToolBar consoleToolBar = new JToolBar(JToolBar.HORIZONTAL);
consoleToolBar.setFloatable(false);
consoleToolBar.add(Box.createHorizontalGlue());
LogDivertLevelListener logDivertLevelListener = new LogDivertLevelListener();
JToggleButton noLogDivertButton = new JToggleButton("", IconUtils.loadClassPathIcon("org/signalml/app/icon/stop.png"));
noLogDivertButton.setActionCommand("0");
noLogDivertButton.addActionListener(logDivertLevelListener);
noLogDivertButton.setToolTipText(_("Do not show log messages in the console"));
JToggleButton errorLogDivertButton = new JToggleButton("", IconUtils.loadClassPathIcon("org/signalml/app/icon/error.png"));
errorLogDivertButton.setActionCommand("1");
errorLogDivertButton.addActionListener(logDivertLevelListener);
errorLogDivertButton.setToolTipText(_("Show only warning and error log messages in the console"));
JToggleButton debugLogDivertButton = new JToggleButton("", IconUtils.loadClassPathIcon("org/signalml/app/icon/bug.png"));
debugLogDivertButton.setActionCommand("2");
debugLogDivertButton.addActionListener(logDivertLevelListener);
debugLogDivertButton.setToolTipText(_("Show all log messages in the console, including debug messages"));
ButtonGroup bg = new ButtonGroup();
bg.add(noLogDivertButton);
bg.add(errorLogDivertButton);
bg.add(debugLogDivertButton);
bg.setSelected(errorLogDivertButton.getModel(), true);
consoleToolBar.add(noLogDivertButton);
consoleToolBar.add(errorLogDivertButton);
consoleToolBar.add(debugLogDivertButton);
consoleToolBar.addSeparator(new Dimension(20,1));
JToggleButton scrollLockButton = new JToggleButton(new ScrollLockAction());
scrollLockButton.setText("");
consoleToolBar.add(scrollLockButton);
consoleToolBar.add(new ClearAction());
if (fileChooser != null) {
consoleToolBar.add(new SaveAsTextAction());
}
this.add(consoleToolBar,BorderLayout.NORTH);
document = new PlainDocument();
textArea = new JTextArea(document);
textArea.setEditable(false);
consoleAppender = new ViewerConsoleAppender();
consoleAppender.setConsole(this);
PatternLayout layout = new PatternLayout("%p [%c] - %m\n");
consoleAppender.setLayout(layout);
consoleAppender.setThreshold(Level.WARN);
Logger.getRootLogger().addAppender(consoleAppender);
scrollPane = new JScrollPane(textArea,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
this.add(scrollPane,BorderLayout.CENTER);
}
public void addText(final String text) {
final Runnable task = new Runnable() {
public void run() {
if (null != document) {
synchronized (document) {
try {
document.insertString(document.getLength(), text, null);
if (scrollLock) {
textArea.setCaretPosition(lockedCaretPosition);
} else {
textArea.setCaretPosition(document.getLength());
}
} catch (BadLocationException ex) {
logger.error("Bad document location", ex);
}
}
}
}
};
if (SwingUtilities.isEventDispatchThread()) {
task.run();
} else {
SwingUtilities.invokeLater(task);
}
}
/** Passes text to {@link #addText} first appending '\n' at the end if it isn't there. */
public void addTextNL(String text) {
if (text.endsWith("\n"))
addText(text);
else
addText(text + "\n");
}
public void saveToFile(File file) throws IOException {
Writer w = null;
try {
w = new FileWriter(file);
synchronized (document) {
try {
w.write(document.getText(0, document.getLength()));
} catch (BadLocationException ex) {
logger.error("Bad document location", ex);
}
}
} finally {
if (w != null) {
w.close();
}
}
}
public ViewerFileChooser getFileChooser() {
return fileChooser;
}
public void setFileChooser(ViewerFileChooser fileChooser) {
this.fileChooser = fileChooser;
}
class ScrollLockAction extends AbstractAction {
private static final long serialVersionUID = 1L;
public ScrollLockAction() {
super(_("Lock scroll"));
putValue(AbstractAction.SMALL_ICON, IconUtils.loadClassPathIcon("org/signalml/app/icon/lock.png"));
putValue(AbstractAction.SHORT_DESCRIPTION, _("Prevent the console from scrolling when new text is appended"));
}
public void actionPerformed(ActionEvent ev) {
JToggleButton tb = (JToggleButton) ev.getSource();
scrollLock = tb.isSelected();
if (scrollLock) {
lockedCaretPosition = textArea.viewToModel(SwingUtilities.convertPoint(scrollPane.getViewport(), 0, scrollPane.getViewport().getHeight()/2, textArea));
}
}
}
class ClearAction extends AbstractAction {
private static final long serialVersionUID = 1L;
public ClearAction() {
super(_("Clear"));
putValue(AbstractAction.SMALL_ICON, IconUtils.loadClassPathIcon("org/signalml/app/icon/trash.png"));
putValue(AbstractAction.SHORT_DESCRIPTION, _("Clear the console"));
}
public void actionPerformed(ActionEvent ev) {
try {
synchronized (document) {
document.replace(0, document.getLength(), "", null);
}
} catch (BadLocationException ex) {
logger.error("Bad document location", ex);
}
lockedCaretPosition = 0;
}
}
class SaveAsTextAction extends AbstractAction {
private static final long serialVersionUID = 1L;
public SaveAsTextAction() {
super(_("Save as text"));
putValue(AbstractAction.SMALL_ICON, IconUtils.loadClassPathIcon("org/signalml/app/icon/script_save.png"));
putValue(AbstractAction.SHORT_DESCRIPTION, _("Save the contents of the console to a text file"));
}
public void actionPerformed(ActionEvent ev) {
File file = fileChooser.chooseConsoleSaveAsTextFile(ViewerConsolePane.this);
if (file != null) {
try {
saveToFile(file);
} catch (IOException ex) {
logger.error("Failed to save console text to file", ex);
OptionPane.showException(ViewerConsolePane.this, "error.failedToSaveFile", ex);
}
}
}
}
class LogDivertLevelListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
int command = Integer.parseInt(e.getActionCommand());
switch (command) {
case 1:
consoleAppender.setThreshold(Level.WARN);
Logger.getRootLogger().addAppender(consoleAppender);
break;
case 2:
consoleAppender.setThreshold(Level.DEBUG);
Logger.getRootLogger().addAppender(consoleAppender);
break;
case 0:
default:
Logger.getRootLogger().removeAppender(consoleAppender);
break;
}
}
}
}