/**
   * Returns the component in the currently selected path which contains sourcePoint.
   *
   * @param source The component in whose coordinate space sourcePoint is given
   * @param sourcePoint The point which is being tested
   * @return The component in the currently selected path which contains sourcePoint (relative to
   *     the source component's coordinate space. If sourcePoint is not inside a component on the
   *     currently selected path, null is returned.
   */
  public Component componentForPoint(Component source, Point sourcePoint) {
    int screenX, screenY;
    Point p = sourcePoint;
    int i, c, j, d;
    Component mc;
    Rectangle r2;
    int cWidth, cHeight;
    MenuElement menuElement;
    MenuElement subElements[];
    Vector<MenuElement> tmp;
    int selectionSize;

    SwingUtilities.convertPointToScreen(p, source);

    screenX = p.x;
    screenY = p.y;

    tmp = (Vector<MenuElement>) selection.clone();
    selectionSize = tmp.size();
    for (i = selectionSize - 1; i >= 0; i--) {
      menuElement = (MenuElement) tmp.elementAt(i);
      subElements = menuElement.getSubElements();

      for (j = 0, d = subElements.length; j < d; j++) {
        if (subElements[j] == null) continue;
        mc = subElements[j].getComponent();
        if (!mc.isShowing()) continue;
        if (mc instanceof JComponent) {
          cWidth = mc.getWidth();
          cHeight = mc.getHeight();
        } else {
          r2 = mc.getBounds();
          cWidth = r2.width;
          cHeight = r2.height;
        }
        p.x = screenX;
        p.y = screenY;
        SwingUtilities.convertPointFromScreen(p, mc);

        /**
         * Return the deepest component on the selection path in whose bounds the event's point
         * occurs
         */
        if (p.x >= 0 && p.x < cWidth && p.y >= 0 && p.y < cHeight) {
          return mc;
        }
      }
    }
    return null;
  }
  private boolean isComponentPartOfCurrentMenu(MenuElement root, Component c) {
    MenuElement children[];
    int i, d;

    if (root == null) return false;

    if (root.getComponent() == c) return true;
    else {
      children = root.getSubElements();
      for (i = 0, d = children.length; i < d; i++) {
        if (isComponentPartOfCurrentMenu(children[i], c)) return true;
      }
    }
    return false;
  }
    JMenuItem getItem() {
      JMenuItem i;

      if (null == cmd) {
        i = new JMenu(name);
        for (MenuElement e : submenu) {
          i.add(e.getItem());
        }
      } else {
        i = new JMenuItem(cmd.name());
        i.setActionCommand(cmd.name());
        i.addActionListener(menuListener);
      }

      return i;
    }
  /**
   * When a MenuElement receives an event from a KeyListener, it should never process the event
   * directly. Instead all MenuElements should call this method with the event.
   *
   * @param e a KeyEvent object
   */
  public void processKeyEvent(KeyEvent e) {
    MenuElement[] sel2 = new MenuElement[0];
    sel2 = selection.toArray(sel2);
    int selSize = sel2.length;
    MenuElement[] path;

    if (selSize < 1) {
      return;
    }

    for (int i = selSize - 1; i >= 0; i--) {
      MenuElement elem = sel2[i];
      MenuElement[] subs = elem.getSubElements();
      path = null;

      for (int j = 0; j < subs.length; j++) {
        if (subs[j] == null
            || !subs[j].getComponent().isShowing()
            || !subs[j].getComponent().isEnabled()) {
          continue;
        }

        if (path == null) {
          path = new MenuElement[i + 2];
          System.arraycopy(sel2, 0, path, 0, i + 1);
        }
        path[i + 1] = subs[j];
        subs[j].processKeyEvent(e, path, this);
        if (e.isConsumed()) {
          return;
        }
      }
    }

    // finally dispatch event to the first component in path
    path = new MenuElement[1];
    path[0] = sel2[0];
    path[0].processKeyEvent(e, path, this);
    if (e.isConsumed()) {
      return;
    }
  }
  /**
   * Changes the selection in the menu hierarchy. The elements in the array are sorted in order from
   * the root menu element to the currently selected menu element.
   *
   * <p>Note that this method is public but is used by the look and feel engine and should not be
   * called by client applications.
   *
   * @param path an array of <code>MenuElement</code> objects specifying the selected path
   */
  public void setSelectedPath(MenuElement[] path) {
    int i, c;
    int currentSelectionCount = selection.size();
    int firstDifference = 0;

    if (path == null) {
      path = new MenuElement[0];
    }

    if (DEBUG) {
      System.out.print("Previous:  ");
      printMenuElementArray(getSelectedPath());
      System.out.print("New:  ");
      printMenuElementArray(path);
    }

    for (i = 0, c = path.length; i < c; i++) {
      if (i < currentSelectionCount && selection.elementAt(i) == path[i]) firstDifference++;
      else break;
    }

    for (i = currentSelectionCount - 1; i >= firstDifference; i--) {
      MenuElement me = selection.elementAt(i);
      selection.removeElementAt(i);
      me.menuSelectionChanged(false);
    }

    for (i = firstDifference, c = path.length; i < c; i++) {
      if (path[i] != null) {
        selection.addElement(path[i]);
        path[i].menuSelectionChanged(true);
      }
    }

    fireStateChanged();
  }
  public LabFrame() throws HeadlessException {
    super(title);
    JPanel pnl, pnl1;

    data = new LabData();

    alRootEntities.addAll(data.findRootEntities());

    JMenuBar mb = new JMenuBar();

    for (MenuElement e : menus) {
      mb.add(e.getItem());
    }
    setJMenuBar(mb);

    splMain = new JSplitPane();
    getContentPane().add(splMain);

    desktop = new JDesktopPane();
    desktop.setPreferredSize(new Dimension(400, 200));

    splMain.setRightComponent(desktop);

    lmEntities = new EntityListModel();

    lstEntities = new JList(lmEntities);
    lstEntities.getSelectionModel().addListSelectionListener(lmEntities);
    lstEntities.addMouseListener(dblClickListener);

    JScrollPane scpList = new JScrollPane(lstEntities);
    pnl = new JPanel(new BorderLayout(4, 4));

    pnl.add(scpList, BorderLayout.CENTER);

    pnl1 = new JPanel(null);
    pnl1.setLayout(new BoxLayout(pnl1, BoxLayout.X_AXIS));
    pnl1.add(Box.createHorizontalGlue());
    pnl1.add(new JButton(actNewEntity));
    pnl1.add(Box.createHorizontalGlue());
    pnl1.add(new JButton(actDelEntity));
    pnl1.add(Box.createHorizontalGlue());
    pnl.add(pnl1, BorderLayout.SOUTH);

    splMain.setLeftComponent(pnl);

    il =
        new InternalFrameAdapter() {

          @Override
          public void internalFrameClosed(InternalFrameEvent e) {
            Object sel = ((EntityFrame) e.getInternalFrame()).content;
            mapEntityFrames.remove(sel);
          }

          @Override
          public void internalFrameActivated(InternalFrameEvent e) {
            setTitle(title + " - " + e.getInternalFrame().getTitle());
            Object sel = ((EntityFrame) e.getInternalFrame()).content;
            lstEntities.setSelectedValue(sel, true);
          }
        };
    pack();

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    setVisible(true);

    updateState();
  }
  /**
   * When a MenuElement receives an event from a MouseListener, it should never process the event
   * directly. Instead all MenuElements should call this method with the event.
   *
   * @param event a MouseEvent object
   */
  public void processMouseEvent(MouseEvent event) {
    int screenX, screenY;
    Point p;
    int i, c, j, d;
    Component mc;
    Rectangle r2;
    int cWidth, cHeight;
    MenuElement menuElement;
    MenuElement subElements[];
    MenuElement path[];
    Vector<MenuElement> tmp;
    int selectionSize;
    p = event.getPoint();

    Component source = event.getComponent();

    if ((source != null) && !source.isShowing()) {
      // This can happen if a mouseReleased removes the
      // containing component -- bug 4146684
      return;
    }

    int type = event.getID();
    int modifiers = event.getModifiers();
    // 4188027: drag enter/exit added in JDK 1.1.7A, JDK1.2
    if ((type == MouseEvent.MOUSE_ENTERED || type == MouseEvent.MOUSE_EXITED)
        && ((modifiers
                & (InputEvent.BUTTON1_MASK | InputEvent.BUTTON2_MASK | InputEvent.BUTTON3_MASK))
            != 0)) {
      return;
    }

    if (source != null) {
      SwingUtilities.convertPointToScreen(p, source);
    }

    screenX = p.x;
    screenY = p.y;

    tmp = (Vector<MenuElement>) selection.clone();
    selectionSize = tmp.size();
    boolean success = false;
    for (i = selectionSize - 1; i >= 0 && success == false; i--) {
      menuElement = (MenuElement) tmp.elementAt(i);
      subElements = menuElement.getSubElements();

      path = null;
      for (j = 0, d = subElements.length; j < d && success == false; j++) {
        if (subElements[j] == null) continue;
        mc = subElements[j].getComponent();
        if (!mc.isShowing()) continue;
        if (mc instanceof JComponent) {
          cWidth = mc.getWidth();
          cHeight = mc.getHeight();
        } else {
          r2 = mc.getBounds();
          cWidth = r2.width;
          cHeight = r2.height;
        }
        p.x = screenX;
        p.y = screenY;
        SwingUtilities.convertPointFromScreen(p, mc);

        /**
         * Send the event to visible menu element if menu element currently in the selected path or
         * contains the event location
         */
        if ((p.x >= 0 && p.x < cWidth && p.y >= 0 && p.y < cHeight)) {
          int k;
          if (path == null) {
            path = new MenuElement[i + 2];
            for (k = 0; k <= i; k++) path[k] = (MenuElement) tmp.elementAt(k);
          }
          path[i + 1] = subElements[j];
          MenuElement currentSelection[] = getSelectedPath();

          // Enter/exit detection -- needs tuning...
          if (currentSelection[currentSelection.length - 1] != path[i + 1]
              && (currentSelection.length < 2
                  || currentSelection[currentSelection.length - 2] != path[i + 1])) {
            Component oldMC = currentSelection[currentSelection.length - 1].getComponent();

            MouseEvent exitEvent =
                new MouseEvent(
                    oldMC,
                    MouseEvent.MOUSE_EXITED,
                    event.getWhen(),
                    event.getModifiers(),
                    p.x,
                    p.y,
                    event.getXOnScreen(),
                    event.getYOnScreen(),
                    event.getClickCount(),
                    event.isPopupTrigger(),
                    MouseEvent.NOBUTTON);
            currentSelection[currentSelection.length - 1].processMouseEvent(exitEvent, path, this);

            MouseEvent enterEvent =
                new MouseEvent(
                    mc,
                    MouseEvent.MOUSE_ENTERED,
                    event.getWhen(),
                    event.getModifiers(),
                    p.x,
                    p.y,
                    event.getXOnScreen(),
                    event.getYOnScreen(),
                    event.getClickCount(),
                    event.isPopupTrigger(),
                    MouseEvent.NOBUTTON);
            subElements[j].processMouseEvent(enterEvent, path, this);
          }
          MouseEvent mouseEvent =
              new MouseEvent(
                  mc,
                  event.getID(),
                  event.getWhen(),
                  event.getModifiers(),
                  p.x,
                  p.y,
                  event.getXOnScreen(),
                  event.getYOnScreen(),
                  event.getClickCount(),
                  event.isPopupTrigger(),
                  MouseEvent.NOBUTTON);
          subElements[j].processMouseEvent(mouseEvent, path, this);
          success = true;
          event.consume();
        }
      }
    }
  }