//----------------------------------------------------------------------------// // // // S p i n n e r G l y p h M o d e l // // // //----------------------------------------------------------------------------// // <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.glyph.ui; import omr.glyph.Nest; import omr.glyph.facets.Glyph; import static omr.ui.field.SpinnerUtil.*; import omr.util.Predicate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.swing.AbstractSpinnerModel; /** * Class {@code SpinnerGlyphModel} is a spinner model backed by a * {@link Nest}. * Any modification in the nest is thus transparently handled, since the nest * <b>is</b> the model. * <p>A glyph {@link Predicate} can be assigned to this SpinnerGlyphModel at * construction time in order to restrict the population of glyphs in the * spinner. * This class is used by {@link GlyphBoard} only, but is not coupled with it. * * @author Hervé Bitteur */ public class SpinnerGlyphModel extends AbstractSpinnerModel { //~ Static fields/initializers --------------------------------------------- /** Usual logger utility */ private static final Logger logger = LoggerFactory.getLogger( SpinnerGlyphModel.class); //~ Instance fields -------------------------------------------------------- /** Underlying glyph nest */ private final Nest nest; /** Additional predicate if any */ private final Predicate<Glyph> predicate; /** Current glyph id */ private Integer currentId; //~ Constructors ----------------------------------------------------------- //-------------------// // SpinnerGlyphModel // //-------------------// /** * Creates a new SpinnerGlyphModel object, on all nest glyphs * * @param nest the underlying glyph nest */ public SpinnerGlyphModel (Nest nest) { this(nest, null); } //-------------------// // SpinnerGlyphModel // //-------------------// /** * Creates a new SpinnerGlyphModel object, with a related glyph predicate * * @param nest the underlying glyph nest * @param predicate predicate of glyph, or null */ public SpinnerGlyphModel (Nest nest, Predicate<Glyph> predicate) { if (nest == null) { throw new IllegalArgumentException( "SpinnerGlyphModel expects non-null glyph nest"); } this.nest = nest; this.predicate = predicate; currentId = NO_VALUE; } //~ Methods ---------------------------------------------------------------- //--------------// // getNextValue // //--------------// /** * Return the next legal glyph id in the sequence that comes after the glyph * id returned by {@code getValue()}. If the end of the sequence has * been reached then return null. * * @return the next legal glyph id or null if one doesn't exist */ @Override public Object getNextValue () { final int cur = currentId.intValue(); logger.debug("getNextValue cur={}", cur); if (cur == NO_VALUE) { // Return first suitable glyph in nest for (Glyph glyph : nest.getAllGlyphs()) { if ((predicate == null) || predicate.check(glyph)) { return glyph.getId(); } } return null; } else { // Return first suitable glyph after current glyph in nest boolean found = false; for (Glyph glyph : nest.getAllGlyphs()) { if (!found) { if (glyph.getId() == cur) { found = true; } } else if ((predicate == null) || predicate.check(glyph)) { return glyph.getId(); } } return null; } } //------------------// // getPreviousValue // //------------------// /** * Return the legal glyph id in the sequence that comes before the glyph id * returned by {@code getValue()}. If the end of the sequence has been * reached then return null. * * @return the previous legal value or null if one doesn't exist */ @Override public Object getPreviousValue () { Glyph prevGlyph = null; final int cur = currentId.intValue(); logger.debug("getPreviousValue cur={}", cur); if (cur == NO_VALUE) { return NO_VALUE; } // Nest for (Glyph glyph : nest.getAllGlyphs()) { if (glyph.getId() == cur) { return (prevGlyph != null) ? prevGlyph.getId() : NO_VALUE; } // Should we remember this as (suitable) previous glyph ? if ((predicate == null) || predicate.check(glyph)) { prevGlyph = glyph; } } return null; } //----------// // getValue // //----------// /** * The <i>current element</i> of the sequence. * * @return the current spinner value. */ @Override public Object getValue () { logger.debug("getValue currentId={}", currentId); return currentId; } //----------// // setValue // //----------// /** * Changes current glyph id of the model. If the glyph id is illegal then * an {@code IllegalArgumentException} is thrown. * * @param value the value to set * @exception IllegalArgumentException if {@code value} isn't allowed */ @Override public void setValue (Object value) { logger.debug("setValue value={}", value); Integer id = (Integer) value; boolean ok = false; if (id == NO_VALUE) { ok = true; } else { // Nest Glyph glyph = nest.getGlyph(id); if (glyph != null) { if (predicate != null) { ok = predicate.check(glyph); } else { ok = true; } } } if (ok) { currentId = id; fireStateChanged(); } else { logger.warn("Invalid glyph id: {}", id); } } }