// RecentMenu.java package net.sf.gogui.gui; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.prefs.Preferences; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.KeyStroke; import net.sf.gogui.util.ObjectUtil; import net.sf.gogui.util.Platform; import net.sf.gogui.util.PrefUtil; /** Menu for recent item. Handles removing duplicates and storing the items between sessions. */ public final class RecentMenu { /** Listener for events generated by RecentMenu. */ public interface Listener { void itemSelected(String label, String value); } /** The maximum number of items. If set to a value larger than 10, only the first 10 items will have a mnemonic key. */ public static final int MAX_ITEMS = 10; /** Constructor. @param text The label of the menu. Supports marking the mnemonics in the label with a preceeding '&' (like in Qt). @param path The absolute path name of the node in java.util.prefs.Preferences that is used to store the menu items. @param listener The callback to be called if a menu item is selected. */ public RecentMenu(String text, String path, Listener listener) { assert listener != null; m_path = path; m_listener = listener; m_menu = new GuiMenu(text); m_actionListener = new ActionListener() { public void actionPerformed(ActionEvent event) { RecentMenuItem item = (RecentMenuItem)event.getSource(); String label = item.getRecentMenuLabel(); String value = item.getRecentMenuValue(); m_listener.itemSelected(label, value); } }; get(); updateEnabled(); } /** Add a new item at the top. If the new number of items is greater than MAX_ITEM, the oldest item is removed. */ public void add(String label, String value) { addNewItem(label, value); put(); } public int getCount() { return m_menu.getMenuComponentCount(); } /** Don't modify the items in this menu! */ public GuiMenu getMenu() { return m_menu; } public String getValue(int i) { return getItem(i).getRecentMenuValue(); } public void remove(int i) { m_menu.remove(getItem(i)); relabel(); } public void setLabel(int i, String label) { getItem(i).setRecentMenuLabel(label); getItem(i).setPosition(i); put(); } /** Set menu enabled if not empty, disabled otherwise. */ public void updateEnabled() { int count = getCount(); m_menu.setEnabled(count > 0); } private final String m_path; private final ActionListener m_actionListener; private final Listener m_listener; private final GuiMenu m_menu; private void addNewItem(String label, String value) { for (int i = 0; i < getCount(); ++i) if (getValue(i).equals(value)) m_menu.remove(i); JMenuItem item = new RecentMenuItem(label, value, m_actionListener); m_menu.add(item, 0); // There might be several oldest items to remove, if the list in the // preferences was created with a version of GoGui compiled with a // different value for MAX_ITEM. while (getCount() > MAX_ITEMS) m_menu.remove(getCount() - 1); relabel(); } private void get() { Preferences prefs = PrefUtil.getNode(m_path); if (prefs == null) return; int size = prefs.getInt("size", 0); if (size < 0) size = 0; m_menu.removeAll(); for (int i = 0; i < size; ++i) { prefs = PrefUtil.getNode(m_path + "/" + i); if (prefs == null) break; String label = prefs.get("label", null); String value = prefs.get("value", null); if (label == null || value == null) continue; addNewItem(label, value); } } private RecentMenuItem getItem(int i) { return (RecentMenuItem)m_menu.getItem(i); } private String getLabel(int i) { return getItem(i).getRecentMenuLabel(); } private void put() { Preferences prefs = PrefUtil.createNode(m_path); if (prefs == null) return; int size = getCount(); prefs.putInt("size", size); for (int i = 0; i < size; ++i) { prefs = PrefUtil.createNode(m_path + "/" + (size - i - 1)); if (prefs == null) break; prefs.put("label", getLabel(i)); prefs.put("value", getValue(i)); } } /** Compute all new labels (including the number and mnemonic key) after changes were made. */ private void relabel() { int size = getCount(); for (int i = 0; i < size; ++i) getItem(i).setPosition(i); } } class RecentMenuItem extends JMenuItem { public RecentMenuItem(String label, String value, ActionListener listener) { setRecentMenuLabel(label); m_value = value; if (! ObjectUtil.equals(label, value)) setToolTipText(value); addActionListener(listener); } public String getRecentMenuLabel() { return m_label; } public String getRecentMenuValue() { return m_value; } public void setPosition(int i) { String text; String mnemonic; // Use 1-9 and 0 as mnemonics for the first 10 items if (! Platform.isMac() && i < 9) { text = Integer.toString(i + 1) + ": " + m_label; mnemonic = Integer.toString(i + 1); } else if (! Platform.isMac() && i == 9) { text = "10: " + m_label; mnemonic = "0"; } else { text = m_label; mnemonic = ""; } setText(text); if (! mnemonic.equals("")) { KeyStroke keyStroke = KeyStroke.getKeyStroke(mnemonic); int code = keyStroke.getKeyCode(); setMnemonic(code); } } public void setRecentMenuLabel(String label) { m_label = label; } private String m_label; private final String m_value; }