This commit was manufactured by cvs2svn to create branch
[official-gcc.git] / libjava / javax / swing / MenuSelectionManager.java
blob2e93c01e9345b870806a5059db45827972106250
1 /* MenuSelectionManager.java --
2 Copyright (C) 2002, 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.swing;
41 import java.awt.Component;
42 import java.awt.Dimension;
43 import java.awt.Point;
44 import java.awt.event.KeyEvent;
45 import java.awt.event.MouseEvent;
46 import java.util.ArrayList;
47 import java.util.Vector;
49 import javax.swing.event.ChangeEvent;
50 import javax.swing.event.ChangeListener;
51 import javax.swing.event.EventListenerList;
53 /**
54 * This class manages current menu selectection. It provides
55 * methods to clear and set current selected menu path.
56 * It also fires StateChange event to its registered
57 * listeners whenever selected path of the current menu hierarchy
58 * changes.
61 public class MenuSelectionManager
63 /** ChangeEvent fired when selected path changes*/
64 protected ChangeEvent changeEvent = new ChangeEvent(this);
66 /** List of listeners for this MenuSelectionManager */
67 protected EventListenerList listenerList = new EventListenerList();
69 /** Default manager for the current menu hierarchy*/
70 private static final MenuSelectionManager manager = new MenuSelectionManager();
72 /** Path to the currently selected menu */
73 private Vector selectedPath = new Vector();
75 /**
76 * Fires StateChange event to registered listeners
78 protected void fireStateChanged()
80 ChangeListener[] listeners = getChangeListeners();
82 for (int i = 0; i < listeners.length; i++)
83 listeners[i].stateChanged(changeEvent);
86 /**
87 * Adds ChangeListener to this MenuSelectionManager
89 * @param listener ChangeListener to add
91 public void addChangeListener(ChangeListener listener)
93 listenerList.add(ChangeListener.class, listener);
96 /**
97 * Removes ChangeListener from the list of registered listeners
98 * for this MenuSelectionManager.
100 * @param listener ChangeListner to remove
102 public void removeChangeListener(ChangeListener listener)
104 listenerList.remove(ChangeListener.class, listener);
108 * Returns list of registered listeners with MenuSelectionManager
110 * @since 1.4
112 public ChangeListener[] getChangeListeners()
114 return (ChangeListener[]) listenerList.getListeners(ChangeListener.class);
118 * Unselects all the menu elements on the selection path
120 public void clearSelectedPath()
122 // Send events from the bottom most item in the menu - hierarchy to the
123 // top most
124 for (int i = selectedPath.size() - 1; i >= 0; i--)
125 ((MenuElement) selectedPath.get(i)).menuSelectionChanged(false);
127 // clear selected path
128 selectedPath.clear();
130 // notify all listeners that the selected path was changed
131 fireStateChanged();
135 * This method returns menu element on the selected path that contains
136 * given source point. If no menu element on the selected path contains this
137 * point, then null is returned.
139 * @param source Component relative to which sourcePoint is given
140 * @param sourcePoint point for which we want to find menu element that contains it
142 * @return Returns menu element that contains given source point and belongs
143 * to the currently selected path. Null is return if no such menu element found.
145 public Component componentForPoint(Component source, Point sourcePoint)
147 // Convert sourcePoint to screen coordinates.
148 Point sourcePointOnScreen = sourcePoint;
149 SwingUtilities.convertPointToScreen(sourcePointOnScreen, source);
151 Point compPointOnScreen;
152 Component resultComp = null;
154 // For each menu element on the selected path, express its location
155 // in terms of screen coordinates and check if there is any
156 // menu element on the selected path that contains given source point.
157 for (int i = 0; i < selectedPath.size(); i++)
159 Component comp = ((Component) selectedPath.get(i));
160 Dimension size = comp.getSize();
162 // convert location of this menu item to screen coordinates
163 compPointOnScreen = comp.getLocationOnScreen();
165 if (compPointOnScreen.x <= sourcePointOnScreen.x
166 && sourcePointOnScreen.x < compPointOnScreen.x + size.width
167 && compPointOnScreen.y <= sourcePointOnScreen.y
168 && sourcePointOnScreen.y < compPointOnScreen.y + size.height)
170 Point p = sourcePointOnScreen;
171 SwingUtilities.convertPointFromScreen(p, comp);
172 resultComp = SwingUtilities.getDeepestComponentAt(comp, p.x, p.y);
173 break;
176 return resultComp;
180 * Returns shared instance of MenuSelection Manager
182 * @return default Manager
184 public static MenuSelectionManager defaultManager()
186 return manager;
190 * Returns path representing current menu selection
192 * @return Current selection path
194 public MenuElement[] getSelectedPath()
196 MenuElement[] path = new MenuElement[selectedPath.size()];
198 for (int i = 0; i < path.length; i++)
199 path[i] = (MenuElement) selectedPath.get(i);
201 return path;
205 * Returns true if specified component is part of current menu
206 * heirarchy and false otherwise
208 * @param c Component for which to check
209 * @return True if specified component is part of current menu
211 public boolean isComponentPartOfCurrentMenu(Component c)
213 MenuElement[] subElements;
214 for (int i = 0; i < selectedPath.size(); i++)
216 subElements = ((MenuElement) selectedPath.get(i)).getSubElements();
217 for (int j = 0; j < subElements.length; j++)
219 if ((subElements[j].getComponent()).equals(c))
220 return true;
224 return false;
228 * DOCUMENT ME!
230 * @param e DOCUMENT ME!
232 public void processKeyEvent(KeyEvent e)
234 throw new UnsupportedOperationException("not implemented");
238 * Forwards given mouse event to all of the source subcomponents.
240 * @param event Mouse event
242 public void processMouseEvent(MouseEvent event)
244 Component source = ((Component) event.getSource());
246 // In the case of drag event, event.getSource() returns component
247 // where drag event originated. However menu element processing this
248 // event should be the one over which mouse is currently located,
249 // which is not necessary the source of the drag event.
250 Component mouseOverMenuComp;
252 // find over which menu element the mouse is currently located
253 if (event.getID() == MouseEvent.MOUSE_DRAGGED
254 || event.getID() == MouseEvent.MOUSE_RELEASED)
255 mouseOverMenuComp = componentForPoint(source, event.getPoint());
256 else
257 mouseOverMenuComp = source;
259 // Process this event only if mouse is located over some menu element
260 if (mouseOverMenuComp != null && (mouseOverMenuComp instanceof MenuElement))
262 MenuElement[] path = getPath(mouseOverMenuComp);
263 ((MenuElement) mouseOverMenuComp).processMouseEvent(event, path,
264 manager);
266 // FIXME: Java specification says that mouse events should be
267 // forwarded to subcomponents. The code below does it, but
268 // menu's work fine without it. This code is commented for now.
271 MenuElement[] subComponents = ((MenuElement) mouseOverMenuComp)
272 .getSubElements();
274 for (int i = 0; i < subComponents.length; i++)
276 subComponents[i].processMouseEvent(event, path, manager);
283 * Sets menu selection to the specified path
285 * @param path new selection path
287 public void setSelectedPath(MenuElement[] path)
289 if (path == null)
291 clearSelectedPath();
292 return;
295 int i;
296 int minSize = path.length; // size of the smaller path.
298 if (path.length > selectedPath.size())
300 minSize = selectedPath.size();
302 // if new selected path contains more elements then current
303 // selection then first add all elements at
304 // the indexes > selectedPath.size
305 for (i = selectedPath.size(); i < path.length; i++)
307 selectedPath.add(path[i]);
308 path[i].menuSelectionChanged(true);
312 else if (path.length < selectedPath.size())
314 // if new selected path contains less elements then current
315 // selection then first remove all elements from the selection
316 // at the indexes > path.length
317 for (i = selectedPath.size() - 1; i >= path.length; i--)
319 ((MenuElement) selectedPath.get(i)).menuSelectionChanged(false);
320 selectedPath.remove(i);
323 minSize = path.length;
326 // Now compare elements in new and current selection path at the
327 // same location and adjust selection until
328 // same menu elements will be encountered at the
329 // same index in both current and new selection path.
330 MenuElement oldSelectedItem;
332 for (i = minSize - 1; i >= 0; i--)
334 oldSelectedItem = (MenuElement) selectedPath.get(i);
336 if (path[i].equals(oldSelectedItem))
337 break;
339 oldSelectedItem.menuSelectionChanged(false);
340 path[i].menuSelectionChanged(true);
341 selectedPath.setElementAt(path[i], i);
344 fireStateChanged();
348 * Returns path to the specified component
350 * @param c component for which to find path for
352 * @return path to the specified component
354 private MenuElement[] getPath(Component c)
356 // FIXME: There is the same method in BasicMenuItemUI. However I
357 // cannot use it here instead of this method, since I cannot assume that
358 // all the menu elements on the selected path are JMenuItem or JMenu.
359 // For now I've just duplicated it here. Please
360 // fix me or delete me if another better approach will be found, and
361 // this method will not be necessary.
362 ArrayList path = new ArrayList();
364 // if given component is JMenu, we also need to include
365 // it's popup menu in the path
366 if (c instanceof JMenu)
367 path.add(((JMenu) c).getPopupMenu());
368 while (c instanceof MenuElement)
370 path.add(0, (MenuElement) c);
372 if (c instanceof JPopupMenu)
373 c = ((JPopupMenu) c).getInvoker();
374 else
375 c = c.getParent();
378 MenuElement[] pathArray = new MenuElement[path.size()];
379 path.toArray(pathArray);
380 return pathArray;