001 /* 002 * Created on Jan 13, 2009 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 005 * the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 010 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 011 * specific language governing permissions and limitations under the License. 012 * 013 * Copyright @2009-2010 the original author or authors. 014 */ 015 package org.fest.swing.core; 016 017 import static javax.swing.SwingUtilities.convertRectangle; 018 import static org.fest.swing.edt.GuiActionRunner.execute; 019 020 import java.awt.Component; 021 import java.awt.Container; 022 import java.awt.Rectangle; 023 024 import javax.swing.JComponent; 025 import javax.swing.JInternalFrame; 026 import javax.swing.JViewport; 027 028 import org.fest.swing.edt.GuiTask; 029 030 /** 031 * Understands utility methods related to scrolling. 032 * 033 * @author Juhos Csaba-Zsolt 034 * 035 * @since 1.2 036 */ 037 public final class Scrolling { 038 039 /** 040 * Scrolls a <code>{@link JComponent}</code> into view within a container. 041 * @param robot simulates user input. 042 * @param c the given component. 043 */ 044 public static void scrollToVisible(Robot robot, JComponent c) { 045 JComponent root = findClosestValidatingRootAncestor(c); 046 // scroll the component to view within each validating root ancestor, starting from the nearest 047 while (root != null) { 048 scrollToVisible(robot, root, c); 049 // find the next validating root 050 root = findClosestValidatingRootAncestor(root); 051 } 052 } 053 054 /** 055 * Returns a component's closest validating root ancestor in the AWT containment hierarchy. 056 * @param c the given component. 057 * @return the found ancestor or <code>null</code> if there isn't one. 058 */ 059 private static JComponent findClosestValidatingRootAncestor(JComponent c) { 060 // the candidate validating root at every iteration (candidate = not necessarily a root) 061 Container root = c; 062 // we go up to the top of the hierarchy 063 while (root != null) { 064 Container parent = root.getParent(); 065 // the new candidate root becomes the parent of the previous one 066 root = parent; 067 // if the candidate isn't a JComponent, we're not interested in it (we need JComponent#scrollRectToVisible) 068 if (!(root instanceof JComponent)) continue; 069 // we don't have to take JFrame into account, it's not a JComponent (ant it's a top-level container anyway) 070 if (root instanceof JViewport || root instanceof JInternalFrame) return (JComponent) root; 071 } 072 return null; 073 } 074 075 /** 076 * Scrolls a component into view within a container. 077 * @param robot simulates user input. 078 * @param container the given container. 079 * @param target the given component. 080 */ 081 private static void scrollToVisible(Robot robot, JComponent container, Component target) { 082 Rectangle r = convertRectangle(target.getParent(), target.getBounds(), container); 083 scrollToVisible(robot, container, r); 084 } 085 086 /** 087 * Scrolls a rectangular region of a component into view. 088 * @param robot simulates user input. 089 * @param c the component. 090 * @param rectangle the rectangular region. 091 */ 092 private static void scrollToVisible(Robot robot, final JComponent c, final Rectangle rectangle) { 093 execute(new GuiTask() { 094 protected void executeInEDT() { 095 c.scrollRectToVisible(rectangle); 096 } 097 }); 098 robot.waitForIdle(); 099 } 100 101 private Scrolling() {} 102 }