Package org.jdesktop.wonderland.modules.contextmenu.client.ui

Source Code of org.jdesktop.wonderland.modules.contextmenu.client.ui.SwingContextMenu$LabelListener

/**
* Project Wonderland
*
* Copyright (c) 2004-2009, Sun Microsystems, Inc., All Rights Reserved
*
* Redistributions in source code form must reproduce the above
* copyright and this condition.
*
* The contents of this file are subject to the GNU General Public
* License, Version 2 (the "License"); you may not use this file
* except in compliance with the License. A copy of the License is
* available at http://www.opensource.org/licenses/gpl-license.php.
*
* Sun designates this particular file as subject to the "Classpath"
* exception as provided by Sun in the License file that accompanied
* this code.
*/
package org.jdesktop.wonderland.modules.contextmenu.client.ui;

import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import org.jdesktop.wonderland.client.cell.Cell;
import org.jdesktop.wonderland.client.contextmenu.ContextMenuItemEvent;
import org.jdesktop.wonderland.client.contextmenu.ContextMenuItem;
import org.jdesktop.wonderland.client.contextmenu.ContextMenuActionListener;
import org.jdesktop.wonderland.client.contextmenu.ContextMenuEvent;
import org.jdesktop.wonderland.client.contextmenu.ContextMenuInvocationSettings;
import org.jdesktop.wonderland.client.contextmenu.ContextMenuItem.MenuItemRepaintListener;
import org.jdesktop.wonderland.client.contextmenu.ContextMenuManager;
import org.jdesktop.wonderland.client.contextmenu.SimpleContextMenuItem;
import org.jdesktop.wonderland.client.contextmenu.cell.ContextMenuComponent;
import org.jdesktop.wonderland.client.contextmenu.spi.ContextMenuFactorySPI;
import org.jdesktop.wonderland.client.input.Event;
import org.jdesktop.wonderland.client.input.EventClassListener;
import org.jdesktop.wonderland.client.scenemanager.SceneManager;
import org.jdesktop.wonderland.client.scenemanager.event.ActivatedEvent;
import org.jdesktop.wonderland.client.scenemanager.event.ContextEvent;
import org.jdesktop.wonderland.client.scenemanager.event.SelectionEvent;

/**
* A Swing-based implementation of the system context menu.
*
* @author Jordan Slott <jslott@dev.java.net>
*/
public class SwingContextMenu implements MenuItemRepaintListener {

    private static Logger logger = Logger.getLogger(SwingContextMenu.class.getName());
    private JFrame contextMenu = null;
    private JPanel contextPanel = null;
    private Cell popupCell = null;
    private Map<JMenuItem, ContextMenuItem> menuItemMap = new HashMap();
    private Map<ContextMenuItem, JMenuItem> reverseMenuMap = new HashMap();

    // Colors matching the Wonderland logo color scheme
    private Color WL_LIGHT_BLUE = new Color(12, 104, 234);
    private Color WL_BLUE = new Color(7, 73, 165);
    private Color WL_LIGHT_GREEN = new Color(61, 207, 60);
    private Color WL_GREEN = new Color(45, 164, 48);

    // the context selection listener we registered
    private final ContextSelectionListener listener = new ContextSelectionListener();

    /** Constructor */
    public SwingContextMenu() {
        // Initialize the GUI.
        contextMenu = new JFrame();
        contextMenu.setResizable(false);
        contextMenu.setUndecorated(true);
        contextMenu.getContentPane().setLayout(new GridLayout(1, 1));

        contextPanel = new JPanel();
        contextMenu.getContentPane().add(contextPanel);
        contextPanel.setBorder(BorderFactory.createLineBorder(WL_LIGHT_BLUE, 2));
        contextPanel.setLayout(new BoxLayout(contextPanel, BoxLayout.Y_AXIS));
    }

    /**
     * Add ourself as a global event listener
     */
    public void register() {
         // Register a global listener for context and selection events
        SceneManager.getSceneManager().addSceneListener(listener);
    }

    /**
     * Remove ourself from being a global event listener
     */
    public void unregister() {
        SceneManager.getSceneManager().removeSceneListener(listener);
    }

    /**
     * This method is synchronized so that the possible repaints don't happen
     * while we are still constructing the menu in initializeMenu().
     */
    public synchronized void repaintMenuItem(ContextMenuItem menuItem) {
        // Tell the menu item to repaint itself. Reset the values on the
        // context menu, tell it to repaint.
        JMenuItem item = reverseMenuMap.get(menuItem);
        if (menuItem instanceof SimpleContextMenuItem) {
            SimpleContextMenuItem scmi = (SimpleContextMenuItem)menuItem;
            item.setText(scmi.getLabel());
            item.setEnabled(scmi.isEnabled());
            if (scmi.getImage() != null) {
                item.setIcon(new ImageIcon(scmi.getImage()));
            }
            item.repaint();
            contextMenu.pack();
            contextMenu.repaint();
        }
    }

