//----------------------------------------------------------------------------//
// //
// S e c t i o n B o a r d //
// //
//----------------------------------------------------------------------------//
// <editor-fold defaultstate="collapsed" desc="hdr"> //
// Copyright © Hervé Bitteur and others 2000-2013. All rights reserved. //
// This software is released under the GNU General Public License. //
// Goto http://kenai.com/projects/audiveris to report bugs or suggestions. //
//----------------------------------------------------------------------------//
// </editor-fold>
package omr.lag.ui;
import omr.constant.Constant;
import omr.constant.ConstantSet;
import omr.lag.Lag;
import omr.lag.Section;
import omr.run.Orientation;
import omr.selection.MouseMovement;
import omr.selection.SectionEvent;
import omr.selection.SectionIdEvent;
import omr.selection.SectionSetEvent;
import omr.selection.SelectionHint;
import omr.selection.UserEvent;
import omr.stick.StickRelation;
import omr.ui.Board;
import omr.ui.field.LIntegerField;
import omr.ui.field.SpinnerUtil;
import omr.ui.util.Panel;
import com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Set;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
* Class {@code SectionBoard} defines a board dedicated to the display
* of {@link omr.lag.Section} information, it can also be used as an
* input means by directly entering the section id in the proper Id
* spinner.
*
* @author Hervé Bitteur
*/
public class SectionBoard
extends Board
{
//~ Static fields/initializers ---------------------------------------------
/** Specific application parameters */
private static final Constants constants = new Constants();
/** Usual logger utility */
private static final Logger logger = LoggerFactory.getLogger(
SectionBoard.class);
/** Events this board is interested in */
private static final Class<?>[] eventsRead = new Class<?>[]{
SectionEvent.class,
SectionSetEvent.class
};
//~ Instance fields --------------------------------------------------------
/** Underlying lag */
protected final Lag lag;
/** Counter of section selection */
protected final JLabel count = new JLabel("");
// Section input devices
//
/** Button for section dump */
private final JButton dump;
/** Spinner for section id */
private final JSpinner id = new JSpinner();
// Output for plain Section
//
/** Field for left abscissa */
private final LIntegerField x = new LIntegerField(
false,
"X",
"Left abscissa in pixels");
/** Field for top ordinate */
private final LIntegerField y = new LIntegerField(
false,
"Y",
"Top ordinate in pixels");
/** Field for width */
private final LIntegerField width = new LIntegerField(
false,
"Width",
"Horizontal width in pixels");
/** Field for height */
private final LIntegerField height = new LIntegerField(
false,
"Height",
"Vertical height in pixels");
/** Field for weight */
private final LIntegerField weight = new LIntegerField(
false,
"Weight",
"Number of pixels in this section");
// Additional output for StickSection (TODO: remove these fields)
//
/** Field for role in stick building */
private final JTextField role = new JTextField();
private final LIntegerField direction = new LIntegerField(
false,
"Dir",
"Direction from the stick core");
/** Field for layer number */
private final LIntegerField layer = new LIntegerField(
false,
"Layer",
"Layer number for this stick section");
/** To avoid loop, indicate that selecting is being done by the spinner */
private boolean idSelecting = false;
/** To avoid loop, indicate that update() method id being processed */
private boolean updating = false;
//~ Constructors -----------------------------------------------------------
//--------------//
// SectionBoard //
//--------------//
/**
* Create a Section Board
*
* @param lag the related lag
* @param expanded true for initially expanded, false for collapsed
*/
public SectionBoard (final Lag lag,
boolean expanded)
{
super(
Board.SECTION.name
+ ((lag.getOrientation() == Orientation.VERTICAL) ? " Vert" : " Hori"),
Board.SECTION.position
+ ((lag.getOrientation() == Orientation.VERTICAL) ? 100 : 0),
lag.getSectionService(),
eventsRead,
true, // Dump
expanded);
this.lag = lag;
// Dump button
dump = getDumpButton();
dump.setToolTipText("Dump this section");
dump.addActionListener(
new ActionListener()
{
@Override
public void actionPerformed (ActionEvent e)
{
// Retrieve current section selection
Section section = (Section) lag.getSectionService()
.getSelection(
SectionEvent.class);
if (section != null) {
section.dump();
}
}
});
dump.setEnabled(false); // Until a section selection is made
// ID Spinner
id.setToolTipText("General spinner for any section id");
id.addChangeListener(
new ChangeListener()
{
@Override
public void stateChanged (ChangeEvent e)
{
// Make sure this new Id value is due to user
// action on an Id spinner, and not the mere update
// of section fields (which include this id).
if (!updating) {
Integer sectionId = (Integer) id.getValue();
logger.debug("sectionId={} for {}", sectionId, lag);
idSelecting = true;
lag.getSectionService()
.publish(
new SectionIdEvent(
SectionBoard.this,
SelectionHint.SECTION_INIT,
sectionId));
idSelecting = false;
}
}
});
id.setModel(new SpinnerSectionModel(lag));
SpinnerUtil.setEditable(id, true);
SpinnerUtil.setRightAlignment(id);
// Relation
if (constants.hideRelationFields.getValue()) {
direction.setVisible(false);
layer.setVisible(false);
role.setVisible(false);
}
role.setEditable(false);
role.setHorizontalAlignment(JTextField.CENTER);
role.setToolTipText("Role in the composition of the containing stick");
// Component layout
defineLayout();
}
//~ Methods ----------------------------------------------------------------
//---------//
// onEvent //
//---------//
/**
* Call-back triggered when Section Selection has been modified
*
* @param event the section event
*/
@SuppressWarnings("unchecked")
@Override
public void onEvent (UserEvent event)
{
try {
// Ignore RELEASING
if (event.movement == MouseMovement.RELEASING) {
return;
}
logger.debug("SectionBoard: {}", event);
if (event instanceof SectionEvent) {
handleEvent((SectionEvent) event);
} else if (event instanceof SectionSetEvent) {
handleEvent((SectionSetEvent) event);
}
} catch (Exception ex) {
logger.warn(getClass().getName() + " onEvent error", ex);
}
}
//--------------//
// defineLayout //
//--------------//
private void defineLayout ()
{
FormLayout layout = Panel.makeFormLayout(4, 3);
PanelBuilder builder = new PanelBuilder(layout, getBody());
builder.setDefaultDialogBorder();
CellConstraints cst = new CellConstraints();
int r = 1; // --------------------------------
builder.add(count, cst.xy(9, r));
r += 2; // --------------------------------
builder.addLabel("Id", cst.xy(1, r));
builder.add(id, cst.xy(3, r));
builder.add(x.getLabel(), cst.xy(5, r));
builder.add(x.getField(), cst.xy(7, r));
builder.add(width.getLabel(), cst.xy(9, r));
builder.add(width.getField(), cst.xy(11, r));
r += 2; // --------------------------------
builder.add(weight.getLabel(), cst.xy(1, r));
builder.add(weight.getField(), cst.xy(3, r));
builder.add(y.getLabel(), cst.xy(5, r));
builder.add(y.getField(), cst.xy(7, r));
builder.add(height.getLabel(), cst.xy(9, r));
builder.add(height.getField(), cst.xy(11, r));
r += 2; // --------------------------------
builder.add(layer.getLabel(), cst.xy(1, r));
builder.add(layer.getField(), cst.xy(3, r));
builder.add(direction.getLabel(), cst.xy(5, r));
builder.add(direction.getField(), cst.xy(7, r));
builder.add(role, cst.xyw(9, r, 3));
}
//-------------//
// handleEvent //
//-------------//
/**
* Interest in Section
*
* @param sectionEvent
*/
private void handleEvent (SectionEvent sectionEvent)
{
if (updating) {
return;
}
try {
// Update section fields in this board
updating = true;
final Section section = (sectionEvent != null)
? sectionEvent.getData() : null;
dump.setEnabled(section != null);
Integer sectionId = null;
if (idSelecting) {
sectionId = (Integer) id.getValue();
}
emptyFields(getBody());
if (section == null) {
// If the user is currently using the Id spinner, make sure we
// display the right Id value in the spinner, even if there is
// no corresponding section
if (idSelecting) {
id.setValue(sectionId);
} else {
id.setValue(SpinnerUtil.NO_VALUE);
}
if (constants.hideRelationFields.getValue()) {
direction.setVisible(false);
layer.setVisible(false);
role.setVisible(false);
}
} else {
// We have a valid section, let's display its fields
id.setValue(section.getId());
Rectangle box = section.getBounds();
x.setValue(box.x);
y.setValue(box.y);
width.setValue(box.width);
height.setValue(box.height);
weight.setValue(section.getWeight());
// Additional relation fields for a StickSection
StickRelation relation = section.getRelation();
if (relation != null) {
if (constants.hideRelationFields.getValue()) {
layer.setVisible(true);
}
layer.setValue(relation.layer);
if (constants.hideRelationFields.getValue()) {
direction.setVisible(true);
}
direction.setValue(relation.direction);
if (relation.role != null) {
role.setText(relation.role.toString());
if (constants.hideRelationFields.getValue()) {
role.setVisible(true);
}
} else {
if (constants.hideRelationFields.getValue()) {
role.setVisible(false);
}
}
} else if (constants.hideRelationFields.getValue()) {
direction.setVisible(false);
layer.setVisible(false);
role.setVisible(false);
}
}
} finally {
updating = false;
}
}
//-------------//
// handleEvent //
//-------------//
/**
* Interest in SectionSet
*
* @param sectionSetEvent
*/
private void handleEvent (SectionSetEvent sectionSetEvent)
{
// Display count of sections in the section set
Set<Section> sections = sectionSetEvent.getData();
if ((sections != null) && !sections.isEmpty()) {
count.setText(Integer.toString(sections.size()));
} else {
count.setText("");
}
}
//~ Inner Classes ----------------------------------------------------------
//-----------//
// Constants //
//-----------//
private static final class Constants
extends ConstantSet
{
//~ Instance fields ----------------------------------------------------
Constant.Boolean hideRelationFields = new Constant.Boolean(
true,
"Should we hide section relation fields when empty?");
}
}