/* ViewerStatusBar.java created 2007-09-10
*
*/
package org.signalml.app.view.workspace;
import static org.signalml.app.util.i18n.SvarogI18n._;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.SwingConstants;
import javax.swing.border.BevelBorder;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.signalml.app.action.selector.ActionFocusEvent;
import org.signalml.app.action.selector.ActionFocusListener;
import org.signalml.app.action.selector.ActionFocusManager;
import org.signalml.app.action.workspace.ViewModeAction;
import org.signalml.app.document.BookDocument;
import org.signalml.app.document.signal.SignalDocument;
import org.signalml.app.util.IconUtils;
import org.signalml.app.view.book.BookPlot;
import org.signalml.app.view.book.BookView;
import org.signalml.app.view.common.components.AntialiasedLabel;
import org.signalml.app.view.signal.PositionedTag;
import org.signalml.app.view.signal.SignalPlot;
import org.signalml.app.view.signal.SignalView;
import org.signalml.domain.montage.Montage;
import org.signalml.exception.SanityCheckException;
import org.signalml.plugin.export.signal.Document;
import org.signalml.plugin.export.signal.SignalSelection;
import org.signalml.plugin.export.signal.SignalSelectionType;
import org.signalml.plugin.export.signal.Tag;
import org.signalml.util.FormatUtils;
/** ViewerStatusBar
*
*
* @author Michal Dobaczewski © 2007-2008 CC Otwarte Systemy Komputerowe Sp. z o.o.
*/
public class ViewerStatusBar extends JPanel implements ActionFocusListener, PropertyChangeListener, ChangeListener {
private static final ImageIcon FILTER_ON_ICON = IconUtils.loadClassPathIcon("org/signalml/app/icon/filteron.png");
private static final ImageIcon FILTER_OFF_ICON = IconUtils.loadClassPathIcon("org/signalml/app/icon/filter.png");
private static final long serialVersionUID = 1L;
private String sampleAbbrevString;
private String pageAbbrevString;
private String blockAbbrevString;
private String pageSelectionString;
private String blockSelectionString;
private String channelSelectionString;
private String pageTagString;
private String blockTagString;
private String channelTagString;
private String filterOnString;
private String filterOffString;
private String filterOnToolTipString;
private String filterOffToolTipString;
private Font statusFont;
private Font smallFont;
private JPanel statusPanel;
private JPanel positionPanel;
private JPanel selectionPanel;
private JPanel filteringPanel;
private JPanel buttonPanel;
private JLabel statusLabel;
private JLabel positionLabel;
private JLabel filteringLabel;
private JLabel selectionLabel;
private JToggleButton viewModeButton;
private ViewModeAction viewModeAction;
private ActionFocusManager actionFocusManager;
private SignalDocument currentSignal = null;
private BookDocument currentBook = null;
private Font filteringFont;
public ViewerStatusBar() {
super(new BorderLayout());
statusFont = new Font(Font.DIALOG, Font.PLAIN, 12);
smallFont = new Font(Font.DIALOG, Font.PLAIN, 9);
filteringFont = new Font(Font.DIALOG, Font.BOLD, 16);
sampleAbbrevString = _("S");
pageAbbrevString = _("P");
blockAbbrevString = _("B");
pageSelectionString = _("Page selection");
blockSelectionString = _("Block selection");
channelSelectionString = _("Channel selection");
pageTagString = _("Page tag");
blockTagString = _("Block tag");
channelTagString = _("Channel tag");
filterOnString = _("ON");
filterOffString = _("OFF");
filterOnToolTipString = _("Filtering is enabled for the master plot");
filterOffToolTipString = _("Filtering is disbled for the master plot");
}
public void initialize() {
statusPanel = new JPanel(new BorderLayout());
statusPanel.setBorder(new CompoundBorder(
new BevelBorder(BevelBorder.LOWERED),
new EmptyBorder(2,4,2,4)
));
statusPanel.add(getStatusLabel(), BorderLayout.CENTER);
positionPanel = new JPanel(new BorderLayout());
positionPanel.setBorder(new CompoundBorder(
new BevelBorder(BevelBorder.LOWERED),
new EmptyBorder(2,4,2,4)
));
positionPanel.setPreferredSize(new Dimension(360,20));
positionPanel.add(getPositionLabel(), BorderLayout.CENTER);
selectionPanel = new JPanel(new BorderLayout());
selectionPanel.setBorder(new CompoundBorder(
new BevelBorder(BevelBorder.LOWERED),
new EmptyBorder(2,4,2,4)
));
selectionPanel.setPreferredSize(new Dimension(360,20));
selectionPanel.add(getSelectionLabel(), BorderLayout.CENTER);
filteringPanel = new JPanel(new BorderLayout());
filteringPanel.setBorder(new CompoundBorder(
new BevelBorder(BevelBorder.LOWERED),
new EmptyBorder(2,4,2,4)
));
filteringPanel.setPreferredSize(new Dimension(65,20));
filteringPanel.add(getFilteringLabel(), BorderLayout.CENTER);
buttonPanel = new JPanel();
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
buttonPanel.setBorder(new EmptyBorder(4,0,4,0));
buttonPanel.add(getViewModeButton());
JPanel fixedPanel = new JPanel();
fixedPanel.setLayout(new BoxLayout(fixedPanel, BoxLayout.X_AXIS));
fixedPanel.add(Box.createHorizontalStrut(3));
fixedPanel.add(positionPanel);
fixedPanel.add(Box.createHorizontalStrut(3));
fixedPanel.add(selectionPanel);
fixedPanel.add(Box.createHorizontalStrut(3));
fixedPanel.add(filteringPanel);
fixedPanel.add(Box.createHorizontalStrut(3));
fixedPanel.add(buttonPanel);
fixedPanel.add(Box.createHorizontalStrut(4));
add(statusPanel, BorderLayout.CENTER);
add(fixedPanel, BorderLayout.EAST);
}
public JLabel getStatusLabel() {
if (statusLabel == null) {
statusLabel = new JLabel();
statusLabel.setFont(statusFont);
statusLabel.setVerticalAlignment(SwingConstants.CENTER);
}
return statusLabel;
}
public JLabel getPositionLabel() {
if (positionLabel == null) {
positionLabel = new AntialiasedLabel();
positionLabel.setFont(smallFont);
positionLabel.setVerticalAlignment(SwingConstants.CENTER);
}
return positionLabel;
}
public JLabel getSelectionLabel() {
if (selectionLabel == null) {
selectionLabel = new AntialiasedLabel();
selectionLabel.setFont(smallFont);
selectionLabel.setVerticalAlignment(SwingConstants.CENTER);
}
return selectionLabel;
}
public JLabel getFilteringLabel() {
if (filteringLabel == null) {
filteringLabel = new AntialiasedLabel();
filteringLabel.setFont(filteringFont);
filteringLabel.setVerticalAlignment(SwingConstants.CENTER);
}
return filteringLabel;
}
public JToggleButton getViewModeButton() {
if (viewModeButton == null) {
viewModeButton = new JToggleButton(viewModeAction) {
private static final long serialVersionUID = 1L;
@Override
public Point getToolTipLocation(MouseEvent event) {
// XXX unusual ergonomy hack: prevent the tooltip from completely obscuring the button,
// which is always at the bottom of the screen
return new Point(0,-20);
}
};
viewModeButton.setBorder(null);
viewModeButton.setHideActionText(true);
viewModeButton.setMargin(new Insets(0,0,0,0));
viewModeButton.setFocusPainted(false);
viewModeButton.setContentAreaFilled(false);
viewModeButton.setSelectedIcon(IconUtils.loadClassPathIcon("org/signalml/app/icon/viewmodeon.png"));
}
return viewModeButton;
}
public void setStatus(String status) {
getStatusLabel().setText(status);
getStatusLabel().setToolTipText(status);
}
public void setPosition(String position) {
getPositionLabel().setText(position);
getPositionLabel().setToolTipText(position);
}
public void setSelection(String selection) {
getSelectionLabel().setText(selection);
getSelectionLabel().setToolTipText(selection);
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (currentSignal != null) {
digestSignalInfo(currentSignal);
}
if (currentBook != null) {
digestBookInfo(currentBook);
}
}
@Override
public void stateChanged(ChangeEvent e) {
if (currentSignal != null) {
digestSignalInfo(currentSignal);
}
}
@Override
public void actionFocusChanged(ActionFocusEvent e) {
clearInfo();
Document document = actionFocusManager.getActiveDocument();
if (document != null) {
if (document instanceof SignalDocument) {
setCurrentSignal((SignalDocument) document);
} else if (document instanceof BookDocument) {
setCurrentBook((BookDocument) document);
}
}
}
private void setCurrentBook(BookDocument currentBook) {
if (this.currentBook != currentBook) {
BookView view;
BookPlot plot;
if (this.currentBook != null) {
this.currentBook.removePropertyChangeListener(this);
view = (BookView) this.currentBook.getDocumentView();
view.removeActionFocusListener(this);
plot = view.getPlot();
plot.removePropertyChangeListener(this);
}
this.currentBook = currentBook;
if (currentBook != null) {
currentBook.addPropertyChangeListener(this);
view = (BookView) currentBook.getDocumentView();
view.addActionFocusListener(this);
plot = view.getPlot();
plot.addPropertyChangeListener(this);
}
}
if (this.currentBook != null) {
digestBookInfo(this.currentBook);
}
}
private void digestBookInfo(BookDocument document) {
BookView view = (BookView) document.getDocumentView();
// BookPlot plot = view.getPlot();
setFiltered(view.getFilter().getFilterChain().isFiltered());
}
private void setCurrentSignal(SignalDocument currentSignal) {
if (this.currentSignal != currentSignal) {
SignalView view;
SignalPlot plot;
if (this.currentSignal != null) {
this.currentSignal.removePropertyChangeListener(this);
view = (SignalView) this.currentSignal.getDocumentView();
view.removeActionFocusListener(this);
plot = view.getMasterPlot();
plot.removePropertyChangeListener(this);
plot.getViewport().removeChangeListener(this);
}
this.currentSignal = currentSignal;
if (currentSignal != null) {
currentSignal.addPropertyChangeListener(this);
view = (SignalView) currentSignal.getDocumentView();
view.addActionFocusListener(this);
plot = view.getMasterPlot();
plot.addPropertyChangeListener(this);
plot.getViewport().addChangeListener(this);
}
}
if (this.currentSignal != null) {
digestSignalInfo(this.currentSignal);
}
}
// TODO this could be optimized slightly by reacting separately
// to changes which involve changing only postion or only selection
// moreover in some situations this can be called repeatedly a few times in a row
// (for example when selection is removed due to passing offscreen)
private void digestSignalInfo(SignalDocument document) {
SignalView view = (SignalView) document.getDocumentView();
SignalPlot plot = view.getMasterPlot();
Point position = plot.getViewport().getViewPosition();
Dimension size = plot.getViewport().getExtentSize();
Point endPosition = new Point(position.x + size.width - 1, position.y + size.height - 1);
double timeZoomFactor = plot.getTimeZoomFactor();
int minSample = (int) Math.max(0, Math.floor(((double)(position.x)) / timeZoomFactor)) + 1;
int maxSample = (int) Math.max(0, Math.ceil(((double)(endPosition.x)) / timeZoomFactor)) + 1;
float minTime = plot.toTimeSpace(position);
float maxTime = plot.toTimeSpace(endPosition);
int minPage = plot.toPageSpace(position) + 1;
int maxPage = plot.toPageSpace(endPosition) + 1;
int minBlock = plot.toBlockSpace(position) + 1;
int maxBlock = plot.toBlockSpace(endPosition) + 1;
StringBuilder sb = new StringBuilder();
FormatUtils.addTime(minTime, sb);
sb.append(" - ");
FormatUtils.addTime(maxTime, sb);
sb.append(" (").append(sampleAbbrevString).append(": ").append(minSample).append('-').append(maxSample).append(')');
sb.append(" (").append(pageAbbrevString).append(": ").append(minPage).append('-').append(maxPage).append(')');
sb.append(" (").append(blockAbbrevString).append(": ").append(minBlock).append('-').append(maxBlock).append(')');
setPosition(sb.toString());
sb = new StringBuilder();
SignalSelection signalSelection = view.getSignalSelection();
if (signalSelection != null) {
addSignalSelection(document, view.getSignalSelectionPlot(), signalSelection, sb);
} else {
PositionedTag tagSelection = view.getTagSelection();
if (tagSelection != null) {
addTag(document, view.getTagSelectionPlot(), tagSelection.getTag(), sb);
}
}
setSelection(sb.toString());
setFiltered(document.getMontage().isFiltered());
}
private void setFiltered(boolean filtered) {
JLabel label = getFilteringLabel();
if (filtered) {
label.setIcon(FILTER_ON_ICON);
label.setForeground(Color.BLUE);
label.setText(filterOnString);
label.setToolTipText(filterOnToolTipString);
} else {
label.setIcon(FILTER_OFF_ICON);
label.setForeground(Color.LIGHT_GRAY);
label.setText(filterOffString);
label.setToolTipText(filterOffToolTipString);
}
}
private void addTag(SignalDocument document, SignalPlot plot, Tag tag, StringBuilder sb) {
SignalSelectionType type = tag.getType();
if (type.isPage()) {
sb.append(pageTagString).append(" \"").append(tag.getStyle().getDescriptionOrName()).append("\" ");
addPageSelectionInfo(plot, tag, sb);
}
else if (type.isBlock()) {
sb.append(blockTagString).append(" \"").append(tag.getStyle().getDescriptionOrName()).append("\" ");
addBlockSelectionInfo(plot, tag, sb);
}
else if (type.isChannel()) {
sb.append(channelTagString).append(" \"").append(tag.getStyle().getDescriptionOrName()).append("\" ");
addChannelTagInfo(document, plot, tag, sb);
} else {
throw new SanityCheckException("Bad type [" + type + "]");
}
}
private void addSignalSelection(SignalDocument document, SignalPlot plot, SignalSelection signalSelection, StringBuilder sb) {
SignalSelectionType type = signalSelection.getType();
if (type.isPage()) {
sb.append(pageSelectionString).append(' ');
addPageSelectionInfo(plot, signalSelection, sb);
}
else if (type.isBlock()) {
sb.append(blockSelectionString).append(' ');
addBlockSelectionInfo(plot, signalSelection, sb);
}
else if (type.isChannel()) {
sb.append(channelSelectionString).append(' ');
addChannelSelectionInfo(document, plot, signalSelection, sb);
} else {
throw new SanityCheckException("Bad type [" + type + "]");
}
}
private void addPageSelectionInfo(SignalPlot plot, SignalSelection signalSelection, StringBuilder sb) {
double time = signalSelection.getPosition();
double endTime = time + signalSelection.getLength();
FormatUtils.addTime(time, sb);
sb.append(" - ");
FormatUtils.addTime(endTime, sb);
sb.append(" (").append(pageAbbrevString).append(": ");
sb.append(signalSelection.getStartSegment(plot.getPageSize())+1).append('-');
sb.append(signalSelection.getEndSegment(plot.getPageSize())).append(')');
}
private void addBlockSelectionInfo(SignalPlot plot, SignalSelection signalSelection, StringBuilder sb) {
double time = signalSelection.getPosition();
double endTime = time + signalSelection.getLength();
FormatUtils.addTime(time, sb);
sb.append(" - ");
FormatUtils.addTime(endTime, sb);
sb.append(" (").append(blockAbbrevString).append(": ");
sb.append(signalSelection.getStartSegment(plot.getBlockSize())+1).append('-');
sb.append(signalSelection.getEndSegment(plot.getBlockSize())).append(')');
}
private void addChannelSelectionInfo(SignalDocument document, SignalPlot plot, SignalSelection signalSelection, StringBuilder sb) {
double time = signalSelection.getPosition();
double endTime = time + signalSelection.getLength();
FormatUtils.addTime(time, sb);
sb.append(" - ");
FormatUtils.addTime(endTime, sb);
Montage montage = plot.getLocalMontage();
if (montage == null) {
montage = document.getMontage();
}
if (signalSelection.getChannel() != SignalSelection.CHANNEL_NULL)
sb.append(" (").append(montage.getMontageChannelLabelAt(signalSelection.getChannel())).append(')');
else
sb.append(" (all channels)");
}
private void addChannelTagInfo(SignalDocument document, SignalPlot plot, Tag tag, StringBuilder sb) {
double time = tag.getPosition();
double endTime = time + tag.getLength();
FormatUtils.addTime(time, sb);
sb.append(" - ");
FormatUtils.addTime(endTime, sb);
Montage montage = plot.getLocalMontage();
if (montage == null) {
montage = document.getMontage();
}
if (tag.getChannel() != -1)
sb.append(" (").append(montage.getSourceChannelLabelAt(tag.getChannel())).append(')');
else
sb.append(" (all channels)");
}
public void clearInfo() {
setCurrentSignal(null);
setCurrentBook(null);
setPosition("");
setSelection("");
}
public ViewModeAction getMaximizeDocumentsAction() {
return viewModeAction;
}
public void setMaximizeDocumentsAction(ViewModeAction viewModeAction) {
this.viewModeAction = viewModeAction;
}
public ActionFocusManager getActionFocusManager() {
return actionFocusManager;
}
public void setActionFocusManager(ActionFocusManager actionFocusManager) {
this.actionFocusManager = actionFocusManager;
}
}