    /**
     * Initialize the context menu items. This is synchronized so nothing else
     * can do stuff while the context menu is being created. An example of
     * would be repaintMenuItem() which may try to access the context menu
     * before it has been created.
     */
    private synchronized void initializeMenu(ContextEvent event, Cell cell) {
        // Loop through any menu item and remove the listener
        for (Map.Entry<JMenuItem, ContextMenuItem> entry : menuItemMap.entrySet()) {
            entry.getValue().removeMenuItemRepaintListener(this);
        }

        // Clear out any existing entries in the context menu
        contextPanel.removeAll();
        menuItemMap.clear();
        reverseMenuMap.clear();

       
        // create new ContextMenuEvent
        ContextMenuEvent ctxEvent = new ContextMenuEvent(event, cell);

        // Tell the context menu listeners that we are about to display a
        // context menu, giving listeners an opportunity to make adjustments
        ContextMenuManager.getContextMenuManager().fireContextMenuEvent(ctxEvent);

        // get the settings from the event, possibly adjusted by listeners
        ContextMenuInvocationSettings settings = ctxEvent.getSettings();
        // Adjust name of menu (by default, this is the cell's name)
        JPanel titlePanel = new JPanel();
        titlePanel.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
        titlePanel.setBackground(WL_BLUE);
        JLabel title = new JLabel("<html><b>" + settings.getMenuName() + "</b></html>");
        title.setForeground(Color.WHITE);
        title.setBackground(Color.GRAY);
        titlePanel.add(title);
        contextPanel.add(titlePanel);
        contextPanel.invalidate();
       
        // Fetch the manager of the context menu
        ContextMenuManager cmm = ContextMenuManager.getContextMenuManager();
       
        // fetch context menu component
        ContextMenuComponent cmc = cell.getComponent(ContextMenuComponent.class);
       
        // show standard menu items?
        if (settings.isDisplayStandard() == true) {
          // fetch standard items from CMM
          List<ContextMenuFactorySPI> factoryList = cmm.getContextMenuFactoryList();
          // add each item to the menu
          for (ContextMenuFactorySPI factory : factoryList) {
              ContextMenuItem items[] = factory.getContextMenuItems(event);
              for (ContextMenuItem item : items) {
                  addContextMenuItem(item, cell);
              }
          }
        }

        // show cell-specific standard items?
        if (settings.isDisplayCellStandard() && cmc != null) {
          // fetch standard factories from CMC
          ContextMenuFactorySPI factories[] = cmc.getContextMenuFactories();
          // add each item to the menu
          for (ContextMenuFactorySPI factory : factories) {
              ContextMenuItem items[] = factory.getContextMenuItems(event);
              for (ContextMenuItem item : items) {
                  addContextMenuItem(item, cell);
              }
          }
        }

        // show temporary items?

        if (settings.isDisplayTemporaryFactories()) {
          // fetch standard factories from CMC
          List<ContextMenuFactorySPI> factoryList = settings.getFactoryList();
          // add each item to the menu
          for (ContextMenuFactorySPI factory : factoryList) {
              ContextMenuItem items[] = factory.getContextMenuItems(event);
              for (ContextMenuItem item : items) {
                  addContextMenuItem(item, cell);
              }
          }
        }
    }

