1. /*
  2. * @(#)DefaultFocusManager.java 1.15 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import java.awt.event.KeyEvent;
  9. import java.awt.Component;
  10. import java.awt.Container;
  11. import java.awt.event.ActionEvent;
  12. import java.awt.Window;
  13. import java.awt.Dialog;
  14. import java.awt.Rectangle;
  15. import java.util.Stack;
  16. /**
  17. * Default swing focus manager implementation.
  18. *
  19. * @version 1.15 11/29/01
  20. * @author Arnaud Weber
  21. */
  22. public class DefaultFocusManager extends FocusManager {
  23. /** This method is called by JComponents when a key event occurs.
  24. * JComponent gives key events to the focus manager
  25. * first, then to key listeners, then to the keyboard UI dispatcher.
  26. * This method should look at the key event and change the focused
  27. * component if the key event matches the receiver's focus manager
  28. * hot keys. For example the default focus manager will change the
  29. * focus if the key event matches TAB or Shift + TAB.
  30. * The focus manager should call consume() on <b>anEvent</b> if
  31. * <code>anEvent</code> has been processed.
  32. * <code>focusedComponent</code> is the component that currently has
  33. * the focus.
  34. * Note: FocusManager will receive KEY_PRESSED, KEY_RELEASED and KEY_TYPED
  35. * key events. If one event is consumed, all other events type should be consumed.
  36. */
  37. Stack history = new Stack();
  38. public void processKeyEvent(Component focusedComponent,KeyEvent anEvent) {
  39. if(anEvent.getKeyCode() == KeyEvent.VK_TAB || anEvent.getKeyChar() == '\t') {
  40. /** If the focused component manages focus, let it do so
  41. * if control is not pressed
  42. */
  43. if(focusedComponent instanceof JComponent) {
  44. JComponent fc = (JComponent) focusedComponent;
  45. if(fc.isManagingFocus()) {
  46. int isctrl = (anEvent.getModifiers() &
  47. ActionEvent.CTRL_MASK);
  48. if ((isctrl != ActionEvent.CTRL_MASK) ||
  49. (anEvent.getKeyCode() == KeyEvent.VK_I))
  50. return;
  51. }
  52. }
  53. /** If this is not a key press, consume and return **/
  54. if(anEvent.getID() != KeyEvent.KEY_PRESSED){
  55. anEvent.consume();
  56. return;
  57. }
  58. // System.out.println("\n\n******TAB pressed in processKeyEvent");
  59. if((anEvent.getModifiers() & ActionEvent.SHIFT_MASK) == ActionEvent.SHIFT_MASK)
  60. focusPreviousComponent(focusedComponent);
  61. else
  62. focusNextComponent(focusedComponent);
  63. anEvent.consume();
  64. }
  65. }
  66. /** Cause the focus manager to set the focus on the next focusable component **/
  67. public void focusNextComponent(Component aComponent) {
  68. if(aComponent instanceof JComponent) {
  69. JComponent fc = (JComponent) aComponent;
  70. Component nc;
  71. Container root = getFocusRoot(fc);
  72. if (!history.empty() && history.peek() != aComponent) {
  73. history.removeAllElements();
  74. }
  75. if(root != null) {
  76. nc = getFocusableComponentAfter(fc,root,true);
  77. if(nc != null) {
  78. if (history.empty() || history.peek() == aComponent) {
  79. history.push(nc);
  80. }
  81. if(nc instanceof JComponent)
  82. ((JComponent)nc).grabFocus();
  83. else
  84. nc.requestFocus();
  85. }
  86. }
  87. }
  88. }
  89. /** Cause the focus manager to set the focus on the previous focusable component **/
  90. public void focusPreviousComponent(Component aComponent) {
  91. if(aComponent instanceof JComponent) {
  92. JComponent fc = (JComponent) aComponent;
  93. Component nc;
  94. Container root = getFocusRoot(fc);
  95. if (!history.empty() && history.peek() == aComponent) {
  96. history.pop();
  97. if (!history.empty()) {
  98. nc = (Component) history.peek();
  99. if (nc instanceof JComponent)
  100. ((JComponent)nc).grabFocus();
  101. else
  102. nc.requestFocus();
  103. return;
  104. }
  105. }
  106. history.removeAllElements();
  107. if(root != null) {
  108. nc = getFocusableComponentAfter(fc,root,false);
  109. if(nc != null) {
  110. if(nc instanceof JComponent)
  111. ((JComponent)nc).grabFocus();
  112. else
  113. nc.requestFocus();
  114. }
  115. }
  116. }
  117. }
  118. Container getFocusRoot(Component c) {
  119. Container p;
  120. for(p = c.getParent() ; p != null ; p = p.getParent()) {
  121. if(((p instanceof JComponent) && ((JComponent)p).isFocusCycleRoot()) ||
  122. (p instanceof Window) || (p instanceof Dialog))
  123. return p;
  124. }
  125. return null;
  126. }
  127. private Component getFocusableComponentAfter(Component focusedComponent,
  128. Container rootContainer,
  129. boolean moveForward) {
  130. Component nextComponent;
  131. Component initialComponent;
  132. nextComponent = initialComponent = focusedComponent;
  133. do {
  134. if(moveForward) {
  135. nextComponent = getNextComponent(nextComponent,rootContainer,true);
  136. } else
  137. nextComponent = getPreviousComponent(nextComponent,rootContainer);
  138. if(nextComponent == null)
  139. break;
  140. if(nextComponent == initialComponent)
  141. break;
  142. } while(!(nextComponent.isVisible() &&
  143. nextComponent.isFocusTraversable() &&
  144. nextComponent.isEnabled()));
  145. return nextComponent;
  146. }
  147. private Component getNextComponent(Component component,
  148. Container root,
  149. boolean canGoDown) {
  150. Component nsv = null;
  151. if(canGoDown && component.isVisible() &&
  152. ( !(component instanceof JComponent) ||
  153. !(((JComponent)component).isManagingFocus()) ) &&
  154. ((component instanceof Container) && ((Container)component).getComponentCount() > 0)) {
  155. return getFirstComponent((Container)component);
  156. } else {
  157. Container parent = component.getParent();
  158. nsv = getComponentAfter(parent,component);
  159. if(nsv != null)
  160. return nsv;
  161. if(parent == root)
  162. return root;
  163. else
  164. return getNextComponent(parent,root,false);
  165. }
  166. }
  167. private Component getPreviousComponent(Component component,Container root) {
  168. Container parent = component.getParent();
  169. if(component == root)
  170. return getDeepestLastComponent(root);
  171. else {
  172. Component nsv = getComponentBefore(parent,component);
  173. if(nsv != null)
  174. return getDeepestLastComponent(nsv);
  175. else
  176. return parent;
  177. }
  178. }
  179. private Component getDeepestLastComponent(Component component) {
  180. if(component.isVisible() &&
  181. (((component instanceof JComponent) &&
  182. !((JComponent)component).isManagingFocus()) ||
  183. !(component instanceof JComponent)) &&
  184. ((component instanceof Container) && ((Container)component).getComponentCount() > 0)) {
  185. return getDeepestLastComponent(getLastComponent((Container) component));
  186. } else
  187. return component;
  188. }
  189. /** Return the first component that should receive the focus **/
  190. public Component getFirstComponent(Container aContainer) {
  191. Component orderedChildren[] = childrenTabOrder(aContainer);
  192. if(orderedChildren.length > 0)
  193. return orderedChildren[0];
  194. else
  195. return null;
  196. }
  197. /** Return the last component that should receive the focus **/
  198. public Component getLastComponent(Container aContainer) {
  199. Component orderedChildren[] = childrenTabOrder(aContainer);
  200. if(orderedChildren.length > 0)
  201. return orderedChildren[orderedChildren.length - 1];
  202. else
  203. return null;
  204. }
  205. /** Return the component that should receive the focus before aComponent **/
  206. public Component getComponentBefore(Container aContainer,Component aComponent) {
  207. Component comp;
  208. if ((comp = inverseGetNextFocusable(aContainer, aComponent)) != null)
  209. return comp;
  210. return tabOrderPreviousComponent(aContainer, aComponent);
  211. }
  212. /** Return the component the should receive the focus after aComponent **/
  213. public Component getComponentAfter(Container aContainer,Component aComponent) {
  214. Component nc;
  215. if ((aComponent instanceof JComponent) &&
  216. (nc = ((JComponent)aComponent).getNextFocusableComponent()) != null){
  217. return nc;
  218. }
  219. return tabOrderNextComponent(aContainer, aComponent);
  220. }
  221. /** Return true if <code>a</code> should be before <code>b</code> in the
  222. * "tab" order. Override this method if you want to change the automatic
  223. * "tab" order.
  224. * The default implementation will order tab to give a left to right, top
  225. * down order. Override this method if another order is required.
  226. */
  227. public boolean compareTabOrder(Component a,Component b) {
  228. Rectangle bounds;
  229. int ay,by;
  230. int ax,bx;
  231. if(a instanceof JComponent) {
  232. ay = ((JComponent)a).getY();
  233. ax = ((JComponent)a).getX();
  234. } else {
  235. bounds = a.getBounds();
  236. ay = bounds.y;
  237. ax = bounds.x;
  238. }
  239. if(b instanceof JComponent) {
  240. by = ((JComponent)b).getY();
  241. bx = ((JComponent)b).getX();
  242. } else {
  243. bounds = b.getBounds();
  244. by = bounds.y;
  245. bx = bounds.x;
  246. }
  247. if(Math.abs(ay - by) < 10) {
  248. return (ax < bx);
  249. }
  250. return (ay < by);
  251. }
  252. /** Return the component after comp according to compareTabOrder. If
  253. * comp is the last component according to that order, return null.
  254. */
  255. private Component tabOrderNextComponent(Container cont, Component cmp) {
  256. Component orderedChildren[] = childrenTabOrder(cont);
  257. int i;
  258. int c = orderedChildren.length;
  259. /* since cmp is a child of cont, we know cont has at least one child */
  260. if (c == 1) return null;
  261. for(i=0; i < c - 1 ; i++)
  262. if(orderedChildren[i] == cmp)
  263. return orderedChildren[i+1];
  264. return null;
  265. }
  266. /** Return the component before comp according to compareTabOrder. If
  267. * comp is the first component according to that order, return null.
  268. */
  269. private Component tabOrderPreviousComponent(Container cont, Component cmp) {
  270. Component orderedChildren[] = childrenTabOrder(cont);
  271. int i;
  272. int c = orderedChildren.length;
  273. /* since cmp is a child of cont, we know cont has at least one child */
  274. if (c==1) return null;
  275. for(i=1; i < c ; i++)
  276. if(orderedChildren[i] == cmp)
  277. return orderedChildren[i-1];
  278. return null;
  279. }
  280. /** If there is a child c of Cont such that
  281. * c.getNextFocusableComponent == comp, return that component.
  282. * Otherwise, return null.
  283. */
  284. private Component inverseGetNextFocusable(Container cont, Component comp) {
  285. Component children[] = cont.getComponents();
  286. int i;
  287. int c;
  288. for(i=0,c = children.length ; i < c ; i++) {
  289. if((children[i] instanceof JComponent) &&
  290. (((JComponent)children[i]).getNextFocusableComponent()) == comp)
  291. return children[i];
  292. }
  293. return null;
  294. }
  295. Component[] childrenTabOrder(Container co) {
  296. Component children[] = co.getComponents();
  297. Component tmp;
  298. int i,j,c;
  299. /** Get the tab order from the geometry **/
  300. for(i=0,c = children.length ; i < c ; i++) {
  301. for(j=i ; j < c ; j++) {
  302. if(i==j)
  303. continue;
  304. if(compareTabOrder(children[j],children[i])) {
  305. tmp = children[i];
  306. children[i] = children[j];
  307. children[j] = tmp;
  308. }
  309. }
  310. }
  311. return children;
  312. }
  313. void clearHistory() {
  314. history.removeAllElements();
  315. }
  316. }