gt:       final GamePiece p = map.findPiece(e.getPoint(), targetSelector);
context: /*
   * $Id$
   *
   * Copyright (c) 2000-2012 by Rodney Kinney, Brent Easton
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Library General Public
   * License (LGPL) as published by the Free Software Foundation.
   *
   * This library 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
   * Library General Public License for more details.
   *
   * You should have received a copy of the GNU Library General Public
   * License along with this library; if not, copies are available
   * at http://www.opensource.org.
   */
  package VASSAL.build.module.map;
  
  import java.awt.Font;
  import java.awt.Point;
  import java.awt.event.MouseAdapter;
  import java.awt.event.MouseEvent;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.Iterator;
  
  import javax.swing.Action;
  import javax.swing.JMenu;
  import javax.swing.JMenuItem;
  import javax.swing.JPopupMenu;
  import javax.swing.KeyStroke;
  
  import org.w3c.dom.Document;
  import org.w3c.dom.Element;
  
  import VASSAL.build.Buildable;
  import VASSAL.build.module.Map;
  import VASSAL.counters.Deck;
  import VASSAL.counters.EventFilter;
  import VASSAL.counters.GamePiece;
  import VASSAL.counters.KeyCommand;
  import VASSAL.counters.KeyCommandSubMenu;
  import VASSAL.counters.PieceFinder;
  import VASSAL.counters.Properties;
  
  public class MenuDisplayer extends MouseAdapter implements Buildable {
    public static Font POPUP_MENU_FONT = new Font("Dialog", 0, 10);
  
    protected Map map;
    protected PieceFinder targetSelector;
  
    public void addTo(Buildable b) {
      targetSelector = createTargetSelector();
      map = (Map) b;
      map.addLocalMouseListener(this);
    }
  
    /**
     * Return a {@link PieceFinder} instance that will select a
     * {@link GamePiece} whose menu will be displayed when the
     * user clicks on the map
     * @return
     */
    protected PieceFinder createTargetSelector() {
      return new PieceFinder.PieceInStack() {
        public Object visitDeck(Deck d) {
          Point pos = d.getPosition();
          Point p = new Point(pt.x - pos.x, pt.y - pos.y);
          if (d.getShape().contains(p)) {
            return d;
          }
          else {
            return null;
          }
        }
      };
    }
  
    public void add(Buildable b) {
    }
  
    public Element getBuildElement(Document doc) {
      return doc.createElement(getClass().getName());
    }
  
    public void build(Element e) {
    }
  
    public static JPopupMenu createPopup(GamePiece target) {
      return createPopup(target, false);
    }
  
    /**
     *
     * @param target
     * @param global If true, then apply the KeyCommands globally,
     * i.e. to all selected pieces
     * @return
     */
    public static JPopupMenu createPopup(GamePiece target, boolean global) {
      JPopupMenu popup = new JPopupMenu();
      KeyCommand c[] = (KeyCommand[]) target.getProperty(Properties.KEY_COMMANDS);
      if (c != null) {
        ArrayList<JMenuItem> commands = new ArrayList<JMenuItem>();
        ArrayList<KeyStroke> strokes = new ArrayList<KeyStroke>();
  
        // Maps instances of KeyCommandSubMenu to corresponding JMenu
        HashMap<KeyCommandSubMenu,JMenu> subMenus =
          new HashMap<KeyCommandSubMenu,JMenu>();
        // Maps name to a list of commands with that name
        HashMap<String,ArrayList<JMenuItem>> commandNames =
          new HashMap<String,ArrayList<JMenuItem>>();
  
        for (int i = 0; i < c.length; ++i) {
          c[i].setGlobal(global);
          KeyStroke stroke = c[i].getKeyStroke();
          JMenuItem item = null;
          if (c[i] instanceof KeyCommandSubMenu) {
            JMenu subMenu = new JMenu(c[i].getLocalizedMenuText());
            subMenu.setFont(POPUP_MENU_FONT);
            subMenus.put((KeyCommandSubMenu) c[i], subMenu);
            item = subMenu;
            commands.add(item);
            strokes.add(KeyStroke.getKeyStroke('\0'));
          }
          else {
            if (strokes.contains(stroke)) {
              JMenuItem command = commands.get(strokes.indexOf(stroke));
              Action action = command.getAction();
              if (action != null) {
                String commandName =
                  (String) command.getAction().getValue(Action.NAME);
                if (commandName == null ||
                    commandName.length() < c[i].getName().length()) {
                  item = new JMenuItem(c[i].getLocalizedMenuText());
                  item.addActionListener(c[i]);
                  item.setFont(POPUP_MENU_FONT);
                  item.setEnabled(c[i].isEnabled());
                  commands.set(strokes.indexOf(stroke), item);
                }
              }
            }
            else {
              strokes.add(stroke != null ? stroke : KeyStroke.getKeyStroke('\0'));
              item = new JMenuItem(c[i].getLocalizedMenuText());
              item.addActionListener(c[i]);
              item.setFont(POPUP_MENU_FONT);
              item.setEnabled(c[i].isEnabled());
              commands.add(item);
            }
          }
          if (c[i].getName() != null &&
              c[i].getName().length() > 0 &&
              item != null) {
            ArrayList<JMenuItem> l = commandNames.get(c[i].getName());
            if (l == null) {
              l = new ArrayList<JMenuItem>();
              commandNames.put(c[i].getName(), l);
            }
            l.add(item);
          }
        }
  
        // Move commands from main menu into submenus
        for (java.util.Map.Entry<KeyCommandSubMenu,JMenu> e :
                                                          subMenus.entrySet()) {
          final KeyCommandSubMenu menuCommand = e.getKey();
          final JMenu subMenu = e.getValue();
  
          for (Iterator<String> it2 = menuCommand.getCommands(); it2.hasNext();) {
            final ArrayList<JMenuItem> matchingCommands =
              commandNames.get(it2.next());
            if (matchingCommands != null) {
              for (JMenuItem item : matchingCommands) {
                subMenu.add(item);
                commands.remove(item);
              }
            }
          }
        }
  
        // Promote contents of a single submenu [Removed as per Bug 4775]
        // if (commands.size() == 1) {
        //   if (commands.get(0) instanceof JMenu) {
        //     JMenu submenu = (JMenu) commands.get(0);
        //     commands.remove(submenu);
        //     for (int i = 0; i < submenu.getItemCount(); i++) {
        //       commands.add(submenu.getItem(i));
        //     }
        //   }
        // }
  
        for (JMenuItem item : commands) {
          popup.add(item);
        }
      }
      return popup;
    }
  
    public void mouseReleased(MouseEvent e) {
      if (e.isMetaDown()) {
  