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