    /**
     * Adds a context menu entry.
     *
     * @param menuItem The new context menu item
     */
    private void addContextMenuItem(ContextMenuItem menuItem, Cell cell) {

        // Only support SimpleContextMenuItems for now!
        if (!(menuItem instanceof SimpleContextMenuItem)) {
            logger.warning("Menu item type not supported: " + menuItem);
            return;
        }
        SimpleContextMenuItem simpleItem = (SimpleContextMenuItem)menuItem;

        // Creates the context menu item, using the image as an icon if it
        // exists.
        String name = simpleItem.getLabel();
        Image image = simpleItem.getImage();
        boolean isEnabled = simpleItem.isEnabled();

        JMenuItem item = null;
        if (image == null) {
            item = new JMenuItem(name);
        }
        else {
            item = new JMenuItem(name, new ImageIcon(image));
        }

        // Try to make the menu item look a bit nicer
        item.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 7));
        item.addMouseListener(new LabelListener(name));

        // If the state of the menu item is "DISABLED" then grey out the item
        item.setEnabled(isEnabled);

        // Add the item to the menu
        contextPanel.add(item);
        contextPanel.invalidate();
        contextMenu.pack();

        // Listen for changes to each menu item.
        menuItem.addMenuItemRepaintListener(this);

        // Add an entry to the map of each menu item
        menuItemMap.put(item, menuItem);
        reverseMenuMap.put(menuItem, item);
    }

    /**
     * Shows the Entity context menu given the AWT MouseEvent and the Entity
     * associated with the mouse click
     */
    private void showContextMenu(MouseEvent event, Cell cell) {
        // Check if there is an existing popup menu visible and make
        // it invisible
        if (contextMenu.isVisible() == true) {
            contextMenu.setVisible(false);
        }

        // Make the popup menu visible in the new locatio
        popupCell = cell;
        Component component = event.getComponent();
        Point parentPoint = new Point(component.getLocationOnScreen());
        parentPoint.translate(event.getX(), event.getY());
        contextMenu.setLocation(parentPoint);
        contextMenu.setVisible(true);
        contextMenu.toFront();
        contextMenu.pack();
        contextMenu.repaint();
    }

    /**
     * Hides the context menu.
     */
    private void hideContextMenu() {
        contextMenu.setVisible(false);
    }

    /**
     * Listeners for clicks on any contxt menu element
     */
    class LabelListener extends MouseAdapter {

        /* The original text of the string */
        public String text = null;

        /** Constructor, takes the index of the element */
        public LabelListener(String text) {
            this.text = text;
        }

        @Override
        public void mouseClicked(MouseEvent e) {
            // Fetch the source for this event. Check to see if it is enabled,
            // if not then just return
            JMenuItem item = (JMenuItem)e.getSource();
            if (item.isEnabled() == false) {
                return;
            }

            // Otherwise, highlight the menu item and hide the menu
            item.setBackground(WL_GREEN);
            item.repaint();
            hideContextMenu();

            // Find the listener to dispatch the action to
            ContextMenuItem menuItem = menuItemMap.get(item);
            if (menuItem != null && menuItem instanceof SimpleContextMenuItem) {
                // Only deal with SimpleMenuItems for now
                SimpleContextMenuItem scmi = (SimpleContextMenuItem)menuItem;
                ContextMenuActionListener listener = scmi.getActionListener();
                if (listener != null) {
                    listener.actionPerformed(
                            new ContextMenuItemEvent(menuItem, popupCell));
                }
            }
        }

        @Override
        public void mouseEntered(MouseEvent e) {
            // Highlight the menu item with a color, but only if it is enabled
            JMenuItem item = (JMenuItem)e.getSource();
            if (item.isEnabled() == true) {
                item.setBackground(WL_LIGHT_GREEN);
                item.setOpaque(true);
                item.repaint();
                contextMenu.pack();
            }
        }

        @Override
        public void mouseExited(MouseEvent e) {
            // De-highlight the menu item with a color, but only if it is enabled
            JMenuItem item = (JMenuItem) e.getSource();
            if (item.isEnabled() == true) {
                item.setBackground(Color.white);
                contextMenu.pack();
            }
        }
    }

    /**
     * Inner class that listeners for context and selection events
     */
    class ContextSelectionListener extends EventClassListener {

        public ContextSelectionListener() {
            setSwingSafe(true);
        }

        @Override
        public Class[] eventClassesToConsume() {
            return new Class[] {
                ActivatedEvent.class, ContextEvent.class, SelectionEvent.class
            };
        }

        @Override
        public void commitEvent(Event event) {

            // Go ahead and either close the context menu or show the context
            // menu.
            if (event instanceof ActivatedEvent || event instanceof SelectionEvent) {
                // Hide the context menu in the AWT Event Thread so that we do
                // not interfere with the MT Game Render thread
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        hideContextMenu();
                    }
                });
            }
            else if (event instanceof ContextEvent) {
                // Show the context menu, initialize the menu if this is the
                // first time
                final Cell cell = ((ContextEvent)event).getPrimaryCell();
                if (cell == null) {
                    // Hide the context menu in the AWT Event Thread so that we do
                    // not interfere with the MT Game Render thread
                    SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
                            hideContextMenu();
                        }
                    });
                    return;
                }

                // Initialize the context menu in the AWT Event Thread so that
                // we do not interfere with the MT Game Render thread
                final ContextEvent ce = (ContextEvent) event;
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        initializeMenu(ce, cell);
                        showContextMenu(ce.getMouseEvent(), cell);
                    }
                });
            }
        }
    }
}
TOP

Related Classes of org.jdesktop.wonderland.modules.contextmenu.client.ui.SwingContextMenu$LabelListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.