Package org.jdesktop.wonderland.modules.avatarbase.client

Source Code of org.jdesktop.wonderland.modules.avatarbase.client.AvatarClientPlugin$ConfigureContextMenuFactory

/**
* Open Wonderland
*
* Copyright (c) 2010 - 2011, Open Wonderland Foundation, 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.
*
* The Open Wonderland Foundation designates this particular file as
* subject to the "Classpath" exception as provided by the Open Wonderland
* Foundation in the License file that accompanied this code.
*/

/**
* 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.avatarbase.client;

import com.jme.math.Vector3f;
import imi.camera.CameraModels;
import imi.camera.ChaseCamModel;
import imi.camera.ChaseCamState;
import imi.character.AvatarSystem;
import imi.character.avatar.Avatar;
import imi.repository.Repository;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.instrument.Instrumentation;
import java.lang.ref.WeakReference;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenuItem;
import javax.swing.JRadioButtonMenuItem;
import org.jdesktop.mtgame.WorldManager;
import org.jdesktop.wonderland.client.BaseClientPlugin;
import org.jdesktop.wonderland.client.ClientContext;
import org.jdesktop.wonderland.client.cell.Cell;
import org.jdesktop.wonderland.client.cell.Cell.RendererType;
import org.jdesktop.wonderland.client.cell.CellComponent;
import org.jdesktop.wonderland.client.cell.CellRenderer;
import org.jdesktop.wonderland.client.cell.ComponentChangeListener;
import org.jdesktop.wonderland.client.cell.asset.AssetUtils;
import org.jdesktop.wonderland.client.cell.view.AvatarCell;
import org.jdesktop.wonderland.client.cell.view.ViewCell;
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;
import org.jdesktop.wonderland.client.contextmenu.ContextMenuItemEvent;
import org.jdesktop.wonderland.client.contextmenu.ContextMenuListener;
import org.jdesktop.wonderland.client.contextmenu.ContextMenuManager;
import org.jdesktop.wonderland.client.contextmenu.SimpleContextMenuItem;
import org.jdesktop.wonderland.client.contextmenu.spi.ContextMenuFactorySPI;
import org.jdesktop.wonderland.client.jme.ClientContextJME;
import org.jdesktop.wonderland.client.jme.JmeClientMain;
import org.jdesktop.wonderland.client.jme.MainFrame;
import org.jdesktop.wonderland.client.jme.MainFrameImpl;
import org.jdesktop.wonderland.client.jme.ViewManager;
import org.jdesktop.wonderland.client.jme.ViewManager.ViewManagerListener;
import org.jdesktop.wonderland.client.login.ServerSessionManager;
import org.jdesktop.wonderland.client.scenemanager.event.ContextEvent;
import org.jdesktop.wonderland.common.annotation.Plugin;
import org.jdesktop.wonderland.common.cell.CellTransform;
import org.jdesktop.wonderland.modules.avatarbase.client.AvatarSessionLoader.AvatarLoaderStateListener;
import org.jdesktop.wonderland.modules.avatarbase.client.AvatarSessionLoader.State;
import org.jdesktop.wonderland.modules.avatarbase.client.cell.AvatarConfigComponent;
import org.jdesktop.wonderland.modules.avatarbase.client.jme.FlexibleCameraAdapter;
import org.jdesktop.wonderland.modules.avatarbase.client.jme.cellrenderer.AvatarCollisionChangeRequestEvent;
import org.jdesktop.wonderland.modules.avatarbase.client.jme.cellrenderer.AvatarControls;
import org.jdesktop.wonderland.modules.avatarbase.client.jme.cellrenderer.AvatarImiJME;
import org.jdesktop.wonderland.modules.avatarbase.client.jme.cellrenderer.AvatarImiJME.AvatarChangedListener;
import org.jdesktop.wonderland.modules.avatarbase.client.jme.cellrenderer.AvatarTestPanel;
import org.jdesktop.wonderland.modules.avatarbase.client.jme.cellrenderer.GestureHUD;
import org.jdesktop.wonderland.modules.avatarbase.client.jme.cellrenderer.WlAvatarCharacter;
import org.jdesktop.wonderland.modules.avatarbase.client.jme.cellrenderer.WonderlandAvatarCache;
import org.jdesktop.wonderland.modules.avatarbase.client.registry.AvatarRegistry;
import org.jdesktop.wonderland.modules.avatarbase.client.registry.AvatarRegistry.AvatarInUseListener;
import org.jdesktop.wonderland.modules.avatarbase.client.registry.spi.AvatarSPI;
import org.jdesktop.wonderland.modules.avatarbase.client.ui.AvatarConfigFrame;
import org.jdesktop.wonderland.modules.avatarbase.common.cell.AvatarConfigInfo;

/**
* A client-side plugin to initialize the avatar system
*
* @author Jordan Slott <jslott@dev.java.net>
*/
@Plugin
public class AvatarClientPlugin extends BaseClientPlugin
        implements AvatarLoaderStateListener, ViewManagerListener {

    private static Logger logger = Logger.getLogger(AvatarClientPlugin.class.getName());

    private static final ResourceBundle bundle =
            ResourceBundle.getBundle("org/jdesktop/wonderland/modules/" +
            "avatarbase/client/resources/Bundle");

    // A map of a session and the loader for that session
    private Map<ServerSessionManager, AvatarSessionLoader> loaderMap = null;

    // Listener for when a new avatar becomes in-use
    private AvatarInUseListener inUseListener = null;

    // Listen for when the avatar character changes to update the state of the
    // chase camera.
    private AvatarChangedListener avatarChangedListener = null;

    // The current avatar cell renderer
    private AvatarImiJME avatarCellRenderer = null;

    // Chase camera state and model and menu item
    private ChaseCamState camState = null;
    private ChaseCamModel camModel = null;
    private JRadioButtonMenuItem chaseCameraMI = null;


    // Some test control panels for the avatar
    private WeakReference<AvatarTestPanel> testPanelRef = null;
    private JMenuItem avatarControlsMI = null;
    private JMenuItem avatarSettingsMI = null;
    private Instrumentation instrumentation = null;

    // The gesture HUD panel and menu item
    private WeakReference<GestureHUD> gestureHUDRef = null;
    private JCheckBoxMenuItem gestureMI = null;

    // True if the menus have been added to the main menu, false if not
    private boolean menusAdded = false;

    // Menu items for the collision & gravity check boxes
    private JCheckBoxMenuItem collisionResponseEnabledMI = null;
    private JCheckBoxMenuItem gravityEnabledMI = null;

    // The avatar configuration menu item
    private JMenuItem avatarConfigMI = null;

    // Indicates that the avatar has already been set once the primary view
    // has been set, so that is does not happen more than once. We synchronized
    // on the mutex
    private Lock isAvatarSetMutex = new ReentrantLock();
    private Boolean isAvatarSet = false;

    // Context menu listener
    private ContextMenuListener ctxListener;

    /**
     * {@inheritDoc]
     */
    @Override
    public void initialize(ServerSessionManager manager) {
        loaderMap = new HashMap();

        // A listener for changes to the primary view cell renderer. (This
        // rarely happens in practice). When the avatar cell renderer changes,
        // reset the chase camera state.
        avatarChangedListener = new AvatarChangedListener() {
            public void avatarChanged(Avatar newAvatar) {
                if (camState != null) {
                    // stop listener for changes from the old avatar cell
                    // renderer.
                    avatarCellRenderer.removeAvatarChangedListener(avatarChangedListener);

                    if (newAvatar.getContext() != null) {
                        camState.setTargetCharacter(newAvatar);
                    }
                    else {
                        camState.setTargetCharacter(null);
                    }

                    // Fetch the initial position of the camera. This is based
                    // upon the current avatar position. We can assume that the
                    // primary View Cell exists at this point, since the menu
                    // item is not added until a primary View Cell exists.
                    ViewManager viewManager = ViewManager.getViewManager();
                    ViewCell viewCell = viewManager.getPrimaryViewCell();
                    CellTransform transform = viewCell.getWorldTransform();
                    Vector3f translation = transform.getTranslation(null);

                    // This is the offset from the avatar view Cell to place the
                    // camera
                    Vector3f offset = new Vector3f(0.0f, 4.0f, -10.0f);

                    // force an update
                    camState.setCameraPosition(translation.add(offset));
                }

                // OWL issue #125: Reinitialize the gesture HUD panel with the
                // current avatar character.
                if (gestureHUDRef != null && gestureHUDRef.get() != null) {
                    if (newAvatar instanceof WlAvatarCharacter) {
                        gestureHUDRef.get().setAvatarCharacter((WlAvatarCharacter) newAvatar,
                                                               gestureMI.getState());
                    } else {
                        gestureHUDRef.get().setVisible(false);
                    }
                }
            }
        };

        // A menu item for the chase camera
        chaseCameraMI = new JRadioButtonMenuItem(bundle.getString("Chase_Camera"));
        chaseCameraMI.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                // Fetch the initial position of the camera. This is based upon
                // the current avatar position. We can assume that the primary
                // View Cell exists at this point, since the menu item is not
                // added until a primary View Cell exists.
                ViewManager viewManager = ViewManager.getViewManager();
                ViewCell viewCell = viewManager.getPrimaryViewCell();
                CellTransform transform = viewCell.getWorldTransform();
                Vector3f translation = transform.getTranslation(null);

                // This is the offset from the avatar view Cell to place the
                // camera
                Vector3f offset = new Vector3f(0.0f, 4.0f, -10.0f);

                // Create the camera state if it does not yet exist. Initialize
                // the initial position to that of the view Cell.
                if (camState == null) {
                    camModel = (ChaseCamModel) CameraModels.getCameraModel(ChaseCamModel.class);
                    camState = new ChaseCamState(offset, new Vector3f(0.0f, 1.8f, 0.0f));
                    camState.setDamping(1.7f);
                    camState.setLookAtDamping(1.7f);
                }
                camState.setCameraPosition(translation.add(offset));
                camState.setTargetCharacter(avatarCellRenderer.getAvatarCharacter());

                // Create the Chase Camera with the model and state and add to
                // the View Manager
                FlexibleCameraAdapter chaseCamera =
                        new FlexibleCameraAdapter(camModel, camState);
                viewManager.setCameraController(chaseCamera);
            }
        });

        // A menu item for a test control panel for the avatar.
