package org.signalml.app.view.common.dialogs;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Window;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
import org.signalml.app.view.common.components.ProgressState;
/**
* Dialog that shows progress of some time consuming operation.
* It's a Property Change Listener, the only property it reacts to is
* progressState, it's value is a {@link ProgressState} object.
*
* @author Tomasz Sawicki
*/
public class ProgressDialog extends AbstractDialog implements PropertyChangeListener {
public static final String PROGRESS_STATE = "progressState";
public final int DIALOG_WIDTH = 400;
public final int DIALOG_HEIGHT = 280;
/**
* The text area.
*/
private ProgressStateList progressStateList = null;
/**
* The progress bar.
*/
private JProgressBar progressBar = null;
/**
* If there was an error.
*/
private boolean error;
/**
* If there was a success.
*/
private boolean success;
/**
* Default constructor.
*
* @param w parent window
* @param isModal if this window is modal
* @param caption window's caption
*/
public ProgressDialog(Window w, boolean isModal, String title) {
super(w, isModal);
setTitle(title);
setPreferredSize(new Dimension(DIALOG_WIDTH, DIALOG_HEIGHT));
}
/**
* Creates the interface.
*
* @return the interfacesize
*/
@Override
protected JComponent createInterface() {
JPanel interfacePanel = new JPanel(new BorderLayout(10, 10));
CompoundBorder panelBorder = new CompoundBorder(new TitledBorder(""), new EmptyBorder(3, 3, 3, 3));
interfacePanel.setBorder(panelBorder);
interfacePanel.add(new JScrollPane(getProgressStateList()), BorderLayout.CENTER);
interfacePanel.add(getProgressBar(), BorderLayout.PAGE_END);
return interfacePanel;
}
/**
* Gets the text area.
*
* @return the text area
*/
private ProgressStateList getProgressStateList() {
if (progressStateList == null) {
progressStateList = new ProgressStateList();
}
return progressStateList;
}
/**
* Gets the progress bar.
*
* @return the progress bar
*/
private JProgressBar getProgressBar() {
if (progressBar == null) {
progressBar = new JProgressBar();
}
return progressBar;
}
/**
* Only supported model is {@link ProgressState}.
*
* @param clazz class
* @return true if clazz can be assigned to a ProgressState object
*/
@Override
public boolean supportsModelClass(Class<?> clazz) {
return ProgressState.class.isAssignableFrom(clazz);
}
/**
* Fills all components from a {@link ProgressState} object.
*
* @param model a {@link ProgressState} object
*/
@Override
public void fillDialogFromModel(Object model) {
ProgressState state = (ProgressState) model;
error = (state.getCurrentProgress() < 0);
success = (state.getCurrentProgress() == state.getMaxProgress());
getProgressStateList().add(state);
getProgressBar().setValue(state.getCurrentProgress());
getProgressBar().setMaximum(state.getMaxProgress());
if (error || success) {
getOkButton().setEnabled(true);
getCancelButton().setEnabled(false);
} else {
getOkButton().setEnabled(false);
getCancelButton().setEnabled(true);
}
}
/**
* Dialog is read only.
*
* @param model not used
*/
@Override
public void fillModelFromDialog(Object model) {
}
/**
* Only supported property is progressState.
*
* @param evt property change event
*/
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (PROGRESS_STATE.equals(evt.getPropertyName())) {
fillDialogFromModel(evt.getNewValue());
}
}
/**
* No cancel on escape.
*
* @return false
*/
@Override
public boolean isCancelOnEscape() {
return false;
}
/**
* Shows an empty dialog.
*/
public boolean showDialog() {
return showDialog(new ProgressState(), true);
}
/**
* Resets dialog.
*/
@Override
protected void resetDialog() {
super.resetDialog();
getProgressStateList().removeAll();
}
/**
* Returns true if the window was cancelled.
*
* @return true if the window was cancelled
*/
public boolean wasCancelled() {
return (!(error || success));
}
/**
* Returns true if there was a success.
*
* @return true if there was a success
*/
public boolean wasSuccess() {
return success;
}
}
/**
* Class responsible for showing the progress.
*
* @author Tomasz Sawicki
*/
class ProgressStateList extends JList {
/**
* Default constructor
*/
public ProgressStateList() {
setCellRenderer(new ProgressStateListCellRenderer());
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
/**
* Adds an element to the list.
*
* @param state progress state
*/
public void add(ProgressState state) {
if (state.getProgressMsg().equals("")) {
return;
}
Dimension size = getSize();
ArrayList<ProgressState> list = new ArrayList<ProgressState>();
for (int i = 0; i < getModel().getSize(); i++) {
list.add((ProgressState) getModel().getElementAt(i));
}
list.add(state);
setListData(list.toArray());
setSize(size);
}
}
/**
* Renderer for {@link ProgressStateList}
*
* @author Tomasz Sawicki
*/
class ProgressStateListCellRenderer implements ListCellRenderer {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
ProgressState state = (ProgressState) value;
JTextArea textArea = new JTextArea(state.getProgressMsg());
textArea.setBackground(Color.WHITE);
if (state.getCurrentProgress() < 0) {
textArea.setForeground(Color.RED);
} else if (state.getCurrentProgress() == state.getMaxProgress()) {
textArea.setForeground(Color.GREEN);
} else {
textArea.setForeground(Color.BLACK);
}
return textArea;
}
}