blob: c9144fdd251d433d8594d5b64f1979b4d21cc801 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* AbstractMenuFactory.java
*
* Created on January 24, 2004, 7:23 PM
*/
package org.netbeans.actions.engine.spi;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.beans.BeanInfo;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;
import org.netbeans.actions.spi.ActionProvider;
import org.netbeans.actions.spi.ContainerProvider;
/** Basic implementation of a menu factory.
*
* @author Tim Boudreau
*/
public abstract class AbstractMenuFactory implements MenuFactory {
private AbstractEngine engine;
protected static final String KEY_CONTAINERCONTEXT = "containerContext"; //NOI18N
protected static final String KEY_ACTION = "action";
protected static final String KEY_CREATOR = "creator";
/** Creates a new instance of AbstractMenuFactory */
protected AbstractMenuFactory(AbstractEngine engine) {
if (engine == null) throw new NullPointerException (
"Engine may not be null."); //NOI18N
this.engine = engine;
}
protected AbstractEngine getEngine() {
return engine;
}
public JMenu createMenu (String containerContext) {
System.err.println("Creating a menu: " + containerContext);
JMenu result = new JMenu();
result.putClientProperty (KEY_CONTAINERCONTEXT, containerContext);
result.setName(containerContext);
result.setText (getEngine().getContainerProvider().getDisplayName(
ContainerProvider.TYPE_MENU, containerContext));
populateMenu(containerContext, result); //XXX listener should do this
attachToMenu(result);
return result;
}
private void attachToMenu (JMenu menu) {
menu.addContainerListener(getMenuListener());
menu.addComponentListener(getMenuListener());
menu.addMenuListener(getMenuListener());
}
public String getContainerContext (JMenu menu) {
return (String) menu.getClientProperty (KEY_CONTAINERCONTEXT);
}
private Listener listener = null;
private Listener getMenuListener() {
if (listener == null) {
listener = new Listener();
}
return listener;
}
private JMenuItem getOrCreateMenuItem(int type) {
JMenuItem result = type == ActionProvider.ACTION_TYPE_ITEM ? new JMenuItem() :
type == ActionProvider.ACTION_TYPE_SUBCONTEXT ? new JMenu() : null;
if (type == ActionProvider.ACTION_TYPE_ITEM) {
result.addActionListener (getItemListener());
} else if (type == ActionProvider.ACTION_TYPE_SUBCONTEXT){
attachToMenu ((JMenu) result);
}
result.putClientProperty (KEY_CREATOR, this);
return result;
}
protected void populateMenu (String containerCtx, JMenu menu) {
ActionProvider provider = getEngine().getActionProvider();
String[] names = provider.getActionNames(containerCtx);
for (int i=0; i < names.length; i++) {
JMenuItem item = getOrCreateMenuItem(
provider.getActionType(names[i], containerCtx));
configureMenuItem (item, containerCtx, names[i], provider, null);
menu.add(item);
}
getEngine().notifyMenuShown(containerCtx, menu); //XXX listener should do this
addMapping (containerCtx, menu, ContainerProvider.TYPE_MENU); //XXX handle popup
}
protected void depopulateMenu (String containerCtx, JMenu menu) {
menu.removeAll();
}
private void configureMenuItem (JMenuItem item, String containerCtx, String action, ActionProvider provider, Map context) {
// System.err.println("ConfigureMenuItem: " + containerCtx + "/" + action);
item.setName(action);
item.putClientProperty(KEY_ACTION, action);
item.putClientProperty(KEY_CONTAINERCONTEXT, containerCtx);
item.putClientProperty(KEY_CREATOR, this);
item.setText(
provider.getDisplayName(action, containerCtx));
// System.err.println(" item text is " + item.getText());
item.setToolTipText(provider.getDescription(action, containerCtx));
int state = context == null ? ActionProvider.STATE_ENABLED | ActionProvider.STATE_VISIBLE :
provider.getState (action, containerCtx, context);
boolean enabled = (state & ActionProvider.STATE_ENABLED) != 0;
// System.err.println("action " + action + (enabled ? " enabled" : " disabled"));
item.setEnabled(enabled);
boolean visible = (state & ActionProvider.STATE_VISIBLE) != 0;
// System.err.println("action " + action + (visible ? " visible" : " invisible"));
item.setVisible(visible);
item.setMnemonic(provider.getMnemonic(action, containerCtx));
item.setDisplayedMnemonicIndex(provider.getMnemonicIndex(action, containerCtx));
item.setIcon(provider.getIcon(action, containerCtx, BeanInfo.ICON_COLOR_16x16));
}
private String munge (String containerCtx, Object type) {
//XXX create a munge for popup menus
return "menu." + "mainMenu." + containerCtx;
}
private Map mappings = new HashMap();
private void addMapping (String containerCtx, JComponent comp, Object type) {
mappings.put (munge (containerCtx, type), comp);
}
public void update (String containerCtx) {
JMenu menu = (JMenu) mappings.get(munge(containerCtx, ContainerProvider.TYPE_MENU));
if (menu != null) {
updateMenu (menu);
} else {
System.err.println("Tried to update unknown menu context:" + containerCtx);
}
}
private void updateMenu (JMenu menu) {
ActionProvider provider = getEngine().getActionProvider();
Map context = getEngine().getContextProvider().getContext();
String containerCtx = (String) menu.getClientProperty(KEY_CONTAINERCONTEXT);
boolean isDynamic = getEngine().getContainerProvider().isDynamicContext(
ContainerProvider.TYPE_MENU, containerCtx);
String[] actions = provider.getActionNames(containerCtx);
// System.err.println("Updating menu " + containerCtx + "actions: " + Arrays.asList(actions));
int count = menu.getItemCount();
// System.err.println("Item count = " + count);
//XXX for dynamic menus, we'll need to compare the contents of the
//menu with the list of strings, and add/prune
for (int i=0; i < count; i++) {
JMenuItem item = menu.getItem(i);
if (item != null) {
String action = (String) item.getClientProperty (KEY_ACTION);
configureMenuItem (item, containerCtx, action, provider, context);
}
}
}
private MenuItemListener itemListener = null;
private MenuItemListener getItemListener() {
if (itemListener == null) {
itemListener = new MenuItemListener();
}
return itemListener;
}
private class MenuItemListener implements ActionListener {
public void actionPerformed(java.awt.event.ActionEvent e) {
JMenuItem item = (JMenuItem) e.getSource();
String actionCommand = (String) item.getClientProperty(KEY_ACTION);
String context = (String) item.getClientProperty(KEY_CONTAINERCONTEXT);
getEngine().notifyWillPerform (actionCommand, context);
Action action = getEngine().getAction(context, actionCommand);
if (action.isEnabled()) {
ActionEvent event = new ActionEvent (item,
ActionEvent.ACTION_PERFORMED, actionCommand);
action.actionPerformed(event);
}
getEngine().notifyPerformed (actionCommand, context);
}
}
/** Listener which listens to all components to determine their state and
* add context information to child components */
private class Listener extends ComponentAdapter implements ContainerListener, MenuListener {
public void componentAdded(ContainerEvent e) {
JMenu menu = (JMenu) e.getContainer();
JComponent item = (JComponent) e.getChild();
//Mark the child as belonging to the parent container context
String containerContext = getContainerContext(menu);
item.putClientProperty (KEY_CONTAINERCONTEXT, containerContext);
}
public void componentRemoved(ContainerEvent e) {
JComponent menu = (JComponent) e.getContainer();
JComponent item = (JComponent) e.getChild();
item.putClientProperty (KEY_CONTAINERCONTEXT, null);
}
public void componentHidden(ComponentEvent e) {
JMenu menu = (JMenu) e.getComponent();
String containerContext = getContainerContext(menu);
getEngine().notifyMenuHidden (containerContext, menu);
depopulateMenu (containerContext, menu);
}
public void componentShown(ComponentEvent e) {
JMenu menu = (JMenu) e.getComponent();
String containerCtx = getContainerContext(menu);
System.err.println("ComponentShown: Menu" + containerCtx + " - " + menu);
populateMenu(containerCtx, menu);
getEngine().notifyMenuShown (containerCtx, menu);
}
public void menuCanceled(MenuEvent e) {
}
public void menuDeselected(MenuEvent e) {
}
public void menuSelected(MenuEvent e) {
}
}
}