001: /*
002: * AbstractMenuFactory.java
003: *
004: * Created on January 24, 2004, 7:23 PM
005: */
006:
007: package org.netbeans.actions.engine.spi;
008:
009: import java.awt.event.ActionEvent;
010: import java.awt.event.ActionListener;
011: import java.awt.event.ComponentAdapter;
012: import java.awt.event.ComponentEvent;
013: import java.awt.event.ComponentListener;
014: import java.awt.event.ContainerEvent;
015: import java.awt.event.ContainerListener;
016: import java.beans.BeanInfo;
017: import java.util.Arrays;
018: import java.util.HashMap;
019: import java.util.HashSet;
020: import java.util.Map;
021: import java.util.Set;
022: import javax.swing.Action;
023: import javax.swing.JComponent;
024: import javax.swing.JMenu;
025: import javax.swing.JMenuItem;
026: import javax.swing.event.MenuEvent;
027: import javax.swing.event.MenuListener;
028: import org.netbeans.actions.spi.ActionProvider;
029: import org.netbeans.actions.spi.ContainerProvider;
030:
031: /** Basic implementation of a menu factory.
032: *
033: * @author Tim Boudreau
034: */
035: public abstract class AbstractMenuFactory implements MenuFactory {
036: private AbstractEngine engine;
037: protected static final String KEY_CONTAINERCONTEXT = "containerContext"; //NOI18N
038: protected static final String KEY_ACTION = "action";
039: protected static final String KEY_CREATOR = "creator";
040:
041: /** Creates a new instance of AbstractMenuFactory */
042: protected AbstractMenuFactory(AbstractEngine engine) {
043: if (engine == null)
044: throw new NullPointerException("Engine may not be null."); //NOI18N
045: this .engine = engine;
046: }
047:
048: protected AbstractEngine getEngine() {
049: return engine;
050: }
051:
052: public JMenu createMenu(String containerContext) {
053: System.err.println("Creating a menu: " + containerContext);
054: JMenu result = new JMenu();
055: result
056: .putClientProperty(KEY_CONTAINERCONTEXT,
057: containerContext);
058: result.setName(containerContext);
059: result.setText(getEngine().getContainerProvider()
060: .getDisplayName(ContainerProvider.TYPE_MENU,
061: containerContext));
062: populateMenu(containerContext, result); //XXX listener should do this
063: attachToMenu(result);
064: return result;
065: }
066:
067: private void attachToMenu(JMenu menu) {
068: menu.addContainerListener(getMenuListener());
069: menu.addComponentListener(getMenuListener());
070: menu.addMenuListener(getMenuListener());
071: }
072:
073: public String getContainerContext(JMenu menu) {
074: return (String) menu.getClientProperty(KEY_CONTAINERCONTEXT);
075: }
076:
077: private Listener listener = null;
078:
079: private Listener getMenuListener() {
080: if (listener == null) {
081: listener = new Listener();
082: }
083: return listener;
084: }
085:
086: private JMenuItem getOrCreateMenuItem(int type) {
087: JMenuItem result = type == ActionProvider.ACTION_TYPE_ITEM ? new JMenuItem()
088: : type == ActionProvider.ACTION_TYPE_SUBCONTEXT ? new JMenu()
089: : null;
090: if (type == ActionProvider.ACTION_TYPE_ITEM) {
091: result.addActionListener(getItemListener());
092: } else if (type == ActionProvider.ACTION_TYPE_SUBCONTEXT) {
093: attachToMenu((JMenu) result);
094: }
095: result.putClientProperty(KEY_CREATOR, this );
096: return result;
097: }
098:
099: protected void populateMenu(String containerCtx, JMenu menu) {
100: ActionProvider provider = getEngine().getActionProvider();
101: String[] names = provider.getActionNames(containerCtx);
102: for (int i = 0; i < names.length; i++) {
103: JMenuItem item = getOrCreateMenuItem(provider
104: .getActionType(names[i], containerCtx));
105: configureMenuItem(item, containerCtx, names[i], provider,
106: null);
107: menu.add(item);
108: }
109: getEngine().notifyMenuShown(containerCtx, menu); //XXX listener should do this
110: addMapping(containerCtx, menu, ContainerProvider.TYPE_MENU); //XXX handle popup
111: }
112:
113: protected void depopulateMenu(String containerCtx, JMenu menu) {
114: menu.removeAll();
115: }
116:
117: private void configureMenuItem(JMenuItem item, String containerCtx,
118: String action, ActionProvider provider, Map context) {
119: // System.err.println("ConfigureMenuItem: " + containerCtx + "/" + action);
120: item.setName(action);
121: item.putClientProperty(KEY_ACTION, action);
122: item.putClientProperty(KEY_CONTAINERCONTEXT, containerCtx);
123: item.putClientProperty(KEY_CREATOR, this );
124: item.setText(provider.getDisplayName(action, containerCtx));
125: // System.err.println(" item text is " + item.getText());
126: item.setToolTipText(provider.getDescription(action,
127: containerCtx));
128: int state = context == null ? ActionProvider.STATE_ENABLED
129: | ActionProvider.STATE_VISIBLE : provider.getState(
130: action, containerCtx, context);
131: boolean enabled = (state & ActionProvider.STATE_ENABLED) != 0;
132: // System.err.println("action " + action + (enabled ? " enabled" : " disabled"));
133: item.setEnabled(enabled);
134: boolean visible = (state & ActionProvider.STATE_VISIBLE) != 0;
135: // System.err.println("action " + action + (visible ? " visible" : " invisible"));
136: item.setVisible(visible);
137: item.setMnemonic(provider.getMnemonic(action, containerCtx));
138: item.setDisplayedMnemonicIndex(provider.getMnemonicIndex(
139: action, containerCtx));
140: item.setIcon(provider.getIcon(action, containerCtx,
141: BeanInfo.ICON_COLOR_16x16));
142: }
143:
144: private String munge(String containerCtx, Object type) {
145: //XXX create a munge for popup menus
146: return "menu." + "mainMenu." + containerCtx;
147: }
148:
149: private Map mappings = new HashMap();
150:
151: private void addMapping(String containerCtx, JComponent comp,
152: Object type) {
153: mappings.put(munge(containerCtx, type), comp);
154: }
155:
156: public void update(String containerCtx) {
157: JMenu menu = (JMenu) mappings.get(munge(containerCtx,
158: ContainerProvider.TYPE_MENU));
159: if (menu != null) {
160: updateMenu(menu);
161: } else {
162: System.err.println("Tried to update unknown menu context:"
163: + containerCtx);
164: }
165: }
166:
167: private void updateMenu(JMenu menu) {
168: ActionProvider provider = getEngine().getActionProvider();
169: Map context = getEngine().getContextProvider().getContext();
170: String containerCtx = (String) menu
171: .getClientProperty(KEY_CONTAINERCONTEXT);
172: boolean isDynamic = getEngine().getContainerProvider()
173: .isDynamicContext(ContainerProvider.TYPE_MENU,
174: containerCtx);
175:
176: String[] actions = provider.getActionNames(containerCtx);
177: // System.err.println("Updating menu " + containerCtx + "actions: " + Arrays.asList(actions));
178:
179: int count = menu.getItemCount();
180: // System.err.println("Item count = " + count);
181: //XXX for dynamic menus, we'll need to compare the contents of the
182: //menu with the list of strings, and add/prune
183:
184: for (int i = 0; i < count; i++) {
185: JMenuItem item = menu.getItem(i);
186: if (item != null) {
187: String action = (String) item
188: .getClientProperty(KEY_ACTION);
189: configureMenuItem(item, containerCtx, action, provider,
190: context);
191: }
192: }
193: }
194:
195: private MenuItemListener itemListener = null;
196:
197: private MenuItemListener getItemListener() {
198: if (itemListener == null) {
199: itemListener = new MenuItemListener();
200: }
201: return itemListener;
202: }
203:
204: private class MenuItemListener implements ActionListener {
205: public void actionPerformed(java.awt.event.ActionEvent e) {
206: JMenuItem item = (JMenuItem) e.getSource();
207: String actionCommand = (String) item
208: .getClientProperty(KEY_ACTION);
209: String context = (String) item
210: .getClientProperty(KEY_CONTAINERCONTEXT);
211:
212: getEngine().notifyWillPerform(actionCommand, context);
213:
214: Action action = getEngine().getAction(context,
215: actionCommand);
216:
217: if (action.isEnabled()) {
218: ActionEvent event = new ActionEvent(item,
219: ActionEvent.ACTION_PERFORMED, actionCommand);
220: action.actionPerformed(event);
221: }
222:
223: getEngine().notifyPerformed(actionCommand, context);
224: }
225: }
226:
227: /** Listener which listens to all components to determine their state and
228: * add context information to child components */
229: private class Listener extends ComponentAdapter implements
230: ContainerListener, MenuListener {
231: public void componentAdded(ContainerEvent e) {
232: JMenu menu = (JMenu) e.getContainer();
233: JComponent item = (JComponent) e.getChild();
234: //Mark the child as belonging to the parent container context
235: String containerContext = getContainerContext(menu);
236:
237: item.putClientProperty(KEY_CONTAINERCONTEXT,
238: containerContext);
239: }
240:
241: public void componentRemoved(ContainerEvent e) {
242: JComponent menu = (JComponent) e.getContainer();
243: JComponent item = (JComponent) e.getChild();
244: item.putClientProperty(KEY_CONTAINERCONTEXT, null);
245: }
246:
247: public void componentHidden(ComponentEvent e) {
248: JMenu menu = (JMenu) e.getComponent();
249: String containerContext = getContainerContext(menu);
250: getEngine().notifyMenuHidden(containerContext, menu);
251: depopulateMenu(containerContext, menu);
252: }
253:
254: public void componentShown(ComponentEvent e) {
255: JMenu menu = (JMenu) e.getComponent();
256: String containerCtx = getContainerContext(menu);
257: System.err.println("ComponentShown: Menu" + containerCtx
258: + " - " + menu);
259: populateMenu(containerCtx, menu);
260: getEngine().notifyMenuShown(containerCtx, menu);
261: }
262:
263: public void menuCanceled(MenuEvent e) {
264: }
265:
266: public void menuDeselected(MenuEvent e) {
267: }
268:
269: public void menuSelected(MenuEvent e) {
270: }
271:
272: }
273: }
|