package de.lmu.ifi.dbs.elki.gui.util;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2011
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import java.awt.Dimension;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import javax.swing.BoxLayout;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import de.lmu.ifi.dbs.elki.logging.LoggingConfiguration;
import de.lmu.ifi.dbs.elki.logging.progress.FiniteProgress;
import de.lmu.ifi.dbs.elki.logging.progress.IndefiniteProgress;
import de.lmu.ifi.dbs.elki.logging.progress.Progress;
import de.lmu.ifi.dbs.elki.logging.progress.ProgressLogRecord;
import de.lmu.ifi.dbs.elki.logging.progress.StepProgress;
/**
* Panel that contains a text logging pane ({@link LogPane}) and progress bars.
*
* @author Erich Schubert
*
* @apiviz.owns LogPane
* @apiviz.uses LoggingConfiguration
* @apiviz.uses de.lmu.ifi.dbs.elki.logging.ELKILogRecord
* @apiviz.uses ProgressLogRecord
*/
public class LogPanel extends JPanel {
/**
* Serial
*/
private static final long serialVersionUID = 1L;
/**
* The actual text logging pane
*/
protected LogPane logpane = new LogPane();
/**
* Current progress bars
*/
protected HashMap<Progress, JProgressBar> pbarmap = new HashMap<Progress, JProgressBar>();
/**
* Constructor.
*/
public LogPanel() {
super();
super.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
JScrollPane outputPane = new JScrollPane(logpane);
outputPane.setPreferredSize(new Dimension(200, 200));
super.add(outputPane);
}
/**
* Become the default logger.
*/
public void becomeDefaultLogger() {
LoggingConfiguration.replaceDefaultHandler(new LogPanelHandler());
}
/**
* Print a message as if it were logged, without going through the full
* logger.
*
* @param message Message text
* @param level Message level
*/
public void publish(String message, Level level) {
try {
publish(new LogRecord(level, message));
}
catch(Exception e) {
throw new RuntimeException("Error writing a log-like message.", e);
}
}
/**
* Publish a logging record.
*
* @param record Log record to publish
*/
public void publish(final LogRecord record) {
if(record instanceof ProgressLogRecord) {
ProgressLogRecord preg = (ProgressLogRecord) record;
Progress prog = preg.getProgress();
JProgressBar pbar = getOrCreateProgressBar(prog);
updateProgressBar(prog, pbar);
if(prog.isComplete()) {
removeProgressBar(prog, pbar);
}
if(prog.isComplete() || prog instanceof StepProgress) {
publishTextRecord(record);
}
}
else {
publishTextRecord(record);
}
}
/**
* Publish a text record to the pane
*
* @param record Record to publish
*/
private void publishTextRecord(final LogRecord record) {
try {
logpane.publish(record);
}
catch(Exception e) {
throw new RuntimeException("Error writing a log-like message.", e);
}
}
/**
* Get an existing or create a new progress bar.
*
* @param prog Progress
* @return Associated progress bar.
*/
private JProgressBar getOrCreateProgressBar(Progress prog) {
JProgressBar pbar = pbarmap.get(prog);
// Add a new progress bar.
if(pbar == null) {
if(prog instanceof FiniteProgress) {
pbar = new JProgressBar(0, ((FiniteProgress) prog).getTotal());
pbar.setStringPainted(true);
}
else if(prog instanceof IndefiniteProgress) {
pbar = new JProgressBar();
pbar.setIndeterminate(true);
pbar.setStringPainted(true);
}
else {
throw new RuntimeException("Unsupported progress record");
}
pbarmap.put(prog, pbar);
final JProgressBar pbar2 = pbar;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
addProgressBar(pbar2);
}
});
}
return pbar;
}
/**
* Update a progress bar
*
* @param prog Progress
* @param pbar Associated progress bar
*/
private void updateProgressBar(Progress prog, JProgressBar pbar) {
if(prog instanceof FiniteProgress) {
pbar.setValue(((FiniteProgress) prog).getProcessed());
pbar.setString(((FiniteProgress) prog).toString());
}
else if(prog instanceof IndefiniteProgress) {
pbar.setValue(((IndefiniteProgress) prog).getProcessed());
pbar.setString(((IndefiniteProgress) prog).toString());
}
else {
throw new RuntimeException("Unsupported progress record");
}
}
/**
* Remove a progress bar
*
* @param prog Progress
* @param pbar Associated progress bar
*/
private void removeProgressBar(Progress prog, JProgressBar pbar) {
pbarmap.remove(prog);
final JProgressBar pbar2 = pbar;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
removeProgressBar(pbar2);
}
});
}
/**
* Clear the current contents.
*/
public void clear() {
logpane.clear();
for(Entry<Progress, JProgressBar> ent : pbarmap.entrySet()) {
super.remove(ent.getValue());
pbarmap.remove(ent.getKey());
}
}
/**
* Add a new progress bar.
*
* Protected, so this can be called via invokeLater
*
* @param pbar
*/
protected void addProgressBar(final JProgressBar pbar) {
super.add(pbar);
super.revalidate();
}
/**
* Remove a new progress bar.
*
* Protected, so this can be called via invokeLater
*
* @param pbar
*/
protected void removeProgressBar(final JProgressBar pbar) {
super.remove(pbar);
super.revalidate();
}
/**
* Internal {@link java.util.logging.Handler}
*
* @author Erich Schubert
*
* @apiviz.exclude
*/
private class LogPanelHandler extends Handler {
/**
* Constructor.
*/
protected LogPanelHandler() {
super();
}
@Override
public void close() throws SecurityException {
// do nothing
}
@Override
public void flush() {
// do nothing
}
@Override
public void publish(final LogRecord record) {
LogPanel.this.publish(record);
}
}
}