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.applet.Applet;
023: import java.awt.Component;
024: import java.awt.Container;
025: import java.awt.EventQueue;
026: import java.awt.FontMetrics;
027: import java.awt.Graphics;
028: import java.awt.Insets;
029: import java.awt.KeyboardFocusManager;
030: import java.awt.Point;
031: import java.awt.Rectangle;
032: import java.awt.Window;
033: import java.awt.event.ActionEvent;
034: import java.awt.event.InputEvent;
035: import java.awt.event.KeyEvent;
036: import java.awt.event.MouseEvent;
037: import java.awt.geom.Rectangle2D;
038: import java.lang.reflect.InvocationTargetException;
039: import java.util.ArrayList;
040:
041: import javax.accessibility.Accessible;
042: import javax.accessibility.AccessibleComponent;
043: import javax.accessibility.AccessibleContext;
044: import javax.accessibility.AccessibleStateSet;
045: import javax.swing.plaf.UIResource;
046:
047: import org.apache.harmony.x.swing.Utilities;
048:
049: import org.apache.harmony.x.swing.internal.nls.Messages;
050:
051: public class SwingUtilities implements SwingConstants {
052:
053: private static final Rectangle auxRect = new Rectangle();
054:
055: private SwingUtilities() {
056: }
057:
058: public static String layoutCompoundLabel(final JComponent c,
059: final FontMetrics fm, final String text, final Icon icon,
060: final int verticalAlignment, final int horizontalAlignment,
061: final int verticalTextPosition,
062: final int horizontalTextPosition, final Rectangle viewR,
063: final Rectangle iconR, final Rectangle textR,
064: final int textIconGap) {
065:
066: final int hTextPos = Utilities.convertLeadTrail(
067: horizontalTextPosition, c);
068: final int hPos = Utilities.convertLeadTrail(
069: horizontalAlignment, c);
070:
071: return doLayoutCompoundLabel(fm, text, icon, verticalAlignment,
072: hPos, verticalTextPosition, hTextPos, viewR, iconR,
073: textR, textIconGap);
074: }
075:
076: public static String layoutCompoundLabel(final FontMetrics fm,
077: final String text, final Icon icon,
078: final int verticalAlignment, final int horizontalAlignment,
079: final int verticalTextPosition,
080: final int horizontalTextPosition, final Rectangle viewR,
081: final Rectangle iconR, final Rectangle textR,
082: final int textIconGap) {
083:
084: final int hTextPos = defaultLeadTrail(horizontalTextPosition,
085: RIGHT);
086: final int hPos = defaultLeadTrail(horizontalAlignment, CENTER);
087:
088: return doLayoutCompoundLabel(fm, text, icon, verticalAlignment,
089: hPos, verticalTextPosition, hTextPos, viewR, iconR,
090: textR, textIconGap);
091: }
092:
093: public static MouseEvent convertMouseEvent(final Component source,
094: final MouseEvent event, final Component destination) {
095: Point convertedPoint = convertPoint(source, event.getPoint(),
096: destination);
097: return new MouseEvent((destination != null) ? destination
098: : source, event.getID(), event.getWhen(), event
099: .getModifiersEx(), convertedPoint.x, convertedPoint.y,
100: event.getClickCount(), event.isPopupTrigger(), event
101: .getButton());
102: }
103:
104: public static Rectangle convertRectangle(final Component source,
105: final Rectangle rect, final Component destination) {
106: Rectangle convertedRect = new Rectangle(rect);
107: convertedRect.setLocation(convertPoint(source, rect.x, rect.y,
108: destination));
109: return convertedRect;
110: }
111:
112: public static Point convertPoint(final Component source,
113: final Point point, final Component destination) {
114: return (point != null) ? convertPoint(source, point.x, point.y,
115: destination) : null;
116: }
117:
118: public static Point convertPoint(final Component source,
119: final int x, final int y, final Component destination) {
120: Point convertedPoint = new Point(x, y);
121: if (source != null && destination != null) {
122: convertPointToScreen(convertedPoint, source);
123: convertPointFromScreen(convertedPoint, destination);
124: } else {
125: translateRelatedPoint(convertedPoint, source, 1, true);
126: translateRelatedPoint(convertedPoint, destination, -1, true);
127: }
128:
129: return convertedPoint;
130: }
131:
132: public static void convertPointToScreen(final Point point,
133: final Component component) {
134: if (component == null) {
135: throw new NullPointerException(Messages
136: .getString("swing.61")); //$NON-NLS-1$
137: }
138: translateRelatedPoint(point, component, 1, false);
139: }
140:
141: public static void convertPointFromScreen(final Point point,
142: final Component component) {
143: if (component == null) {
144: throw new NullPointerException(Messages
145: .getString("swing.62")); //$NON-NLS-1$
146: }
147: translateRelatedPoint(point, component, -1, false);
148: }
149:
150: public static Rectangle[] computeDifference(final Rectangle rect1,
151: final Rectangle rect2) {
152: if (rect1 == null || rect1.isEmpty() || rect2 == null
153: || rect2.isEmpty()) {
154: return new Rectangle[0];
155: }
156: Rectangle isection = rect1.intersection(rect2);
157: if (isection.isEmpty()) {
158: return new Rectangle[0];
159: }
160: ArrayList reminders = new ArrayList(4);
161: substract(rect1, isection, reminders);
162: return (Rectangle[]) reminders.toArray(new Rectangle[0]);
163: }
164:
165: private static void substract(final Rectangle rect,
166: final Rectangle isection, final ArrayList remainders) {
167: int isectionRight = isection.x + isection.width;
168: int rectRight = rect.x + rect.width;
169: int isectionBottom = isection.y + isection.height;
170: int rectBottom = rect.y + rect.height;
171:
172: if (isection.y > rect.y) {
173: remainders.add(new Rectangle(rect.x, rect.y, rect.width,
174: isection.y - rect.y));
175: }
176: if (isection.x > rect.x) {
177: remainders.add(new Rectangle(rect.x, isection.y, isection.x
178: - rect.x, isection.height));
179: }
180: if (isectionRight < rectRight) {
181: remainders.add(new Rectangle(isectionRight, isection.y,
182: rectRight - isectionRight, isection.height));
183: }
184: if (isectionBottom < rectBottom) {
185: remainders.add(new Rectangle(rect.x, isectionBottom,
186: rect.width, rectBottom - isectionBottom));
187: }
188: }
189:
190: public static Rectangle calculateInnerArea(
191: final JComponent component, final Rectangle rect) {
192: if (component == null) {
193: return null;
194: }
195:
196: Insets insets = component.getInsets();
197: Rectangle bounds = component.getBounds(rect);
198: bounds.setRect(insets.left, insets.top, bounds.width
199: - insets.right - insets.left, bounds.height
200: - insets.top - insets.bottom);
201: return bounds;
202: }
203:
204: public static final boolean isRectangleContainingRectangle(
205: final Rectangle r1, final Rectangle r2) {
206: return r1.contains(r2);
207: }
208:
209: public static Rectangle computeUnion(final int x, final int y,
210: final int width, final int height, final Rectangle rect) {
211: auxRect.setBounds(x, y, width, height);
212: Rectangle2D.union(auxRect, rect, rect);
213: return rect;
214: }
215:
216: public static Rectangle computeIntersection(final int x,
217: final int y, final int width, final int height,
218: final Rectangle rect) {
219: auxRect.setBounds(x, y, width, height);
220: Rectangle2D.intersect(auxRect, rect, rect);
221: if (rect.height < 0 || rect.width < 0) {
222: rect.setBounds(0, 0, 0, 0);
223: }
224: return rect;
225: }
226:
227: public static Rectangle getLocalBounds(final Component component) {
228: return new Rectangle(0, 0, component.getWidth(), component
229: .getHeight());
230: }
231:
232: public static Container getAncestorNamed(final String name,
233: final Component component) {
234: Component ancestor = null;
235: if (component != null && name != null) {
236: for (ancestor = Utilities.getNotWindowParent(component); !((ancestor == null) || name
237: .equals(ancestor.getName())); ancestor = Utilities
238: .getNotWindowParent(ancestor))
239: ;
240: }
241: return (Container) ancestor;
242: }
243:
244: public static Container getAncestorOfClass(
245: final Class<?> wantedClass, final Component component) {
246: if (component == null || wantedClass == null) {
247: return null;
248: }
249:
250: Component ancestor = null;
251: for (ancestor = component.getParent(); !((ancestor == null) || (wantedClass
252: .isAssignableFrom(ancestor.getClass()))); ancestor = ancestor
253: .getParent()) {
254: }
255: return (Container) ancestor;
256: }
257:
258: public static JRootPane getRootPane(final Component component) {
259: if (component == null) {
260: return null;
261: }
262: if (component instanceof JRootPane) {
263: return (JRootPane) component;
264: }
265: if (component instanceof RootPaneContainer) {
266: return ((RootPaneContainer) component).getRootPane();
267: }
268: return (JRootPane) getAncestorOfClass(JRootPane.class,
269: component);
270: }
271:
272: public static Window windowForComponent(final Component component) {
273: return (Window) getAncestorOfClass(Window.class, component);
274: }
275:
276: public static Window getWindowAncestor(final Component component) {
277: return windowForComponent(component);
278: }
279:
280: public static boolean isDescendingFrom(final Component child,
281: final Component parent) {
282: if (parent == child) {
283: return true;
284: }
285:
286: for (Component ancestor = Utilities.getNotWindowParent(child); ancestor != null; ancestor = Utilities
287: .getNotWindowParent(ancestor)) {
288:
289: if (ancestor == parent) {
290: return true;
291: }
292: }
293:
294: return false;
295: }
296:
297: public static void paintComponent(final Graphics graphics,
298: final Component component, final Container container,
299: final int x, final int y, final int width, final int height) {
300: Container auxContainer = Utilities
301: .getNotWindowParent(component);
302: if (auxContainer instanceof CellRendererPane) {
303: if (Utilities.getNotWindowParent(auxContainer) != container) {
304: container.add(auxContainer);
305: }
306: } else {
307: auxContainer = new CellRendererPane();
308: container.add(auxContainer);
309: }
310: ((CellRendererPane) auxContainer).paintComponent(graphics,
311: component, container, x, y, width, height, false);
312: }
313:
314: public static void paintComponent(final Graphics graphics,
315: final Component component, final Container container,
316: final Rectangle rect) {
317: paintComponent(graphics, component, container, rect.x, rect.y,
318: rect.width, rect.height);
319: }
320:
321: private static InputMap getUIInputMapChild(final InputMap inputMap) {
322: if (inputMap == null) {
323: return null;
324: }
325:
326: InputMap result = inputMap;
327: InputMap parent = inputMap.getParent();
328: while (parent != null && !(parent instanceof UIResource)) {
329: result = parent;
330: parent = result.getParent();
331: }
332:
333: return result;
334: }
335:
336: public static InputMap getUIInputMap(final JComponent component,
337: final int condition) {
338: InputMap inputMap = getUIInputMapChild(component
339: .getInputMap(condition));
340: return (inputMap != null) ? inputMap.getParent() : null;
341: }
342:
343: public static void replaceUIInputMap(final JComponent component,
344: final int condition, final InputMap uiInputMap) {
345: InputMap inputMap = component.getInputMap(condition);
346:
347: if (inputMap == null) {
348: component.setInputMap(condition, uiInputMap);
349: } else {
350: if (uiInputMap != null) {
351: inputMap = getUIInputMapChild(inputMap);
352: inputMap.setParent(uiInputMap);
353: } else {
354: while (inputMap != null) {
355: if (inputMap.getParent() instanceof UIResource) {
356: inputMap.setParent(inputMap.getParent()
357: .getParent());
358: } else {
359: inputMap = inputMap.getParent();
360: }
361: }
362: }
363: }
364: }
365:
366: private static ActionMap getUIActionMapChild(
367: final ActionMap actionMap) {
368: if (actionMap == null) {
369: return null;
370: }
371:
372: ActionMap result = actionMap;
373: ActionMap parent = actionMap.getParent();
374: while (parent != null && !(parent instanceof UIResource)) {
375: result = parent;
376: parent = result.getParent();
377: }
378:
379: return result;
380: }
381:
382: public static ActionMap getUIActionMap(final JComponent component) {
383: ActionMap actionMap = getUIActionMapChild(component
384: .getActionMap());
385: return (actionMap != null) ? actionMap.getParent() : null;
386: }
387:
388: public static void replaceUIActionMap(final JComponent component,
389: final ActionMap uiActionMap) {
390: ActionMap actionMap = component.getActionMap();
391:
392: if (actionMap == null) {
393: component.setActionMap(uiActionMap);
394: } else {
395: if (uiActionMap != null) {
396: actionMap = getUIActionMapChild(actionMap);
397: actionMap.setParent(uiActionMap);
398: } else {
399: while (actionMap != null) {
400: if (actionMap.getParent() instanceof UIResource) {
401: actionMap.setParent(actionMap.getParent()
402: .getParent());
403: } else {
404: actionMap = actionMap.getParent();
405: }
406: }
407: }
408: }
409: }
410:
411: public static void updateComponentTreeUI(final Component component) {
412: updateComponentTreeUILevel(component);
413:
414: component.invalidate();
415: component.validate();
416: component.repaint();
417: }
418:
419: private static void updateComponentTreeUILevel(
420: final Component parent) {
421: if (parent instanceof JComponent) {
422: ((JComponent) parent).updateUI();
423: }
424: Component[] children = null;
425: if (parent instanceof JMenu) {
426: children = ((JMenu) parent).getMenuComponents();
427: } else if (parent instanceof Container) {
428: children = ((Container) parent).getComponents();
429: }
430: if (children == null) {
431: return;
432: }
433: for (int iChild = 0; iChild < children.length; iChild++) {
434: updateComponentTreeUILevel(children[iChild]);
435: }
436: }
437:
438: public static int computeStringWidth(final FontMetrics metrics,
439: final String str) {
440: return metrics.stringWidth(str);
441: }
442:
443: public static Component getDeepestComponentAt(
444: final Component component, final int x, final int y) {
445: if (!component.contains(x, y)) {
446: return null;
447: }
448:
449: Component parent = component;
450: Component child = parent;
451: while (child != null && child instanceof Container) {
452: parent = child;
453: child = parent.getComponentAt(x, y);
454: if (child == parent) {
455: break;
456: }
457: }
458:
459: return (child != null) ? child : parent;
460: }
461:
462: public static Component getRoot(final Component component) {
463: Component result = getWindowOrAppletAncestor(component);
464: Component topRoot = result;
465: while (topRoot instanceof Applet) {
466: result = topRoot;
467: topRoot = getWindowOrAppletAncestor(topRoot.getParent());
468: }
469: return result;
470: }
471:
472: public static Component findFocusOwner(final Component component) {
473: return KeyboardFocusManager.getCurrentKeyboardFocusManager()
474: .getFocusOwner();
475: }
476:
477: public static void invokeLater(final Runnable r) {
478: EventQueue.invokeLater(r);
479: }
480:
481: public static void invokeAndWait(final Runnable r)
482: throws InterruptedException, InvocationTargetException {
483: EventQueue.invokeAndWait(r);
484: }
485:
486: public static boolean isEventDispatchThread() {
487: return EventQueue.isDispatchThread();
488: }
489:
490: public static boolean isRightMouseButton(final MouseEvent event) {
491: return isMouseButtonDown(event, InputEvent.BUTTON3_DOWN_MASK,
492: MouseEvent.BUTTON3);
493: }
494:
495: public static boolean isMiddleMouseButton(final MouseEvent event) {
496: return isMouseButtonDown(event, InputEvent.BUTTON2_DOWN_MASK,
497: MouseEvent.BUTTON2);
498: }
499:
500: public static boolean isLeftMouseButton(final MouseEvent event) {
501: return isMouseButtonDown(event, InputEvent.BUTTON1_DOWN_MASK,
502: MouseEvent.BUTTON1);
503: }
504:
505: public static boolean processKeyBindings(final KeyEvent event) {
506: if (event == null || event.isConsumed()) {
507: return false;
508: }
509:
510: Component source = event.getComponent();
511: return JComponent.processKeyBindings(event, source);
512: }
513:
514: public static boolean notifyAction(final Action action,
515: final KeyStroke keyStroke, final KeyEvent keyEvent,
516: final Object sender, final int modifiers) {
517: if (action == null || !action.isEnabled()) {
518: return false;
519: }
520: Object command = action.getValue(Action.ACTION_COMMAND_KEY);
521: if (command == null && !(action instanceof ActionProxy)) {
522: char keyChar = keyEvent.getKeyChar();
523: if (keyChar != KeyEvent.CHAR_UNDEFINED) {
524: command = String.valueOf(keyChar);
525: }
526: }
527:
528: action.actionPerformed(new ActionEvent(sender,
529: ActionEvent.ACTION_PERFORMED, (String) command,
530: keyEvent.getWhen(), modifiers));
531:
532: return true;
533: }
534:
535: static boolean processKeyEventOnChildren(final Container parent,
536: final KeyEvent event) {
537: for (int iChild = 0; iChild < parent.getComponentCount(); iChild++) {
538: final Component child = parent.getComponent(iChild);
539: if (child instanceof AbstractButton) {
540: if (((AbstractButton) child).processMnemonics(event)) {
541: return true;
542: }
543: }
544: if (processKeyEventOnComponent(child, event)) {
545: return true;
546: }
547: if (child instanceof Container) {
548: if (processKeyEventOnChildren((Container) child, event)) {
549: return true;
550: }
551: }
552: }
553:
554: return false;
555: }
556:
557: static boolean processKeyEventOnComponent(final Component target,
558: final KeyEvent event) {
559: if (target instanceof JComponent) {
560: final boolean pressed = (event.getID() == KeyEvent.KEY_PRESSED);
561: final KeyStroke keyStroke = KeyStroke
562: .getKeyStrokeForEvent(event);
563: if (((JComponent) target).processKeyBinding(keyStroke,
564: event, JComponent.WHEN_IN_FOCUSED_WINDOW, pressed)) {
565: return true;
566: }
567: }
568:
569: return false;
570: }
571:
572: public static Accessible getAccessibleAt(final Component component,
573: final Point point) {
574: Accessible result = null;
575:
576: if (component == null) {
577: return null;
578: }
579: AccessibleContext context = component.getAccessibleContext();
580: if (context == null) {
581: return null;
582: }
583: AccessibleComponent accessibleComponent = context
584: .getAccessibleComponent();
585: if (accessibleComponent == null) {
586: return null;
587: }
588:
589: return accessibleComponent.getAccessibleAt(point);
590: }
591:
592: public static AccessibleStateSet getAccessibleStateSet(
593: final Component component) {
594: AccessibleContext context = component.getAccessibleContext();
595: if (context == null) {
596: return null;
597: }
598:
599: return context.getAccessibleStateSet();
600: }
601:
602: public static Accessible getAccessibleChild(
603: final Component component, final int index) {
604: AccessibleContext context = component.getAccessibleContext();
605: if (context == null) {
606: return null;
607: }
608:
609: return context.getAccessibleChild(index);
610: }
611:
612: public static int getAccessibleIndexInParent(
613: final Component component) {
614: return component.getAccessibleContext()
615: .getAccessibleIndexInParent();
616: }
617:
618: public static int getAccessibleChildrenCount(
619: final Component component) {
620: return component.getAccessibleContext()
621: .getAccessibleChildrenCount();
622: }
623:
624: /**
625: * method that actually implements functionality of both public
626: * layoutCompoundLabel() methods
627: */
628: private static String doLayoutCompoundLabel(final FontMetrics fm,
629: final String text, final Icon icon,
630: final int verticalAlignment, final int horizontalAlignment,
631: final int verticalTextPosition,
632: final int horizontalTextPosition, final Rectangle viewR,
633: final Rectangle iconR, final Rectangle textR,
634: final int textIconGap) {
635:
636: final int gap = icon != null && !Utilities.isEmptyString(text) ? textIconGap
637: : 0;
638:
639: if (icon != null) {
640: iconR.setSize(icon.getIconWidth(), icon.getIconHeight());
641: } else {
642: iconR.setSize(0, 0);
643: }
644:
645: String clippedText = "";
646: if (!Utilities.isEmptyString(text)) {
647: final int adjust = horizontalTextPosition != CENTER ? iconR.width
648: + gap
649: : 0;
650: final int availableLength = viewR.width - adjust;
651: clippedText = Utilities.clipString(fm, text,
652: availableLength);
653: textR.setSize(Utilities.getStringSize(clippedText, fm));
654: } else {
655: textR.setSize(0, 0);
656: }
657:
658: layoutRects(verticalAlignment, horizontalAlignment,
659: verticalTextPosition, horizontalTextPosition, viewR,
660: iconR, textR, gap);
661:
662: return clippedText;
663: }
664:
665: private static void layoutRects(final int verticalAlignment,
666: final int horizontalAlignment, final int vTextPos,
667: final int hTextPos, final Rectangle viewR,
668: final Rectangle iconR, final Rectangle textR, final int gap) {
669:
670: boolean horizontal = hTextPos != CENTER;
671: boolean vertical = vTextPos != CENTER;
672:
673: int hIconPos = hTextPos;
674: int vIconPos = vTextPos;
675: int width = Math.max(iconR.width, textR.width);
676: int height = Math.max(iconR.height, textR.height);
677:
678: if (horizontal) {
679: hIconPos = hTextPos != LEFT ? LEFT : RIGHT;
680: width = iconR.width + textR.width + gap;
681: } else if (vertical) {
682: vIconPos = vTextPos != TOP ? TOP : BOTTOM;
683: height = iconR.height + textR.height + gap;
684: }
685:
686: Rectangle labelR = new Rectangle(width, height);
687:
688: Utilities.alignRect(labelR, viewR, horizontalAlignment,
689: verticalAlignment);
690: Utilities.alignRect(textR, labelR, hTextPos, vTextPos);
691: Utilities.alignRect(iconR, labelR, hIconPos, vIconPos);
692: }
693:
694: private static int defaultLeadTrail(final int anchor,
695: final int value) {
696: if (anchor == LEADING || anchor == TRAILING) {
697: return value;
698: }
699: return anchor;
700: }
701:
702: private static Component getWindowOrAppletAncestor(
703: final Component component) {
704: Component result = component;
705: while (result != null
706: && !(result instanceof Window || result instanceof Applet)) {
707: result = Utilities.getNotWindowParent(result);
708: }
709: return result;
710: }
711:
712: private static void translateRelatedPoint(final Point point,
713: final Component c, final int direction,
714: final boolean stopAtRootPane) {
715: Component currentComponent = c;
716: while ((currentComponent != null)
717: && (!stopAtRootPane || stopAtRootPane
718: && !(currentComponent instanceof JRootPane))) {
719: Point componentLocation = currentComponent.getLocation();
720: point.x += direction * componentLocation.x;
721: point.y += direction * componentLocation.y;
722: currentComponent = Utilities
723: .getNotWindowParent(currentComponent);
724: }
725: }
726:
727: private static boolean isMouseButtonDown(final MouseEvent e,
728: final int downMask, final int button) {
729: return ((e.getModifiersEx() & downMask) != 0)
730: || ((e.getID() == MouseEvent.MOUSE_PRESSED
731: || e.getID() == MouseEvent.MOUSE_RELEASED || e
732: .getID() == MouseEvent.MOUSE_CLICKED) && e
733: .getButton() == button);
734: }
735:
736: }
|