001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Alexander T. Simbirtsev
019: * @version $Revision$
020: */package javax.swing;
021:
022: import java.awt.Component;
023: import java.awt.Point;
024: import java.awt.event.KeyEvent;
025: import java.awt.event.MouseEvent;
026:
027: import javax.swing.event.ChangeEvent;
028: import javax.swing.event.ChangeListener;
029: import javax.swing.event.EventListenerList;
030:
031: import org.apache.harmony.x.swing.Utilities;
032:
033: public class MenuSelectionManager {
034:
035: protected transient ChangeEvent changeEvent;
036: protected EventListenerList listenerList = new EventListenerList();
037:
038: static final MenuElement[] EMPTY_PATH = new MenuElement[0];
039:
040: private static MenuSelectionManager defaultManager;
041:
042: private MenuElement[] selectedPath;
043:
044: public static MenuSelectionManager defaultManager() {
045: if (defaultManager == null) {
046: defaultManager = new MenuSelectionManager();
047: }
048: return defaultManager;
049: }
050:
051: public void addChangeListener(final ChangeListener listener) {
052: listenerList.add(ChangeListener.class, listener);
053: }
054:
055: public void removeChangeListener(final ChangeListener listener) {
056: listenerList.remove(ChangeListener.class, listener);
057: }
058:
059: public ChangeListener[] getChangeListeners() {
060: return (ChangeListener[]) listenerList
061: .getListeners(ChangeListener.class);
062: }
063:
064: protected void fireStateChanged() {
065: ChangeListener[] listeners = getChangeListeners();
066: if (listeners.length == 0) {
067: return;
068: }
069: if (changeEvent == null) {
070: changeEvent = new ChangeEvent(this );
071: }
072: for (int i = 0; i < listeners.length; i++) {
073: listeners[i].stateChanged(changeEvent);
074: }
075: }
076:
077: public void setSelectedPath(final MenuElement[] path) {
078: if (selectedPath == path) {
079: return;
080: }
081:
082: int diffStart = 0;
083: if (selectedPath != null && path != null) {
084: int minLength = Math.min(selectedPath.length, path.length);
085: while (diffStart < minLength
086: && selectedPath[diffStart] == path[diffStart]) {
087: diffStart++;
088: }
089: }
090: if (selectedPath != null) {
091: for (int j = selectedPath.length - 1; j >= diffStart; j--) {
092: selectedPath[j].menuSelectionChanged(false);
093: }
094: }
095: if (path != null) {
096: for (int j = diffStart; j < path.length; j++) {
097: path[j].menuSelectionChanged(true);
098: }
099: }
100:
101: selectedPath = path;
102: fireStateChanged();
103: }
104:
105: public MenuElement[] getSelectedPath() {
106: if (isPathEmpty()) {
107: return EMPTY_PATH;
108: }
109:
110: return (MenuElement[]) selectedPath.clone();
111: }
112:
113: public void clearSelectedPath() {
114: setSelectedPath(null);
115: }
116:
117: public Component componentForPoint(final Component c, final Point p) {
118: if (isPathEmpty()) {
119: return null;
120: }
121:
122: for (int i = selectedPath.length - 1; i >= 0; i--) {
123: Component curComponent = selectedPath[i].getComponent();
124: Point convertedPoint = SwingUtilities.convertPoint(c, p,
125: curComponent);
126: if (curComponent.contains(convertedPoint)) {
127: return curComponent;
128: }
129: }
130:
131: return null;
132: }
133:
134: public boolean isComponentPartOfCurrentMenu(final Component c) {
135: if (isPathEmpty()) {
136: return false;
137: }
138: final MenuElement firstMenuElement = selectedPath[0];
139: if (firstMenuElement == c) {
140: return true;
141: }
142:
143: if (firstMenuElement instanceof JMenuBar
144: || firstMenuElement instanceof JPopupMenu) {
145: final JComponent menu = (JComponent) firstMenuElement;
146: final int numComponents = menu.getComponentCount();
147: for (int i = 0; i < numComponents; i++) {
148: Component curItem = menu.getComponent(i);
149: if ((curItem == c) || curItem instanceof JMenu
150: && ((JMenu) curItem).isMenuComponent(c)) {
151: return true;
152: }
153: }
154: } else if (firstMenuElement instanceof JMenu) {
155: return ((JMenu) firstMenuElement).isMenuComponent(c);
156: }
157:
158: return false;
159: }
160:
161: public void processKeyEvent(final KeyEvent event) {
162: if (isPathEmpty()) {
163: return;
164: }
165:
166: for (int i = selectedPath.length - 1; i >= 0; i--) {
167: final MenuElement[] subElements = selectedPath[i]
168: .getSubElements();
169: for (int j = 0; j < subElements.length; j++) {
170: Component c = subElements[j].getComponent();
171: if (!c.isVisible() || !c.isEnabled()) {
172: continue;
173: }
174: if (c instanceof MenuElement) {
175: final MenuElement[] curPath = Utilities
176: .getMenuElementPath(subElements[j]);
177: ((MenuElement) c).processKeyEvent(event, curPath,
178: this );
179: if (event.isConsumed()) {
180: return;
181: }
182: }
183: }
184: }
185: }
186:
187: public void processMouseEvent(final MouseEvent event) {
188: Component c = componentForPoint((Component) event.getSource(),
189: event.getPoint());
190:
191: if (isPathEmpty()) {
192: return;
193: }
194:
195: if ((event.getID() == MouseEvent.MOUSE_DRAGGED)
196: || (event.getID() == MouseEvent.MOUSE_RELEASED)) {
197:
198: if (c instanceof JMenuItem) {
199: ((JMenuItem) c).processMouseEvent(event, selectedPath,
200: this );
201: }
202: }
203: }
204:
205: boolean isPathEmpty() {
206: return Utilities.isEmptyArray(selectedPath);
207: }
208: }
|