History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/swing/MenuSelectionManager.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/swing/MenuSelectionManager.java+500−0
@@ -0,0 +1,500 @@
1+/*
2+ * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+package javax.swing;
26+
27+import java.awt.*;
28+import java.util.*;
29+import java.awt.event.*;
30+import javax.swing.event.*;
31+
32+import sun.awt.AppContext;
33+
34+/**
35+ * A MenuSelectionManager owns the selection in menu hierarchy.
36+ *
37+ * @author Arnaud Weber
38+ */
39+public class MenuSelectionManager {
40+ private Vector<MenuElement> selection = new Vector<MenuElement>();
41+
42+ /* diagnostic aids -- should be false for production builds. */
43+ private static final boolean TRACE = false; // trace creates and disposes
44+ private static final boolean VERBOSE = false; // show reuse hits/misses
45+ private static final boolean DEBUG = false; // show bad params, misc.
46+
47+ private static final StringBuilder MENU_SELECTION_MANAGER_KEY =
48+ new StringBuilder("javax.swing.MenuSelectionManager");
49+
50+ /**
51+ * Returns the default menu selection manager.
52+ *
53+ * @return a MenuSelectionManager object
54+ */
55+ public static MenuSelectionManager defaultManager() {
56+ synchronized (MENU_SELECTION_MANAGER_KEY) {
57+ AppContext context = AppContext.getAppContext();
58+ MenuSelectionManager msm = (MenuSelectionManager)context.get(
59+ MENU_SELECTION_MANAGER_KEY);
60+ if (msm == null) {
61+ msm = new MenuSelectionManager();
62+ context.put(MENU_SELECTION_MANAGER_KEY, msm);
63+ }
64+
65+ return msm;
66+ }
67+ }
68+
69+ /**
70+ * Only one ChangeEvent is needed per button model instance since the
71+ * event's only state is the source property. The source of events
72+ * generated is always "this".
73+ */
74+ protected transient ChangeEvent changeEvent = null;
75+ protected EventListenerList listenerList = new EventListenerList();
76+
77+ /**
78+ * Changes the selection in the menu hierarchy. The elements
79+ * in the array are sorted in order from the root menu
80+ * element to the currently selected menu element.
81+ * <p>
82+ * Note that this method is public but is used by the look and
83+ * feel engine and should not be called by client applications.
84+ *
85+ * @param path an array of <code>MenuElement</code> objects specifying
86+ * the selected path
87+ */
88+ public void setSelectedPath(MenuElement[] path) {
89+ int i,c;
90+ int currentSelectionCount = selection.size();
91+ int firstDifference = 0;
92+
93+ if(path == null) {
94+ path = new MenuElement[0];
95+ }
96+
97+ if (DEBUG) {
98+ System.out.print("Previous: "); printMenuElementArray(getSelectedPath());
99+ System.out.print("New: "); printMenuElementArray(path);
100+ }
101+
102+ for(i=0,c=path.length;i<c;i++) {
103+ if (i < currentSelectionCount && selection.elementAt(i) == path[i])
104+ firstDifference++;
105+ else
106+ break;
107+ }
108+
109+ for(i=currentSelectionCount - 1 ; i >= firstDifference ; i--) {
110+ MenuElement me = selection.elementAt(i);
111+ selection.removeElementAt(i);
112+ me.menuSelectionChanged(false);
113+ }
114+
115+ for(i = firstDifference, c = path.length ; i < c ; i++) {
116+ if (path[i] != null) {
117+ selection.addElement(path[i]);
118+ path[i].menuSelectionChanged(true);
119+ }
120+ }
121+
122+ fireStateChanged();
123+ }
124+
125+ /**
126+ * Returns the path to the currently selected menu item
127+ *
128+ * @return an array of MenuElement objects representing the selected path
129+ */
130+ public MenuElement[] getSelectedPath() {
131+ MenuElement res[] = new MenuElement[selection.size()];
132+ int i,c;
133+ for(i=0,c=selection.size();i<c;i++)
134+ res[i] = selection.elementAt(i);
135+ return res;
136+ }
137+
138+ /**
139+ * Tell the menu selection to close and unselect all the menu components. Call this method
140+ * when a choice has been made
141+ */
142+ public void clearSelectedPath() {
143+ if (selection.size() > 0) {
144+ setSelectedPath(null);
145+ }
146+ }
147+
148+ /**
149+ * Adds a ChangeListener to the button.
150+ *
151+ * @param l the listener to add
152+ */
153+ public void addChangeListener(ChangeListener l) {
154+ listenerList.add(ChangeListener.class, l);
155+ }
156+
157+ /**
158+ * Removes a ChangeListener from the button.
159+ *
160+ * @param l the listener to remove
161+ */
162+ public void removeChangeListener(ChangeListener l) {
163+ listenerList.remove(ChangeListener.class, l);
164+ }
165+
166+ /**
167+ * Returns an array of all the <code>ChangeListener</code>s added
168+ * to this MenuSelectionManager with addChangeListener().
169+ *
170+ * @return all of the <code>ChangeListener</code>s added or an empty
171+ * array if no listeners have been added
172+ * @since 1.4
173+ */
174+ public ChangeListener[] getChangeListeners() {
175+ return listenerList.getListeners(ChangeListener.class);
176+ }
177+
178+ /**
179+ * Notifies all listeners that have registered interest for
180+ * notification on this event type. The event instance
181+ * is created lazily.
182+ *
183+ * @see EventListenerList
184+ */
185+ protected void fireStateChanged() {
186+ // Guaranteed to return a non-null array
187+ Object[] listeners = listenerList.getListenerList();
188+ // Process the listeners last to first, notifying
189+ // those that are interested in this event
190+ for (int i = listeners.length-2; i>=0; i-=2) {
191+ if (listeners[i]==ChangeListener.class) {
192+ // Lazily create the event:
193+ if (changeEvent == null)
194+ changeEvent = new ChangeEvent(this);
195+ ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
196+ }
197+ }
198+ }
199+
200+ /**
201+ * When a MenuElement receives an event from a MouseListener, it should never process the event
202+ * directly. Instead all MenuElements should call this method with the event.
203+ *
204+ * @param event a MouseEvent object
205+ */
206+ public void processMouseEvent(MouseEvent event) {
207+ int screenX,screenY;
208+ Point p;
209+ int i,c,j,d;
210+ Component mc;
211+ Rectangle r2;
212+ int cWidth,cHeight;
213+ MenuElement menuElement;
214+ MenuElement subElements[];
215+ MenuElement path[];
216+ Vector tmp;
217+ int selectionSize;
218+ p = event.getPoint();
219+
220+ Component source = event.getComponent();
221+
222+ if ((source != null) && !source.isShowing()) {
223+ // This can happen if a mouseReleased removes the
224+ // containing component -- bug 4146684
225+ return;
226+ }
227+
228+ int type = event.getID();
229+ int modifiers = event.getModifiers();
230+ // 4188027: drag enter/exit added in JDK 1.1.7A, JDK1.2
231+ if ((type==MouseEvent.MOUSE_ENTERED||
232+ type==MouseEvent.MOUSE_EXITED)
233+ && ((modifiers & (InputEvent.BUTTON1_MASK |
234+ InputEvent.BUTTON2_MASK | InputEvent.BUTTON3_MASK)) !=0 )) {
235+ return;
236+ }
237+
238+ if (source != null) {
239+ SwingUtilities.convertPointToScreen(p, source);
240+ }
241+
242+ screenX = p.x;
243+ screenY = p.y;
244+
245+ tmp = (Vector)selection.clone();
246+ selectionSize = tmp.size();
247+ boolean success = false;
248+ for (i=selectionSize - 1;i >= 0 && success == false; i--) {
249+ menuElement = (MenuElement) tmp.elementAt(i);
250+ subElements = menuElement.getSubElements();
251+
252+ path = null;
253+ for (j = 0, d = subElements.length;j < d && success == false; j++) {
254+ if (subElements[j] == null)
255+ continue;
256+ mc = subElements[j].getComponent();
257+ if(!mc.isShowing())
258+ continue;
259+ if(mc instanceof JComponent) {
260+ cWidth = mc.getWidth();
261+ cHeight = mc.getHeight();
262+ } else {
263+ r2 = mc.getBounds();
264+ cWidth = r2.width;
265+ cHeight = r2.height;
266+ }
267+ p.x = screenX;
268+ p.y = screenY;
269+ SwingUtilities.convertPointFromScreen(p,mc);
270+
271+ /** Send the event to visible menu element if menu element currently in
272+ * the selected path or contains the event location
273+ */
274+ if(
275+ (p.x >= 0 && p.x < cWidth && p.y >= 0 && p.y < cHeight)) {
276+ int k;
277+ if(path == null) {
278+ path = new MenuElement[i+2];
279+ for(k=0;k<=i;k++)
280+ path[k] = (MenuElement)tmp.elementAt(k);
281+ }
282+ path[i+1] = subElements[j];
283+ MenuElement currentSelection[] = getSelectedPath();
284+
285+ // Enter/exit detection -- needs tuning...
286+ if (currentSelection[currentSelection.length-1] !=
287+ path[i+1] &&
288+ (currentSelection.length < 2 ||
289+ currentSelection[currentSelection.length-2] !=
290+ path[i+1])) {
291+ Component oldMC = currentSelection[currentSelection.length-1].getComponent();
292+
293+ MouseEvent exitEvent = new MouseEvent(oldMC, MouseEvent.MOUSE_EXITED,
294+ event.getWhen(),
295+ event.getModifiers(), p.x, p.y,
296+ event.getXOnScreen(),
297+ event.getYOnScreen(),
298+ event.getClickCount(),
299+ event.isPopupTrigger(),
300+ MouseEvent.NOBUTTON);
301+ currentSelection[currentSelection.length-1].
302+ processMouseEvent(exitEvent, path, this);
303+
304+ MouseEvent enterEvent = new MouseEvent(mc,
305+ MouseEvent.MOUSE_ENTERED,
306+ event.getWhen(),
307+ event.getModifiers(), p.x, p.y,
308+ event.getXOnScreen(),
309+ event.getYOnScreen(),
310+ event.getClickCount(),
311+ event.isPopupTrigger(),
312+ MouseEvent.NOBUTTON);
313+ subElements[j].processMouseEvent(enterEvent, path, this);
314+ }
315+ MouseEvent mouseEvent = new MouseEvent(mc, event.getID(),event. getWhen(),
316+ event.getModifiers(), p.x, p.y,
317+ event.getXOnScreen(),
318+ event.getYOnScreen(),
319+ event.getClickCount(),
320+ event.isPopupTrigger(),
321+ MouseEvent.NOBUTTON);
322+ subElements[j].processMouseEvent(mouseEvent, path, this);
323+ success = true;
324+ event.consume();
325+ }
326+ }
327+ }
328+ }
329+
330+ private void printMenuElementArray(MenuElement path[]) {
331+ printMenuElementArray(path, false);
332+ }
333+
334+ private void printMenuElementArray(MenuElement path[], boolean dumpStack) {
335+ System.out.println("Path is(");
336+ int i, j;
337+ for(i=0,j=path.length; i<j ;i++){
338+ for (int k=0; k<=i; k++)
339+ System.out.print(" ");
340+ MenuElement me = path[i];
341+ if(me instanceof JMenuItem) {
342+ System.out.println(((JMenuItem)me).getText() + ", ");
343+ } else if (me instanceof JMenuBar) {
344+ System.out.println("JMenuBar, ");
345+ } else if(me instanceof JPopupMenu) {
346+ System.out.println("JPopupMenu, ");
347+ } else if (me == null) {
348+ System.out.println("NULL , ");
349+ } else {
350+ System.out.println("" + me + ", ");
351+ }
352+ }
353+ System.out.println(")");
354+
355+ if (dumpStack == true)
356+ Thread.dumpStack();
357+ }
358+
359+ /**
360+ * Returns the component in the currently selected path
361+ * which contains sourcePoint.
362+ *
363+ * @param source The component in whose coordinate space sourcePoint
364+ * is given
365+ * @param sourcePoint The point which is being tested
366+ * @return The component in the currently selected path which
367+ * contains sourcePoint (relative to the source component's
368+ * coordinate space. If sourcePoint is not inside a component
369+ * on the currently selected path, null is returned.
370+ */
371+ public Component componentForPoint(Component source, Point sourcePoint) {
372+ int screenX,screenY;
373+ Point p = sourcePoint;
374+ int i,c,j,d;
375+ Component mc;
376+ Rectangle r2;
377+ int cWidth,cHeight;
378+ MenuElement menuElement;
379+ MenuElement subElements[];
380+ Vector tmp;
381+ int selectionSize;
382+
383+ SwingUtilities.convertPointToScreen(p,source);
384+
385+ screenX = p.x;
386+ screenY = p.y;
387+
388+ tmp = (Vector)selection.clone();
389+ selectionSize = tmp.size();
390+ for(i=selectionSize - 1 ; i >= 0 ; i--) {
391+ menuElement = (MenuElement) tmp.elementAt(i);
392+ subElements = menuElement.getSubElements();
393+
394+ for(j = 0, d = subElements.length ; j < d ; j++) {
395+ if (subElements[j] == null)
396+ continue;
397+ mc = subElements[j].getComponent();
398+ if(!mc.isShowing())
399+ continue;
400+ if(mc instanceof JComponent) {
401+ cWidth = mc.getWidth();
402+ cHeight = mc.getHeight();
403+ } else {
404+ r2 = mc.getBounds();
405+ cWidth = r2.width;
406+ cHeight = r2.height;
407+ }
408+ p.x = screenX;
409+ p.y = screenY;
410+ SwingUtilities.convertPointFromScreen(p,mc);
411+
412+ /** Return the deepest component on the selection
413+ * path in whose bounds the event's point occurs
414+ */
415+ if (p.x >= 0 && p.x < cWidth && p.y >= 0 && p.y < cHeight) {
416+ return mc;
417+ }
418+ }
419+ }
420+ return null;
421+ }
422+
423+ /**
424+ * When a MenuElement receives an event from a KeyListener, it should never process the event
425+ * directly. Instead all MenuElements should call this method with the event.
426+ *
427+ * @param e a KeyEvent object
428+ */
429+ public void processKeyEvent(KeyEvent e) {
430+ MenuElement[] sel2 = new MenuElement[0];
431+ sel2 = selection.toArray(sel2);
432+ int selSize = sel2.length;
433+ MenuElement[] path;
434+
435+ if (selSize < 1) {
436+ return;
437+ }
438+
439+ for (int i=selSize-1; i>=0; i--) {
440+ MenuElement elem = sel2[i];
441+ MenuElement[] subs = elem.getSubElements();
442+ path = null;
443+
444+ for (int j=0; j<subs.length; j++) {
445+ if (subs[j] == null || !subs[j].getComponent().isShowing()
446+ || !subs[j].getComponent().isEnabled()) {
447+ continue;
448+ }
449+
450+ if(path == null) {
451+ path = new MenuElement[i+2];
452+ System.arraycopy(sel2, 0, path, 0, i+1);
453+ }
454+ path[i+1] = subs[j];
455+ subs[j].processKeyEvent(e, path, this);
456+ if (e.isConsumed()) {
457+ return;
458+ }
459+ }
460+ }
461+
462+ // finally dispatch event to the first component in path
463+ path = new MenuElement[1];
464+ path[0] = sel2[0];
465+ path[0].processKeyEvent(e, path, this);
466+ if (e.isConsumed()) {
467+ return;
468+ }
469+ }
470+
471+ /**
472+ * Return true if c is part of the currently used menu
473+ */
474+ public boolean isComponentPartOfCurrentMenu(Component c) {
475+ if(selection.size() > 0) {
476+ MenuElement me = selection.elementAt(0);
477+ return isComponentPartOfCurrentMenu(me,c);
478+ } else
479+ return false;
480+ }
481+
482+ private boolean isComponentPartOfCurrentMenu(MenuElement root,Component c) {
483+ MenuElement children[];
484+ int i,d;
485+
486+ if (root == null)
487+ return false;
488+
489+ if(root.getComponent() == c)
490+ return true;
491+ else {
492+ children = root.getSubElements();
493+ for(i=0,d=children.length;i<d;i++) {
494+ if(isComponentPartOfCurrentMenu(children[i],c))
495+ return true;
496+ }
497+ }
498+ return false;
499+ }
500+}