//----------------------------------------------------------------------------// // // // N a m e S e t // // // //----------------------------------------------------------------------------// // <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.util; import omr.constant.Constant; import omr.ui.util.DynamicMenu; import net.jcip.annotations.ThreadSafe; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import javax.swing.JMenu; import javax.swing.JMenuItem; /** * Class {@code NameSet} encapsulates the handling of a list of names, * a typical use is a history of file names. * * <p> Actually, rather than a set, it is a list where the most recently used * are kept at the head of the list. There is no duplicate in the set (tests are * case-insensitive). </p> * * <p> The NameSet can additionally be used to dynamically generate and handle a * menu. </p> * * @author Hervé Bitteur */ @ThreadSafe public class NameSet { //~ Static fields/initializers --------------------------------------------- /** Separator */ private static final String SEPARATOR = ";"; //~ Instance fields -------------------------------------------------------- /** Global name for this set */ private final String setName; /** Backing constant */ private final Constant.String constant; /** List of names in this set */ private final List<String> names = new ArrayList<>(); /** Max number of names in this set */ private final int maxNameNb; //~ Constructors ----------------------------------------------------------- //---------// // NameSet // //---------// /** * Creates a new set of names, with some customizing parameters. * * @param setName Global name for this set * @param constant the backing constant string * @param maxNameNb Maximum number of elements in this name set */ public NameSet (String setName, Constant.String constant, int maxNameNb) { this.setName = setName; this.constant = constant; this.maxNameNb = maxNameNb; // Retrieve the list of names already in the set String[] vals = constant.getValue().split(SEPARATOR); if (!vals[0].isEmpty()) { names.addAll(Arrays.asList(vals)); } } //~ Methods ---------------------------------------------------------------- // //---------// // isEmpty // //---------// public synchronized boolean isEmpty () { return names.isEmpty(); } //-----// // add // //-----// /** * Insert a (perhaps new) name at the head of the list. If the name was * already in the list, it is moved to the head. * * @param name Name to be inserted in the set */ public synchronized void add (String name) { if ((name == null) || (name.isEmpty())) { return; } // Remove duplicate if any remove(name); // Insert the name at the beginning of the list names.add(0, name); // Check for maximum length while (names.size() > maxNameNb) { names.remove(names.size() - 1); } // Update the constant accordingly updateConstant(); } //------// // menu // //------// /** * Return an up-to-date menu that can be used to trigger actions * related to the designated name. * * @param menu the existing menu to update * @param listener The ActionListener to be triggered. (the selected name * can be retrieved by the listener in the ActionEvent, by * using the ActionEvent.getActionCommand method) * * @return the JMenu, ready to be inserted in a menu hierarchy. */ public JMenu menu (JMenu menu, ActionListener listener) { // Don't fully destroy the menu, just clean all its items, so that the // modifications are made available to the menu hierarchy. if (menu == null) { menu = new JMenu(setName); } else { menu.removeAll(); } // Regenerate proper menu items synchronized (this) { for (String f : names) { JMenuItem menuItem = new JMenuItem(f); menuItem.addActionListener(listener); menu.add(menuItem); } } return menu; } //------// // menu // //------// /** * Create a brand new menu, with the name of the set as default text for * menu text. * * @param listener the listener to be trigerred on item selection * @return the menu ready to be inserted */ public JMenu menu (ActionListener listener) { return menu(setName, listener); } //------// // menu // //------// /** * Create a brand new menu for name selection, with label provided for the * menu and action listener * * @param label the text in the menu item * @param listener the listener to be trigerred on item selection * @return the menu ready to be inserted */ public JMenu menu (String label, ActionListener listener) { return new MyMenu(label, listener).getMenu(); } //--------// // remove // //--------// /** * Remove a given name from the list * * @param name the name to remove * @return true if actually found and removed */ public synchronized boolean remove (String name) { // If the ref exists in the list, it is removed for (Iterator<String> it = names.iterator(); it.hasNext();) { String f = it.next(); if (f.equalsIgnoreCase(name)) { it.remove(); updateConstant(); return true; } } return false; } //----------------// // updateConstant // //----------------// private void updateConstant () { StringBuilder buf = new StringBuilder(1024); for (String n : names) { if (buf.length() > 0) { buf.append(SEPARATOR); } buf.append(n); } constant.setValue(buf.toString()); } //~ Inner Classes ---------------------------------------------------------- //--------// // MyMenu // //--------// private class MyMenu extends DynamicMenu { //~ Instance fields ---------------------------------------------------- private ActionListener listener; //~ Constructors ------------------------------------------------------- public MyMenu (String label, ActionListener listener) { super(label); this.listener = listener; } //~ Methods ------------------------------------------------------------ @Override protected void buildItems () { // Regenerate proper menu items synchronized (NameSet.this) { for (String f : names) { JMenuItem menuItem = new JMenuItem(f); menuItem.addActionListener(listener); getMenu().add(menuItem); } } } } }