//------------------------------------------------------------------------------------------------// // // // S h a p e S e t // // // //------------------------------------------------------------------------------------------------// // <editor-fold defaultstate="collapsed" desc="hdr"> // // Copyright © Audiveris 2018. All rights reserved. // // 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/>. //------------------------------------------------------------------------------------------------// // </editor-fold> package org.audiveris.omr.glyph; import org.audiveris.omr.constant.Constant; import static org.audiveris.omr.glyph.Shape.*; import org.audiveris.omr.sheet.ProcessingSwitches; import org.audiveris.omr.sheet.ProcessingSwitches.Switch; import org.audiveris.omr.sheet.Sheet; import org.audiveris.omr.ui.Colors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.awt.Color; import java.awt.event.ActionListener; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuItem; /** * Class {@code ShapeSet} defines a set of related shapes, for example the "Rests" set * gathers all rest shapes from MULTI_REST down to ONE_128TH_REST. * <p> * It handles additional properties over a simple EnumSet, especially assigned colors and its * automatic insertion in shape menus and palette hierarchy. * So don't remove any of the ShapeSet's, unless you know what you are doing. * * @author Hervé Bitteur */ public class ShapeSet { private static final Logger logger = LoggerFactory.getLogger(ShapeSet.class); /** * Half time numbers. These shapes are used for upper or lower part of a time signature. */ public static final List<Shape> PartialTimes = Arrays.asList( TIME_TWO, TIME_THREE, TIME_FOUR, TIME_FIVE, TIME_SIX, TIME_SEVEN, TIME_EIGHT, TIME_NINE, TIME_TWELVE, TIME_SIXTEEN); /** * Measure counts. * These time-looking shapes may appear right above a staff containing just a long measure rest, * to indicate the number of measures the rest represents. */ public static final List<Shape> MeasureCounts = Arrays.asList( TIME_ZERO, TIME_ONE, TIME_TWO, TIME_THREE, TIME_FOUR, TIME_FIVE, TIME_SIX, TIME_SEVEN, TIME_EIGHT, TIME_NINE, TIME_TWELVE, TIME_SIXTEEN); /** Single-symbols for whole time signature. */ public static final EnumSet<Shape> SingleWholeTimes = EnumSet.of(COMMON_TIME, CUT_TIME); /** Single-symbols and predefined combos for whole time signature. */ public static final EnumSet<Shape> WholeTimes = EnumSet.of( COMMON_TIME, CUT_TIME, TIME_FOUR_FOUR, TIME_TWO_TWO, TIME_TWO_FOUR, TIME_THREE_FOUR, TIME_FIVE_FOUR, TIME_THREE_EIGHT, TIME_SIX_EIGHT); /** All sorts of F clefs. */ public static final EnumSet<Shape> BassClefs = EnumSet.of( F_CLEF, F_CLEF_SMALL, F_CLEF_8VA, F_CLEF_8VB); /** All sorts of G clefs. */ public static final EnumSet<Shape> TrebleClefs = EnumSet.of( G_CLEF, G_CLEF_SMALL, G_CLEF_8VA, G_CLEF_8VB); /** All flags down. */ public static final EnumSet<Shape> FlagsDown = EnumSet.of( FLAG_1, FLAG_2, FLAG_3, FLAG_4, FLAG_5); /** Small flags. */ public static final EnumSet<Shape> SmallFlags = EnumSet.of(SMALL_FLAG, SMALL_FLAG_SLASH); /** All flags up. */ public static final EnumSet<Shape> FlagsUp = EnumSet.of( FLAG_1_UP, FLAG_2_UP, FLAG_3_UP, FLAG_4_UP, FLAG_5_UP); /** All SHARP-based keys. */ public static final EnumSet<Shape> SharpKeys = EnumSet.of( KEY_SHARP_1, KEY_SHARP_2, KEY_SHARP_3, KEY_SHARP_4, KEY_SHARP_5, KEY_SHARP_6, KEY_SHARP_7); /** All FLAT-based keys. */ public static final EnumSet<Shape> FlatKeys = EnumSet.of( KEY_FLAT_1, KEY_FLAT_2, KEY_FLAT_3, KEY_FLAT_4, KEY_FLAT_5, KEY_FLAT_6, KEY_FLAT_7); /** All black note heads. */ public static final EnumSet<Shape> BlackNoteHeads = EnumSet.of( NOTEHEAD_BLACK, NOTEHEAD_BLACK_SMALL); /** All void note heads. */ public static final EnumSet<Shape> VoidNoteHeads = EnumSet.of( NOTEHEAD_VOID, NOTEHEAD_VOID_SMALL); /** All supported small notes. (for cue/grace) */ public static final EnumSet<Shape> SmallNotes = EnumSet.of( NOTEHEAD_BLACK_SMALL, NOTEHEAD_VOID_SMALL, WHOLE_NOTE_SMALL); /** All heads without a stem. */ public static final EnumSet<Shape> StemLessHeads = EnumSet.of( BREVE, WHOLE_NOTE, WHOLE_NOTE_SMALL); /** All heads with a stem. */ public static final EnumSet<Shape> StemHeads = EnumSet.of( NOTEHEAD_BLACK, NOTEHEAD_BLACK_SMALL, NOTEHEAD_VOID, NOTEHEAD_VOID_SMALL); /** All heads. */ public static final List<Shape> Heads = Arrays.asList( BREVE, WHOLE_NOTE, WHOLE_NOTE_SMALL, NOTEHEAD_BLACK, NOTEHEAD_BLACK_SMALL, NOTEHEAD_VOID, NOTEHEAD_VOID_SMALL); /** FermataArcs. */ public static final EnumSet<Shape> FermataArcs = EnumSet.of(FERMATA_ARC, FERMATA_ARC_BELOW); /** Core shapes for barlines. */ public static final EnumSet<Shape> CoreBarlines = EnumSet.copyOf( Arrays.asList(THICK_BARLINE, THICK_CONNECTOR, THIN_BARLINE, THIN_CONNECTOR)); /** Beams. */ public static final EnumSet<Shape> Beams = EnumSet.copyOf( Arrays.asList(BEAM, BEAM_SMALL, BEAM_HOOK, BEAM_HOOK_SMALL)); //---------------------------------------------------------------------------------------------- // Below are predefined instances of ShapeSet, meant mainly for UI packaging. // // By being defined here, they will lead to corresponding gathering in user menus & palette. // So, double-check before removing or modifying any one of them. // // Nota: Do not use EnumSet.range() since this could lead to subtle errors should Shape enum // order be modified. Prefer the use of shapesOf() which lists precisely all set members. //---------------------------------------------------------------------------------------------- public static final ShapeSet Accidentals = new ShapeSet( SHARP, Colors.SCORE_MODIFIERS, shapesOf(FLAT, NATURAL, SHARP, DOUBLE_SHARP, DOUBLE_FLAT)); public static final ShapeSet Articulations = new ShapeSet( ACCENT, Colors.SCORE_MODIFIERS, shapesOf(ACCENT, TENUTO, STACCATO, STACCATISSIMO, STRONG_ACCENT)); public static final ShapeSet Attributes = new ShapeSet( PEDAL_MARK, Colors.SCORE_MODIFIERS, shapesOf(OTTAVA_ALTA, OTTAVA_BASSA, PEDAL_MARK, PEDAL_UP_MARK, ARPEGGIATO)); public static final ShapeSet Barlines = new ShapeSet( LEFT_REPEAT_SIGN, Colors.SCORE_FRAME, shapesOf( THIN_BARLINE, THICK_BARLINE, DOUBLE_BARLINE, FINAL_BARLINE, REVERSE_FINAL_BARLINE, LEFT_REPEAT_SIGN, RIGHT_REPEAT_SIGN, BACK_TO_BACK_REPEAT_SIGN, BRACE, BRACKET, REPEAT_DOT)); public static final ShapeSet BeamsAndTuplets = new ShapeSet( BEAM, Colors.SCORE_NOTES, shapesOf(BEAM /* ,BEAM_SMALL */, BEAM_HOOK, TUPLET_THREE, TUPLET_SIX)); public static final ShapeSet Clefs = new ShapeSet( G_CLEF, Colors.SCORE_FRAME, shapesOf(TrebleClefs, BassClefs, shapesOf(C_CLEF, PERCUSSION_CLEF))); public static final ShapeSet Dynamics = new ShapeSet( DYNAMICS_F, Colors.SCORE_MODIFIERS, shapesOf( DYNAMICS_P, DYNAMICS_PP, DYNAMICS_MP, DYNAMICS_F, DYNAMICS_FF, DYNAMICS_MF, DYNAMICS_FP, DYNAMICS_SF, DYNAMICS_SFZ, CRESCENDO, DIMINUENDO)); public static final ShapeSet Flags = new ShapeSet( FLAG_1, Colors.SCORE_NOTES, shapesOf(new ArrayList<>(FlagsDown), SmallFlags, FlagsUp)); public static final ShapeSet Holds = new ShapeSet( FERMATA, Colors.SCORE_MODIFIERS, shapesOf(BREATH_MARK, CAESURA, FERMATA, FERMATA_BELOW)); public static final ShapeSet Keys = new ShapeSet( KEY_SHARP_3, Colors.SCORE_MODIFIERS, shapesOf(new ArrayList<>(FlatKeys), SharpKeys)); public static final ShapeSet HeadsAndDot = new ShapeSet( NOTEHEAD_BLACK, Colors.SCORE_NOTES, shapesOf(Heads, shapesOf(AUGMENTATION_DOT))); public static final ShapeSet Markers = new ShapeSet( CODA, Colors.SCORE_FRAME, shapesOf(DAL_SEGNO, DA_CAPO, SEGNO, CODA)); public static final ShapeSet Ornaments = new ShapeSet( MORDENT, Colors.SCORE_MODIFIERS, shapesOf( GRACE_NOTE_SLASH, GRACE_NOTE, TR, TURN, TURN_INVERTED, TURN_UP, TURN_SLASH, MORDENT, MORDENT_INVERTED)); public static final ShapeSet Rests = new ShapeSet( QUARTER_REST, Colors.SCORE_NOTES, shapesOf( LONG_REST, BREVE_REST, WHOLE_REST, HALF_REST, QUARTER_REST, EIGHTH_REST, ONE_16TH_REST, ONE_32ND_REST, ONE_64TH_REST, ONE_128TH_REST)); public static final ShapeSet Times = new ShapeSet( TIME_FOUR_FOUR, Colors.SCORE_FRAME, shapesOf(PartialTimes, WholeTimes)); //, shapesOf(TIME_ZERO, TIME_ONE, CUSTOM_TIME))); public static final ShapeSet Digits = new ShapeSet( DIGIT_1, Colors.SCORE_MODIFIERS, shapesOf(DIGIT_0, DIGIT_1, DIGIT_2, DIGIT_3, DIGIT_4, DIGIT_5 // , // DIGIT_6, // DIGIT_7, // DIGIT_8, // DIGIT_9 )); public static final ShapeSet Pluckings = new ShapeSet( PLUCK_P, Colors.SCORE_MODIFIERS, shapesOf(PLUCK_P, PLUCK_I, PLUCK_M, PLUCK_A)); public static final ShapeSet Romans = new ShapeSet( ROMAN_V, Colors.SCORE_MODIFIERS, shapesOf( ROMAN_I, ROMAN_II, ROMAN_III, ROMAN_IV, ROMAN_V, ROMAN_VI, ROMAN_VII, ROMAN_VIII, ROMAN_IX, ROMAN_X, ROMAN_XI, ROMAN_XII)); public static final ShapeSet Physicals = new ShapeSet( LEDGER, Colors.SCORE_PHYSICALS, shapesOf(LYRICS, TEXT, CHARACTER, CLUTTER, SLUR, LEDGER, STEM, ENDING)); // ========================================================================= // Below are EnumSet instances, used programmatically. // They do not lead to shape submenus as the ShapeSet instances do. // ========================================================================= // /** All physical shapes. Here the use of EnumSet.range is OK */ public static final EnumSet<Shape> allPhysicalShapes = EnumSet.range( Shape.values()[0], LAST_PHYSICAL_SHAPE); /** Symbols that can be attached to a stem. */ public static final EnumSet<Shape> StemSymbols = EnumSet.copyOf( shapesOf(StemHeads, Flags.getShapes(), Beams)); /** Pedals */ public static final EnumSet<Shape> Pedals = EnumSet.of(PEDAL_MARK, PEDAL_UP_MARK); /** Tuplets */ public static final EnumSet<Shape> Tuplets = EnumSet.of(TUPLET_THREE, TUPLET_SIX); /** All variants of dot */ public static final EnumSet<Shape> Dots = EnumSet.of( DOT_set, AUGMENTATION_DOT, STACCATO, REPEAT_DOT); /** Clefs ottava (alta or bassa) */ public static final EnumSet<Shape> OttavaClefs = EnumSet.of( G_CLEF_8VA, G_CLEF_8VB, F_CLEF_8VA, F_CLEF_8VB); /** Small Clefs */ public static final EnumSet<Shape> SmallClefs = EnumSet.of(G_CLEF_SMALL, F_CLEF_SMALL); static { // Make sure all the shape colors are defined ShapeSet.defineAllShapeColors(); // Debug ///dumpShapeColors(); } /** Name of the set. */ private String name; /** Underlying shapes. */ private final EnumSet<Shape> shapes; /** Specific sequence of shapes, if any. */ private final List<Shape> sortedShapes; /** The representative shape for this set. */ private final Shape rep; /** Assigned color. */ private Color color; /** Related color constant. */ private Constant.Color constantColor; /** * Creates a new ShapeSet object from a collection of shapes. * * @param rep the representative shape * @param color the default color assigned * @param shapes the provided collection of shapes */ public ShapeSet (Shape rep, Color color, Collection<Shape> shapes) { // The representative shape this.rep = rep; // The default color this.color = (color != null) ? color : Color.BLACK; // The set of shapes this.shapes = EnumSet.noneOf(Shape.class); this.shapes.addAll(shapes); // Keep a specific order? if (shapes instanceof List) { this.sortedShapes = new ArrayList<>(shapes); } else { this.sortedShapes = null; } } //--------// // getRep // //--------// /** * Report the representative shape of the set, if any. * * @return the rep shape, or null */ public Shape getRep () { return rep; } //-----------// // getShapes // //-----------// /** * Exports the set of shapes. * * @return the proper enum set */ public EnumSet<Shape> getShapes () { return shapes; } //------------------// // setConstantColor // //------------------// /** * Define a specific color for the set. * * @param color the specified color */ public void setConstantColor (Color color) { constantColor.setValue(color); setColor(color); } //----------// // contains // //----------// /** * Convenient method to check if encapsulated shapes set does contain the provided * object. * * @param shape the Shape object to check for inclusion * @return true if contained, false otherwise */ public boolean contains (Shape shape) { return shapes.contains(shape); } //----------// // getColor // //----------// /** * Report the color currently assigned to the range, if any. * * @return the related color, or null */ public Color getColor () { return color; } //----------// // setColor // //----------// /** * Assign a display color to the shape set. * * @param color the display color */ private void setColor (Color color) { this.color = color; } //---------// // getName // //---------// /** * Report the name of the set. * * @return the set name */ public String getName () { return name; } //---------// // setName // //---------// private void setName (String name) { this.name = name; constantColor = new Constant.Color( getClass().getName(), name + ".color", Constant.Color.encodeColor(color), "Color code for set " + name); // Check for a user-modified value if (!constantColor.isSourceValue()) { setColor(constantColor.getValue()); } } //-----------------// // getSortedShapes // //-----------------// /** * Exports the sorted collection of shapes. * * @return the proper enum set */ public List<Shape> getSortedShapes () { if (sortedShapes != null) { return sortedShapes; } else { return new ArrayList<>(shapes); } } //-----------------// // addAllShapeSets // //-----------------// /** * Populate the given menu with all ShapeSet instances defined * in this class. * * @param top the JComponent to populate (typically a JMenu or a * JPopupMenu) * @param listener the listener for notification of user selection */ public static void addAllShapeSets (JComponent top, ActionListener listener) { // All ranges of glyph shapes for (Field field : ShapeSet.class.getDeclaredFields()) { if (field.getType() == ShapeSet.class) { JMenuItem menuItem = new JMenuItem(field.getName()); ShapeSet set = valueOf(field.getName()); addColoredItem(top, menuItem, set.getColor()); menuItem.addActionListener(listener); } } } //--------------// // addAllShapes // //--------------// /** * Populate the given menu with a hierarchy of all shapes, * organized by defined ShapeSets. * * @param top the JComponent to populate (typically a JMenu or a JPopupMenu) * @param listener the listener for notification of user selection */ public static void addAllShapes (JComponent top, ActionListener listener) { // All ranges of glyph shapes for (Field field : ShapeSet.class.getDeclaredFields()) { if (field.getType() == ShapeSet.class) { ShapeSet set = ShapeSet.valueOf(field.getName()); JMenu menu = new JMenu(field.getName()); if (set.rep != null) { menu.setIcon(set.rep.getDecoratedSymbol()); } addColoredItem(top, menu, Color.black); // Add menu items for this range addSetShapes(set, menu, listener); } } } //--------------// // addSetShapes // //--------------// /** * Populate the given menu with a list of all shapes that belong * to the given ShapeSet. * * @param set the set for which shape menu items must be buit * @param top the JComponent to populate (typically a JMenu or a * JPopupMenu) * @param listener the listener for notification of user selection */ public static void addSetShapes (ShapeSet set, JComponent top, ActionListener listener) { // All shapes in the given range for (Shape shape : set.getSortedShapes()) { JMenuItem menuItem = new JMenuItem(shape.toString(), shape.getDecoratedSymbol()); addColoredItem(top, menuItem, shape.getColor()); menuItem.setToolTipText(shape.getDescription()); menuItem.addActionListener(listener); } } //-----------------------// // getPhysicalShapeNames // //-----------------------// /** * Report the names of all the physical shapes. * * @return the array of names for shapes up to LAST_PHYSICAL_SHAPE */ public static String[] getPhysicalShapeNames () { int shapeCount = 1 + LAST_PHYSICAL_SHAPE.ordinal(); String[] names = new String[shapeCount]; for (Shape shape : allPhysicalShapes) { names[shape.ordinal()] = shape.name(); } return names; } //-----------------------------// // getPhysicalShapeNamesString // //-----------------------------// /** * Report a formatted string with the names of all the physical shapes. * * @return a global string */ public static String getPhysicalShapeNamesString () { final List<String> names = Arrays.asList(getPhysicalShapeNames()); StringBuilder sb = new StringBuilder("{ //\n"); for (int i = 0; i < names.size(); i++) { String comma = (i < (names.size() - 1)) ? "," : ""; sb.append(String.format("\"%-18s // %3d%n", names.get(i) + "\"" + comma, i)); } sb.append("};"); return sb.toString(); } //------------------// // getTemplateNotes // //------------------// /** * Report the template notes suitable for the provided sheet. * * @param sheet provided sheet or null * @return the template notes, perhaps limited by sheet processing switches */ public static EnumSet<Shape> getTemplateNotes (Sheet sheet) { final EnumSet<Shape> set = EnumSet.of( NOTEHEAD_BLACK, NOTEHEAD_VOID, WHOLE_NOTE, NOTEHEAD_BLACK_SMALL, NOTEHEAD_VOID_SMALL, WHOLE_NOTE_SMALL); if (sheet == null) { return set; } final ProcessingSwitches switches = sheet.getStub().getProcessingSwitches(); if (!switches.getValue(Switch.smallBlackHeads)) { set.remove(NOTEHEAD_BLACK_SMALL); } if (!switches.getValue(Switch.smallVoidHeads)) { set.remove(NOTEHEAD_VOID_SMALL); } if (!switches.getValue(Switch.smallWholeHeads)) { set.remove(WHOLE_NOTE_SMALL); } return set; } //-------------// // getShapeSet // //-------------// /** * Report the ShapeSet for the provided name * * @param name provided name * @return corresponding ShapeSet instance */ public static ShapeSet getShapeSet (String name) { return Sets.map.get(name); } //--------------// // getShapeSets // //--------------// /** * Report the list of all ShapeSet instances * * @return the list of ShapeSet instances */ public static List<ShapeSet> getShapeSets () { return Sets.setList; } //----------------------// // getStemTemplateNotes // //----------------------// /** * Report the stem template notes suitable for the provided sheet. * * @param sheet provided sheet or null * @return the stem template notes, perhaps limited by sheet processing switches */ public static EnumSet<Shape> getStemTemplateNotes (Sheet sheet) { final EnumSet<Shape> set = EnumSet.of( NOTEHEAD_BLACK, NOTEHEAD_VOID, NOTEHEAD_BLACK_SMALL, NOTEHEAD_VOID_SMALL); if (sheet == null) { return set; } final ProcessingSwitches switches = sheet.getStub().getProcessingSwitches(); if (!switches.getValue(Switch.smallBlackHeads)) { set.remove(NOTEHEAD_BLACK_SMALL); } if (!switches.getValue(Switch.smallVoidHeads)) { set.remove(NOTEHEAD_VOID_SMALL); } return set; } //----------------------// // getVoidTemplateNotes // //----------------------// /** * Report the void template notes suitable for the provided sheet. * * @param sheet provided sheet or null * @return the void template notes, perhaps limited by sheet processing switches */ public static EnumSet<Shape> getVoidTemplateNotes (Sheet sheet) { final EnumSet<Shape> set = EnumSet.of(NOTEHEAD_VOID, WHOLE_NOTE, NOTEHEAD_VOID_SMALL); if (sheet == null) { return set; } final ProcessingSwitches switches = sheet.getStub().getProcessingSwitches(); if (!switches.getValue(Switch.smallVoidHeads)) { set.remove(NOTEHEAD_VOID_SMALL); } return set; } //----------// // shapesOf // //----------// /** * Convenient way to build a collection of shapes. * * @param col a collection of shapes * @return a single collection */ public static Collection<Shape> shapesOf (Collection<Shape> col) { Collection<Shape> shapes = (col instanceof List) ? new ArrayList<Shape>() : EnumSet.noneOf(Shape.class); shapes.addAll(col); return shapes; } //----------// // shapesOf // //----------// /** * Convenient way to build a collection of shapes. * * @param col1 a first collection of shapes * @param col2 a second collection of shapes * @return a single collection */ public static Collection<Shape> shapesOf (Collection<Shape> col1, Collection<Shape> col2) { Collection<Shape> shapes = (col1 instanceof List) ? new ArrayList<Shape>() : EnumSet.noneOf(Shape.class); shapes.addAll(col1); shapes.addAll(col2); return shapes; } //----------// // shapesOf // //----------// /** * Convenient way to build a collection of shapes. * * @param shapes an array of shapes * @return a single collection */ public static Collection<Shape> shapesOf (Shape... shapes) { return Arrays.asList(shapes); } //----------// // shapesOf // //----------// /** * Convenient way to build a collection of shapes. * * @param col1 a first collection of shapes * @param col2 a second collection of shapes * @param col3 a third collection of shapes * @param col4 a fourth collection of shapes * @return a single collection */ public static Collection<Shape> shapesOf (Collection<Shape> col1, Collection<Shape> col2, Collection<Shape> col3, Collection<Shape> col4) { Collection<Shape> shapes = (col1 instanceof List) ? new ArrayList<Shape>() : EnumSet.noneOf(Shape.class); shapes.addAll(col1); shapes.addAll(col2); shapes.addAll(col3); shapes.addAll(col4); return shapes; } //----------// // shapesOf // //----------// /** * Convenient way to build a collection of shapes. * * @param col1 a first collection of shapes * @param col2 a second collection of shapes * @param col3 a third collection of shapes * @return a single collection */ public static Collection<Shape> shapesOf (Collection<Shape> col1, Collection<Shape> col2, Collection<Shape> col3) { Collection<Shape> shapes = (col1 instanceof List) ? new ArrayList<Shape>() : EnumSet.noneOf(Shape.class); shapes.addAll(col1); shapes.addAll(col2); shapes.addAll(col3); return shapes; } //---------// // valueOf // //---------// /** * Retrieve a set knowing its name (just like an enumeration). * * @param str the provided set name * @return the range found, or null otherwise */ public static ShapeSet valueOf (String str) { return Sets.map.get(str); } //----------------// // addColoredItem // //----------------// private static void addColoredItem (JComponent top, JMenuItem item, Color color) { if (color != null) { item.setForeground(color); } else { item.setForeground(Color.black); } top.add(item); } //----------------------// // defineAllShapeColors // //----------------------// /** * (package private access meant from Shape class) * Assign a color to every shape, using the color of the containing * set when no specific color is defined for a shape. */ static void defineAllShapeColors () { EnumSet<Shape> colored = EnumSet.noneOf(Shape.class); // Define shape colors, using their containing range as default for (Field field : ShapeSet.class.getDeclaredFields()) { if (field.getType() == ShapeSet.class) { try { ShapeSet set = (ShapeSet) field.get(null); set.setName(field.getName()); // Create shape color for all contained shapes for (Shape shape : set.shapes) { shape.createShapeColor(set.getColor()); colored.add(shape); } } catch (IllegalAccessException ex) { ex.printStackTrace(); } } } /** Sets of similar shapes */ HW_REST_set.createShapeColor(Rests.getColor()); colored.add(HW_REST_set); // Directly assign colors for shapes in no range EnumSet<Shape> leftOver = EnumSet.allOf(Shape.class); leftOver.removeAll(colored); for (Shape shape : leftOver) { shape.createShapeColor(Color.BLACK); } } //------// // Sets // //------// /** Build the set map in a lazy way */ private static class Sets { static final Map<String, ShapeSet> map = new HashMap<>(); static final List<ShapeSet> setList = new ArrayList<>(); static { for (Field field : ShapeSet.class.getDeclaredFields()) { if (field.getType() == ShapeSet.class) { try { ShapeSet set = (ShapeSet) field.get(null); map.put(field.getName(), set); setList.add(set); } catch (IllegalAccessException ex) { ex.printStackTrace(); } } } } private Sets () { } } }