package chatty.gui.components.menus;
import chatty.util.commands.CustomCommand;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.swing.ImageIcon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
/**
* A Popup Menu with convenience methods to add items as well as items in
* submenus.
*
* @author tduva
*/
public abstract class ContextMenu extends JPopupMenu implements ActionListener {
private final ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ContextMenu.this.actionPerformed(getCommandActionEvent(e));
}
};
private final Map<String, JMenu> subMenus = new HashMap<>();
private final Set<ContextMenuListener> listeners = new HashSet<>();
private final Map<String, CustomCommand> commands = new HashMap<>();
private JMenuItem makeItem(String action, String text, ImageIcon icon) {
JMenuItem item = new JMenuItem(text);
item.setActionCommand(action);
item.addActionListener(listener);
if (icon != null) {
item.setIcon(icon);
}
return item;
}
private JMenuItem makeCheckboxItem(String action, String text, boolean selected) {
JMenuItem item = new JCheckBoxMenuItem(text, selected);
item.setActionCommand(action);
item.addActionListener(listener);
return item;
}
/**
* Adds an entry to the submenu with the name {@code parent}, after any
* previously added items in that submenu.
*
* @param action The action of the menu item, which will be send to the
* listener
* @param text The label of the menu item
* @param pos The position in the menu, at the time of adding
* @param parent The name of the submenu, can be {@code null} in which case
* it isn't added to a submenu
* @param icon The icon to display for the menu item
* @return
* @see addItem(String, String, ImageIcon)
*/
protected JMenuItem addItem(String action, String text, int pos, String parent, ImageIcon icon) {
if (parent != null) {
JMenuItem item = makeItem(action, text, icon);
if (pos > -1) {
getSubmenu(parent).insert(item, pos);
} else {
getSubmenu(parent).add(item);
}
return item;
} else {
JMenuItem item = makeItem(action, text, icon);
if (pos > -1) {
insert(item, pos);
} else {
add(item);
}
return item;
}
}
protected JMenuItem addItem(String action, String text) {
return addItem(action, text, -1, null, null);
}
protected JMenuItem addItem(String action, String text, ImageIcon icon) {
return addItem(action, text, -1, null, icon);
}
protected JMenuItem addItem(String action, String text, String parent) {
return addItem(action, text, -1, parent, null);
}
public JMenuItem addCommandItem(CommandMenuItem item) {
if (item.getCommand() == null && item.getLabel() == null) {
addSeparator(item.getPos(), item.getParent());
} else if (item.getCommand() == null) {
JMenu menu = getSubmenu(item.getLabel(), item.getPos());
addKey(item, menu);
} else {
commands.put(item.getId(), item.getCommand());
JMenuItem mItem = addItem(item.getId(), item.getLabel(), item.getPos(), item.getParent(), null);
addKey(item, mItem);
}
return null;
}
private void addKey(CommandMenuItem item, JMenuItem mItem) {
if (item.hasKey()) {
mItem.setMnemonic(KeyEvent.getExtendedKeyCodeForChar(item.getKey().toLowerCase().charAt(0)));
}
}
private ActionEvent getCommandActionEvent(ActionEvent e) {
CustomCommand command = commands.get(e.getActionCommand());
if (command != null) {
return new CommandActionEvent(e, command);
}
return e;
}
protected void addCheckboxItem(String action, String text, boolean selected) {
add(makeCheckboxItem(action, text, selected));
}
protected void addCheckboxItem(String action, String text, String parent, boolean selected) {
if (parent != null) {
getSubmenu(parent).add(makeCheckboxItem(action, text, selected));
} else {
addCheckboxItem(action, text, selected);
}
}
/**
* Adds a seperator to the submenu with the given name, or adds a seperator
* in the main menu if this submenu doesn't exist yet.
*
* @param parent
*/
protected void addSeparator(int pos, String parent) {
if (parent != null && isSubmenu(parent)) {
if (pos > -1) {
getSubmenu(parent).insertSeparator(pos);
} else {
getSubmenu(parent).addSeparator();
}
} else {
if (pos > -1) {
insert(new Separator(), pos);
} else {
addSeparator();
}
}
}
protected void addSeparator(String parent) {
addSeparator(-1, parent);
}
public void addContextMenuListener(ContextMenuListener listener) {
if (listener != null) {
listeners.add(listener);
}
}
protected Set<ContextMenuListener> getContextMenuListeners() {
return listeners;
}
private boolean isSubmenu(String name) {
return subMenus.containsKey(name);
}
private JMenu getSubmenu(String name, int pos) {
if (subMenus.get(name) == null) {
JMenu menu = new JMenu(name);
if (pos > -1) {
insert(menu, pos);
} else {
add(menu);
}
subMenus.put(name, menu);
}
return subMenus.get(name);
}
private JMenu getSubmenu(String name) {
return getSubmenu(name, -1);
}
protected void setSubMenuIcon(String name, ImageIcon icon) {
getSubmenu(name, -1).setIcon(icon);
}
}