Widening.

git-svn-id: https://samskivert.googlecode.com/svn/trunk@2507 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
samskivert
2008-12-18 01:29:32 +00:00
parent c1f89f9227
commit b7e85472f4
+101 -151
View File
@@ -70,6 +70,33 @@ import com.samskivert.util.SortableArrayList;
*/
public class SwingUtil
{
/**
* An operation that may be applied to a component.
*/
public static interface ComponentOp
{
/** Apply an operation to the given component. */
public void apply (Component comp);
}
/**
* An interface for validating the text contained within a document.
*/
public static interface DocumentValidator
{
/** Return false if the text is not valid for any reason. */
public boolean isValid (String text);
}
/**
* An interface for transforming the text contained within a document.
*/
public static interface DocumentTransformer
{
/** Transform the specified text in some way, or simply return the text untransformed. */
public String transform (String text);
}
/**
* Center the given window within the screen boundaries.
*
@@ -98,13 +125,12 @@ public class SwingUtil
public static void centerComponent (Component a, Component b)
{
Dimension asize = a.getSize(), bsize = b.getSize();
b.setLocation((asize.width - bsize.width) / 2,
(asize.height - bsize.height) / 2);
b.setLocation((asize.width - bsize.width) / 2, (asize.height - bsize.height) / 2);
}
/**
* Draw a string centered within a rectangle. The string is drawn
* using the graphics context's current font and color.
* Draw a string centered within a rectangle. The string is drawn using the graphics context's
* current font and color.
*
* @param g the graphics context.
* @param str the string.
@@ -123,41 +149,35 @@ public class SwingUtil
}
/**
* Returns the most reasonable position for the specified rectangle to
* be placed at so as to maximize its containment by the specified
* bounding rectangle while still placing it as near its original
* coordinates as possible.
* Returns the most reasonable position for the specified rectangle to be placed at so as to
* maximize its containment by the specified bounding rectangle while still placing it as near
* its original coordinates as possible.
*
* @param rect the rectangle to be positioned.
* @param bounds the containing rectangle.
*/
public static Point fitRectInRect (
Rectangle rect, Rectangle bounds)
public static Point fitRectInRect (Rectangle rect, Rectangle bounds)
{
// Guarantee that the right and bottom edges will be contained
// and do our best for the top and left edges.
return new Point(
Math.min(bounds.x + bounds.width - rect.width,
// Guarantee that the right and bottom edges will be contained and do our best for the top
// and left edges.
return new Point(Math.min(bounds.x + bounds.width - rect.width,
Math.max(rect.x, bounds.x)),
Math.min(bounds.y + bounds.height - rect.height,
Math.max(rect.y, bounds.y)));
}
/**
* Position the specified rectangle as closely as possible to
* its current position, but make sure it is within the specified
* bounds and that it does not overlap any of the Shapes contained
* in the avoid list.
* Position the specified rectangle as closely as possible to its current position, but make
* sure it is within the specified bounds and that it does not overlap any of the Shapes
* contained in the avoid list.
*
* @param r the rectangle to attempt to position.
* @param bounds the bounding box within which the rectangle must be
* positioned.
* @param avoidShapes a collection of Shapes that must not be overlapped.
* The collection will be destructively modified.
* @param bounds the bounding box within which the rectangle must be positioned.
* @param avoidShapes a collection of Shapes that must not be overlapped. The collection will
* be destructively modified.
*
* @return true if the rectangle was successfully placed, given the
* constraints, or false if the positioning failed (the rectangle will
* be left at it's original location.
* @return true if the rectangle was successfully placed, given the constraints, or false if
* the positioning failed (the rectangle will be left at it's original location.
*/
public static boolean positionRect (
Rectangle r, Rectangle bounds, Collection<? extends Shape> avoidShapes)
@@ -165,8 +185,7 @@ public class SwingUtil
Point origPos = r.getLocation();
Comparator<Point> comp = createPointComparator(origPos);
SortableArrayList<Point> possibles = new SortableArrayList<Point>();
// we start things off with the passed-in point (adjusted to
// be inside the bounds, if needed)
// start things off with the passed-in point (adjusted to be inside the bounds, if needed)
possibles.add(fitRectInRect(r, bounds));
// keep track of area that doesn't generate new possibles
@@ -184,7 +203,6 @@ public class SwingUtil
// see if it hits any shapes we're trying to avoid
for (Iterator<? extends Shape> iter = avoidShapes.iterator(); iter.hasNext(); ) {
Shape shape = iter.next();
if (shape.intersects(r)) {
// remove that shape from our avoid list
iter.remove();
@@ -193,7 +211,6 @@ public class SwingUtil
// add 4 new possible points, each pushed in one direction
Rectangle pusher = shape.getBounds();
possibles.add(new Point(pusher.x - r.width, r.y));
possibles.add(new Point(r.x, pusher.y - r.height));
possibles.add(new Point(pusher.x + pusher.width, r.y));
@@ -215,17 +232,14 @@ public class SwingUtil
}
/**
* Create a comparator that compares against the distance from
* the specified point.
* Create a comparator that compares against the distance from the specified point.
*
* Note: The comparator will continue to sort by distance from the origin
* point, even if the origin point's coordinates are modified after
* the comparator is created.
* Note: The comparator will continue to sort by distance from the origin point, even if the
* origin point's coordinates are modified after the comparator is created.
*
* Used by positionRect().
*/
public static <P extends Point2D> Comparator<P> createPointComparator (
final P origin)
public static <P extends Point2D> Comparator<P> createPointComparator (final P origin)
{
return new Comparator<P>() {
public int compare (P p1, P p2)
@@ -238,11 +252,10 @@ public class SwingUtil
}
/**
* Enables (or disables) the specified component, <em>and all of its
* children.</cite> A simple call to {@link Container#setEnabled}
* does not propagate the enabled state to the children of a
* component, which is senseless in our opinion, but was surely done
* for some arguably good reason.
* Enables (or disables) the specified component, <em>and all of its children.</em> A simple
* call to {@link Container#setEnabled} does not propagate the enabled state to the children of
* a component, which is senseless in our opinion, but was surely done for some arguably good
* reason.
*/
public static void setEnabled (Container comp, final boolean enabled)
{
@@ -254,8 +267,7 @@ public class SwingUtil
}
/**
* Set the opacity on the specified component, <em>and all of its
* children.</cite>
* Set the opacity on the specified component, <em>and all of its children.</em>
*/
public static void setOpaque (JComponent comp, final boolean opaque)
{
@@ -269,8 +281,7 @@ public class SwingUtil
}
/**
* Apply the specified ComponentOp to the supplied component
* and then all its descendants.
* Apply the specified ComponentOp to the supplied component and then all its descendants.
*/
public static void applyToHierarchy (Component comp, ComponentOp op)
{
@@ -278,11 +289,10 @@ public class SwingUtil
}
/**
* Apply the specified ComponentOp to the supplied component
* and then all its descendants, up to the specified maximum depth.
* Apply the specified ComponentOp to the supplied component and then all its descendants, up
* to the specified maximum depth.
*/
public static void applyToHierarchy (
Component comp, int depth, ComponentOp op)
public static void applyToHierarchy (Component comp, int depth, ComponentOp op)
{
if (comp == null) {
return;
@@ -299,78 +309,36 @@ public class SwingUtil
}
/**
* An operation that may be applied to a component.
*/
public static interface ComponentOp
{
/**
* Apply an operation to the given component.
*/
public void apply (Component comp);
}
/**
* An interface for validating the text contained within a document.
*/
public static interface DocumentValidator
{
/**
* Should return false if the text is not valid for any reason.
*/
public boolean isValid (String text);
}
/**
* An interface for transforming the text contained within a document.
*/
public static interface DocumentTransformer
{
/**
* Should transform the specified text in some way, or simply
* return the text untransformed.
*/
public String transform (String text);
}
/**
* Set active Document helpers on the specified text component.
* Changes will not and cannot be made (either via user inputs or
* direct method manipulation) unless the validator says that the
* changes are ok.
* Set active Document helpers on the specified text component. Changes will not and cannot be
* made (either via user inputs or direct method manipulation) unless the validator says that
* the changes are ok.
*
* @param validator if non-null, all changes are sent to this for approval.
* @param transformer if non-null, is queried to change the text
* after all changes are made.
* @param transformer if non-null, is queried to change the text after all changes are made.
*/
public static void setDocumentHelpers (
JTextComponent comp, DocumentValidator validator,
public static void setDocumentHelpers (JTextComponent comp, DocumentValidator validator,
DocumentTransformer transformer)
{
setDocumentHelpers(comp.getDocument(), validator, transformer);
}
/**
* Set active Document helpers on the specified Document.
* Changes will not and cannot be made (either via user inputs or
* direct method manipulation) unless the validator says that the
* Set active Document helpers on the specified Document. Changes will not and cannot be made
* (either via user inputs or direct method manipulation) unless the validator says that the
* changes are ok.
*
* @param validator if non-null, all changes are sent to this for approval.
* @param transformer if non-null, is queried to change the text
* after all changes are made.
* @param transformer if non-null, is queried to change the text after all changes are made.
*/
public static void setDocumentHelpers (
final Document doc, final DocumentValidator validator,
public static void setDocumentHelpers (final Document doc, final DocumentValidator validator,
final DocumentTransformer transformer)
{
if (!(doc instanceof AbstractDocument)) {
throw new IllegalArgumentException(
"Specified document cannot be filtered!");
throw new IllegalArgumentException("Specified document cannot be filtered!");
}
// set up the filter.
((AbstractDocument) doc).setDocumentFilter(new DocumentFilter()
{
((AbstractDocument) doc).setDocumentFilter(new DocumentFilter() {
@Override public void remove (FilterBypass fb, int offset, int length)
throws BadLocationException
{
@@ -391,8 +359,7 @@ public class SwingUtil
}
@Override public void replace (
FilterBypass fb, int offset, int length, String text,
AttributeSet attrs)
FilterBypass fb, int offset, int length, String text, AttributeSet attrs)
throws BadLocationException
{
if (replaceOk(offset, length, text)) {
@@ -402,8 +369,7 @@ public class SwingUtil
}
/**
* Convenience for remove/insert/replace to see if the
* proposed change is valid.
* Convenience for remove/insert/replace to see if the proposed change is valid.
*/
protected boolean replaceOk (int offset, int length, String text)
throws BadLocationException
@@ -415,19 +381,17 @@ public class SwingUtil
String current = doc.getText(0, doc.getLength());
String potential = current.substring(0, offset) +
text + current.substring(offset + length);
// validate the potential text.
return validator.isValid(potential);
} catch (IndexOutOfBoundsException ioobe) {
throw new BadLocationException(
"Bad Location", offset + length);
throw new BadLocationException("Bad Location", offset + length);
}
}
/**
* After a remove/insert/replace has taken place, we may
* want to transform the text in some way.
* After a remove/insert/replace has taken place, we may want to transform the text in
* some way.
*/
protected void transform (FilterBypass fb)
{
@@ -476,8 +440,7 @@ public class SwingUtil
}
/**
* Adjusts the widths and heights of the cells of the supplied table
* to fit their contents.
* Adjusts the widths and heights of the cells of the supplied table to fit their contents.
*/
public static void sizeToContents (JTable table)
{
@@ -491,9 +454,8 @@ public class SwingUtil
int headerWidth = 0, cellWidth = 0;
column = table.getColumnModel().getColumn(cc);
try {
comp = column.getHeaderRenderer().
getTableCellRendererComponent(null, column.getHeaderValue(),
false, false, 0, 0);
comp = column.getHeaderRenderer().getTableCellRendererComponent(
null, column.getHeaderValue(), false, false, 0, 0);
headerWidth = comp.getPreferredSize().width;
} catch (NullPointerException e) {
// getHeaderRenderer() this doesn't work in 1.3
@@ -502,8 +464,7 @@ public class SwingUtil
for (int rr = 0; rr < rcount; rr++) {
Object cellValue = model.getValueAt(rr, cc);
comp = table.getDefaultRenderer(model.getColumnClass(cc)).
getTableCellRendererComponent(table, cellValue,
false, false, 0, cc);
getTableCellRendererComponent(table, cellValue, false, false, 0, cc);
Dimension psize = comp.getPreferredSize();
cellWidth = Math.max(psize.width, cellWidth);
cellHeight = Math.max(psize.height, cellHeight);
@@ -517,11 +478,10 @@ public class SwingUtil
}
/**
* Refreshes the supplied {@link JComponent} to effect a call to
* {@link JComponent#revalidate} and {@link JComponent#repaint}, which
* is frequently necessary in cases such as adding components to or
* removing components from a {@link JPanel} since Swing doesn't
* automatically invalidate things for proper re-rendering.
* Refreshes the supplied {@link JComponent} to effect a call to {@link JComponent#revalidate}
* and {@link JComponent#repaint}, which is frequently necessary in cases such as adding
* components to or removing components from a {@link JPanel} since Swing doesn't automatically
* invalidate things for proper re-rendering.
*/
public static void refresh (JComponent c)
{
@@ -530,8 +490,8 @@ public class SwingUtil
}
/**
* Create a custom cursor out of the specified image, putting the hotspot
* in the exact center of the created cursor.
* Create a custom cursor out of the specified image, putting the hotspot in the exact center
* of the created cursor.
*/
public static Cursor createImageCursor (Image img)
{
@@ -539,8 +499,7 @@ public class SwingUtil
}
/**
* Create a custom cursor out of the specified image, with the specified
* hotspot.
* Create a custom cursor out of the specified image, with the specified hotspot.
*/
public static Cursor createImageCursor (Image img, Point hotspot)
{
@@ -555,8 +514,7 @@ public class SwingUtil
// ", bestSize=" + d.width + "x" + d.height +
// ", maxcolors=" + colors + "].");
// if the passed-in image is smaller, pad it with transparent pixels
// and use it anyway.
// if the passed-in image is smaller, pad it with transparent pixels and use it anyway.
if (((w < d.width) && (h <= d.height)) ||
((w <= d.width) && (h < d.height))) {
Image padder = GraphicsEnvironment.getLocalGraphicsEnvironment().
@@ -587,8 +545,8 @@ public class SwingUtil
}
/**
* Adds a one pixel border of random color to this and all panels
* contained in this panel's child hierarchy.
* Adds a one pixel border of random color to this and all panels contained in this panel's
* child hierarchy.
*/
public static void addDebugBorders (JPanel panel)
{
@@ -606,15 +564,14 @@ public class SwingUtil
}
/**
* Aligns the first <code>rows</code> * <code>cols</code> components
* of <code>parent</code> in a grid. Each component in a column is as
* wide as the maximum preferred width of the components in that
* column; height is similarly determined for each row. The parent is
* made just big enough to fit them all. The components should be
* already added to the parent in row-major order.
* Aligns the first <code>rows</code> * <code>cols</code> components of <code>parent</code> in
* a grid. Each component in a column is as wide as the maximum preferred width of the
* components in that column; height is similarly determined for each row. The parent is made
* just big enough to fit them all. The components should be already added to the parent in
* row-major order.
*
* @param parent the container component; must be configured with a
* {@link SpringLayout} prior to calling this method.
* @param parent the container component; must be configured with a {@link SpringLayout} prior
* to calling this method.
* @param rows number of rows.
* @param cols number of columns.
* @param initialX x location at which to start the grid.
@@ -622,8 +579,7 @@ public class SwingUtil
* @param xPad x padding between cells.
* @param yPad y padding between cells.
*/
public static void makeCompactGrid (
Container parent, int rows, int cols,
public static void makeCompactGrid (Container parent, int rows, int cols,
int initialX, int initialY, int xPad, int yPad)
{
SpringLayout layout = (SpringLayout)parent.getLayout();
@@ -633,13 +589,10 @@ public class SwingUtil
for (int c = 0; c < cols; c++) {
Spring width = Spring.constant(0);
for (int r = 0; r < rows; r++) {
width = Spring.max(
width, getConstraintsForCell(
r, c, parent, cols).getWidth());
width = Spring.max(width, getConstraintsForCell(r, c, parent, cols).getWidth());
}
for (int r = 0; r < rows; r++) {
SpringLayout.Constraints constraints =
getConstraintsForCell(r, c, parent, cols);
SpringLayout.Constraints constraints = getConstraintsForCell(r, c, parent, cols);
constraints.setX(x);
constraints.setWidth(width);
}
@@ -651,13 +604,10 @@ public class SwingUtil
for (int r = 0; r < rows; r++) {
Spring height = Spring.constant(0);
for (int c = 0; c < cols; c++) {
height = Spring.max(
height, getConstraintsForCell(
r, c, parent, cols).getHeight());
height = Spring.max(height, getConstraintsForCell(r, c, parent, cols).getHeight());
}
for (int c = 0; c < cols; c++) {
SpringLayout.Constraints constraints =
getConstraintsForCell(r, c, parent, cols);
SpringLayout.Constraints constraints = getConstraintsForCell(r, c, parent, cols);
constraints.setY(y);
constraints.setHeight(height);
}