//        avatarControlsMI = new JMenuItem(bundle.getString("Avatar_Controls"));
//        avatarControlsMI.addActionListener(new ActionListener() {
//            public void actionPerformed(ActionEvent e) {
//                if (testPanelRef == null || testPanelRef.get() == null) {
//                    AvatarTestPanel test = new AvatarTestPanel();
//                    JFrame f = new JFrame(bundle.getString("Avatar_Controls"));
//                    f.getContentPane().add(test);
//                    f.pack();
//                    f.setVisible(true);
//                    f.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
//                    test.setAvatarCharacter(avatarCellRenderer.getAvatarCharacter());
//                    testPanelRef = new WeakReference(test);
//                } else {
//                    SwingUtilities.getRoot(testPanelRef.get().getParent()).setVisible(true);
//                }
//            }
//        });

        // Avatar Instrumentation is a dev tool
//        avatarSettingsMI = new JMenuItem(bundle.getString("Avatar_Settings..."));
//        avatarSettingsMI.addActionListener(new ActionListener() {
//            public void actionPerformed(ActionEvent e) {
//                AvatarInstrumentation in = new AvatarInstrumentation(instrumentation);
//                in.setVisible(true);
//            }
//        });
//        instrumentation = new DefaultInstrumentation(ClientContextJME.getWorldManager());

        // The menu item for the Gesture (HUD)
        gestureMI = new JCheckBoxMenuItem(bundle.getString("Gesture_UI"));
        gestureMI.setSelected(false);
        gestureMI.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                boolean visible = gestureMI.isSelected();
                if (gestureHUDRef == null || gestureHUDRef.get() == null) {
                    GestureHUD hud = new GestureHUD(gestureMI);
                    hud.setAvatarCharacter(avatarCellRenderer.getAvatarCharacter(), visible);
                    gestureHUDRef = new WeakReference(hud);
                }
                //issue #174 hud visibility management
                if (visible) {
                  gestureHUDRef.get().setMaximized();
                }
                gestureHUDRef.get().setVisible(visible);
            }       
        });

        // The menu item for the avatar configuration
        avatarConfigMI = new JMenuItem(bundle.getString("Avatar_Appearance..."));
        avatarConfigMI.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                AvatarConfigFrame f = new AvatarConfigFrame();
                f.setVisible(true);
            }
        });

        // Check box to set collision enabled
        collisionResponseEnabledMI = new JCheckBoxMenuItem(bundle.getString("Avatar_Collision_Response_Enabled"));
        collisionResponseEnabledMI.setSelected(true); // TODO should be set by server
        collisionResponseEnabledMI.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                boolean isCollisionResponse = collisionResponseEnabledMI.isSelected();
                boolean isGravity = gravityEnabledMI.isSelected();
                ClientContext.getInputManager().postEvent(
                        new AvatarCollisionChangeRequestEvent(isCollisionResponse, isGravity));
            }
        });

        // Check box to set gravity (floor following) enabled
        gravityEnabledMI = new JCheckBoxMenuItem(bundle.getString("Avatar_Gravity_Enabled"));
        gravityEnabledMI.setSelected(true); // TODO should be set by server
        gravityEnabledMI.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                boolean isCollisionResponse = collisionResponseEnabledMI.isSelected();
                boolean isGravity = gravityEnabledMI.isSelected();
                ClientContext.getInputManager().postEvent(
                        new AvatarCollisionChangeRequestEvent(isCollisionResponse, isGravity));
            }
        });

        ctxListener = new ContextMenuListener() {
            public void contextMenuDisplayed(ContextMenuEvent event) {
                // only deal with invocations on AvatarCell
                if (!(event.getPrimaryCell() instanceof AvatarCell)) {
                    return;
                }

                ContextMenuInvocationSettings settings = event.getSettings();
                settings.setDisplayStandard(false);
                settings.setDisplayCellStandard(false);

                AvatarCell cell = (AvatarCell) event.getPrimaryCell();
                settings.setMenuName(cell.getIdentity().getUsername());

                // if this is our avatar, add the configuration menu
                if (cell == ViewManager.getViewManager().getPrimaryViewCell()) {
                    settings.addTempFactory(new ConfigureContextMenuFactory());
                }
            }
        };

        // register the renderer for this session
        ClientContextJME.getAvatarRenderManager().registerRenderer(manager,
                AvatarImiJME.class, AvatarControls.class);

        // XXX TODO: this shouldn't be done here -- it should be done in
        // activate or should be registered per session not globally
        // XXX
        try {
            String serverHostAndPort = manager.getServerNameAndPort();
            String baseURL = "wla://avatarbaseart/";
            URL url = AssetUtils.getAssetURL(baseURL, serverHostAndPort);
            WorldManager worldManager = ClientContextJME.getWorldManager();
            worldManager.addUserData(Repository.class, new Repository(worldManager,
                    new WonderlandAvatarCache(url.toExternalForm(),
                    ClientContext.getUserDirectory("AvatarCache"))));
        } catch (MalformedURLException excp) {
            logger.log(Level.WARNING, "Unable to form avatar base URL", excp);
        } catch(Exception e) {
            logger.log(Level.SEVERE,"Exception, are you using JDK 5 ?", e);
        }

        // Initialize the AvatarSystem after we set up caching
        AvatarSystem.initialize(ClientContextJME.getWorldManager());
       
        super.initialize(manager);
    }

    /**
     * {@inheritDoc]
     */
    @Override
    public void cleanup() {
        // XXX should be done in deactivate XXX
        WorldManager worldManager = ClientContextJME.getWorldManager();
        worldManager.removeUserData(Repository.class);

        ServerSessionManager manager = getSessionManager();
        ClientContextJME.getAvatarRenderManager().unregisterRenderer(manager);
       
        super.cleanup();
    }

    /**
     * {@inheritDoc]
     */
    @Override
    protected void activate() {
        // Upon a new session, load the session and put it in the map. Wait
        // for it to finish loading. When done then set up the view Cell or
        // wait for it to finish.
        ServerSessionManager manager = getSessionManager();
        AvatarSessionLoader loader = new AvatarSessionLoader(manager);
        loaderMap.put(manager, loader);
        loader.addAvatarLoaderStateListener(this);
        loader.load();

        // set up our custom context menu listener to disable the standard
        // menus on avatar cells
        ContextMenuManager.getContextMenuManager().addContextMenuListener(ctxListener);
    }

    /**
     * {@inheritDoc]
     */
    @Override
    protected void deactivate() {
        ContextMenuManager.getContextMenuManager().removeContextMenuListener(ctxListener);

        // First remove the menus. This will prevent users from taking action
        // upon the avatar in the (small) chance they do while the session is
        // being deactivated.
        if (menusAdded == true) {
            MainFrame frame = JmeClientMain.getFrame();
            frame.removeFromWindowMenu(gestureMI);
            frame.removeFromToolsMenu(collisionResponseEnabledMI);
            frame.removeFromToolsMenu(gravityEnabledMI);
            frame.removeFromEditMenu(avatarConfigMI);
           
            if (frame instanceof MainFrameImpl) { // Until MainFrame gets this method added
                ((MainFrameImpl) frame).removeFromCameraChoices(chaseCameraMI);
            }
            else {
                frame.removeFromViewMenu(chaseCameraMI);
            }

            // Remove the avatar controls (test) if it exists
            if (avatarControlsMI != null) {
                frame.removeFromWindowMenu(avatarControlsMI);
            }

            // Add the avatar instrumentions settings if it exists
            if (avatarSettingsMI != null) {
                frame.removeFromEditMenu(avatarSettingsMI);
            }
            menusAdded = false;
        }

        // Next, remove the listener for changes in avatar in use. This will
        // prevent the avatar from being updated while the avatars are removed
        // from the system.
        if (inUseListener != null) {
            AvatarRegistry.getAvatarRegistry().removeAvatarInUseListener(inUseListener);
            inUseListener = null;
        }

        // Stop listening for primary view changes.
        ViewManager.getViewManager().removeViewManagerListener(this);

        // Finally, fetch the avatar session loader for the session just ended
        // and unload all of the avatars from the system. This will remove the
        // avatars one-by-one.
        AvatarSessionLoader loader = loaderMap.get(getSessionManager());
        if (loader != null) {
            loader.removeAvatarLoaderStateListener(this);
            loader.unload();
            loaderMap.remove(getSessionManager());
        }
    }

    /**
     * {@inheritDoc]
     */
    public void stateChanged(State state) {
        if (state == State.READY) {
            // If the state is ready, then set-up the primary view Cell if it is
            // ready or wait for it to become ready.
            ViewManager manager = ViewManager.getViewManager();
            manager.addViewManagerListener(this);
            if (manager.getPrimaryViewCell() != null) {
                // fake a view cell changed event
                primaryViewCellChanged(null, manager.getPrimaryViewCell());
            }
        }
    }

    /**
     * {@inheritDoc]
     */
    public void primaryViewCellChanged(ViewCell oldViewCell, final ViewCell newViewCell) {
        // TODO tidy up oldViewCell
       
        // If there is an old avatar, then remove the listener (although in
        // practice primary view cells do not change.
        if (avatarCellRenderer != null) {
            avatarCellRenderer.removeAvatarChangedListener(avatarChangedListener);
        }

        // If the new primary view cell is null, then just return here
        if (newViewCell == null) {
            return;
        }

        logger.info("Primary view Cell Changes from " + oldViewCell +
                " to " + newViewCell + " " + newViewCell.getName());
       
        // Fetch the cell renderer for the new primary view Cell. It should
        // be of type AvatarImiJME. If not, log a warning and return
        CellRenderer rend = newViewCell.getCellRenderer(RendererType.RENDERER_JME);
        if (!(rend instanceof AvatarImiJME)) {
            logger.warning("Cell renderer for view " + newViewCell.getName() +
                    " is not of type AvatarImiJME.");
            return;
        }

        // We also want to listen (if we aren't doing so already) for when the
        // avatar in-use has changed.
        if (inUseListener == null) {
            inUseListener = new AvatarInUseListener() {
                public void avatarInUse(AvatarSPI avatar, boolean isLocal) {
                    refreshAvatarInUse(newViewCell, isLocal);
                }
            };
            AvatarRegistry.getAvatarRegistry().addAvatarInUseListener(inUseListener);
        }

        // set the current avatar
        avatarCellRenderer = (AvatarImiJME) rend;

        // start listener for new changes. This is used for the chase camera.
        avatarCellRenderer.addAvatarChangedListener(avatarChangedListener);

        // Set the state of the chase camera from the current avatar in the
        // cell renderer.
        if (camState != null) {
            camState.setTargetCharacter(avatarCellRenderer.getAvatarCharacter());
            camModel.reset(camState);
        }

        // Initialize the avatar control panel (test) with the current avatar
        // character.
        //        if (testPanelRef != null && testPanelRef.get() != null) {
        //            testPanelRef.get().setAvatarCharacter(avatarCellRenderer.getAvatarCharacter());
        //        }

        // Initialize the gesture HUD panel with the current avatar character.
        if (gestureHUDRef != null && gestureHUDRef.get() != null) {
            gestureHUDRef.get().setAvatarCharacter(avatarCellRenderer.getAvatarCharacter(),
                                                   gestureMI.isSelected());
        }

        // We also want to listen (if we aren't doing so already) for when the
        // avatar in-use has changed.
        if (inUseListener == null) {
            inUseListener = new AvatarInUseListener() {
                public void avatarInUse(AvatarSPI avatar, boolean isLocal) {
                    refreshAvatarInUse(newViewCell, isLocal);
                }
            };
            AvatarRegistry.getAvatarRegistry().addAvatarInUseListener(inUseListener);
        }

        // Once the avatar loader is ready and the primary view has been set,
        // we tell the avatar cell component to set it's avatar in use. We can
        // only do this after we know the AvatarConfigComponent is on the View
        // Cell. We therefore add a listener, but also check immediately whether
        // the component exists. The handleSetAvatar() method makes sure that
        // the call to refresh() only happens once.
        isAvatarSet = false;
        newViewCell.addComponentChangeListener(new ComponentChangeListener() {
            public void componentChanged(Cell cell, ChangeType type,
                    CellComponent component) {
                AvatarConfigComponent c =
                        cell.getComponent(AvatarConfigComponent.class);
                if (type == ChangeType.ADDED && c != null) {
                    handleSetAvatar((ViewCell)cell);
                }
            }
        });
        if (newViewCell.getComponent(AvatarConfigComponent.class) != null) {
            handleSetAvatar(newViewCell);
        }

        // Finally, enable the menu items to allow avatar configuration. We
        // do this after the view cell is set, so we know we have an avatar
        // in the world.
        if (menusAdded == false) {
            MainFrame frame = JmeClientMain.getFrame();
            frame.addToWindowMenu(gestureMI, 0);
            frame.addToToolsMenu(gravityEnabledMI, 3);
            frame.addToToolsMenu(collisionResponseEnabledMI, 2);
            frame.addToEditMenu(avatarConfigMI, 0);

            if (frame instanceof MainFrameImpl) { // Only until the MainFrame interface gets this method
                ((MainFrameImpl) frame).addToCameraChoices(chaseCameraMI, 3);
            }
            else {
                frame.addToViewMenu(chaseCameraMI, 3);
            }

            // Add the avatar control (test) if it exists
            if (avatarControlsMI != null) {
                frame.addToWindowMenu(avatarControlsMI, 0);
            }

            // Add the avatar instrumentation settings if it exists
            if (avatarSettingsMI != null) {
                frame.addToEditMenu(avatarSettingsMI, 1);
            }
            menusAdded = true;
        }
    }

    /**
     * Handles when the primary view has been set and the view cell contains an
     * AvatarConfigComponent. This insures that the refresh() avatar is only
     * called once.
     */
    private void handleSetAvatar(ViewCell viewCell) {
        // We synchronize on 'isAvatarSet' and only call refresh() if the value
        // is false.
        isAvatarSetMutex.lock();
        try {
            if (isAvatarSet == false) {
                isAvatarSet = true;
                refreshAvatarInUse(viewCell, false);
            }
        } finally {
            isAvatarSetMutex.unlock();
        }
    }

    /**
     * Refreshes the primary view cell with the current avatar in use given the
     * current primary view cell.
     */
    public synchronized void refreshAvatarInUse(ViewCell viewCell, boolean isLocal) {

        // Once the avatar loader is ready and the primary view has been set,
        // we tell the avatar cell component to set it's avatar in use.
        AvatarConfigComponent configComponent = viewCell.getComponent(AvatarConfigComponent.class);
        AvatarRegistry registry = AvatarRegistry.getAvatarRegistry();
        AvatarSPI avatar = registry.getAvatarInUse();
        if (avatar != null) {
            ServerSessionManager session = viewCell.getCellCache().getSession().getSessionManager();
            AvatarConfigInfo configInfo = avatar.getAvatarConfigInfo(session);
            configComponent.requestAvatarConfigInfo(configInfo, isLocal);
        }
    }

    /**
     * Context menu factory for configuring your avatar
     */
    private static class ConfigureContextMenuFactory
            implements ContextMenuFactorySPI
    {
        public ContextMenuItem[] getContextMenuItems(ContextEvent event) {
            return new ContextMenuItem[] {
                new SimpleContextMenuItem(bundle.getString("Configure..."),
                        new ContextMenuActionListener()
                {
                    public void actionPerformed(ContextMenuItemEvent event) {
                        AvatarConfigFrame f = new AvatarConfigFrame();
                        f.setVisible(true);
                    }
                })
            };
        }
    }
}
TOP

Related Classes of org.jdesktop.wonderland.modules.avatarbase.client.AvatarClientPlugin$ConfigureContextMenuFactory

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.