
com.globalmentor.swing.text.ViewComponentManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of globalmentor-swing Show documentation
Show all versions of globalmentor-swing Show documentation
GlobalMentor Java Swing library.
The newest version!
/*
* Copyright © 1996-2009 GlobalMentor, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.globalmentor.swing.text;
import java.awt.*;
import java.util.*;
import static java.lang.Math.*;
import static java.util.Collections.*;
import javax.swing.text.*;
import static com.globalmentor.java.Objects.*;
import com.globalmentor.awt.Inset;
/**
* Manages AWT/Swing components for a particular view. Used with a view that contains AWT/Swing components.
*
* Views that use the view manager should:
*
* - call {@link ViewComponentManager#setLocation(Shape)} from within
View.paint()
after calling the view's default version.
* - call {@link ViewComponentManager#setSize(float, float)} from within {@link View#setSize(float, float)} after calling the view's default version.
* - call {@link ViewComponentManager#setShowing(boolean)} as needed.
*
*
*
* If region-based positioning is used, the associated view should implement {@link Inset}.
*
* @author Garret Wilson
* @see Inset
*/
public class ViewComponentManager //TODO finish the class comments with examples of usage
{
/**
* A component position.
* @author Garret Wilson
*/
public interface Position extends Cloneable {
/**
* @return A clone of the position.
* @throws CloneNotSupportedException if the clone operation fails.
*/
public Object clone() throws CloneNotSupportedException;
}
/**
* A region-based location along an axis.
* @author Garret Wilson
*/
public static class AxisLocation {
/** The region along an axis relative to the origin. */
public enum Region {
/** The inset before the center of the content; "left" for left-to-right orientation. */
BEFORE,
/** The center of the content. */
MIDDLE,
/** The inset after the center of the content; "right" for left-to-right orientation. */
AFTER
}
/** The region along the axis relative to the origin. */
private final Region region;
/** @return The region along the axis relative to the origin. */
public Region getRegion() {
return region;
}
/** The alignment along the axis (0.0 to 1.0, inclusive) relative to the origin. */
private final float alignment;
/** @return The alignment along the axis (0.0 to 1.0, inclusive) relative to the origin. */
public float getAlignment() {
return alignment;
}
/**
* Constructs a location along an axis aligned in a region.
* @param region The region along the axis relative to the origin.
* @param alignment The alignment along the axis (0.0 to 1.0, inclusive) relative to the origin.
* @throws IllegalArgumentException if the alignment is less than 0.0 or greater than 1.0.
*/
public AxisLocation(final Region region, final float alignment) {
this.region = region; //save the region
this.alignment = alignment; //save the alignment
if(alignment < 0 || alignment > 1) { //if the alignment is not valid
throw new IllegalArgumentException("Alignment " + alignment + " must be constrained from 0.0 to 1.0, inclusive.");
}
}
/**
* Determines the coordinate along the axis relative to the given origin and span based upon the region and alignment.
* @param spanBefore The span in the near inset.
* @param spanMiddle The span in the middle inset.
* @param spanAfter The span in the far inset.
* @param extent The extent of the object.
* @return The absolute coordinate along the axis.
*/
public float getCoordinate(final float spanBefore, final float spanMiddle, final float spanAfter, final float extent) {
final float origin; //we'll find the origin coordinate along the axis
final float span; //we'll find the span into which the coordinate should be determined
final Region region = getRegion(); //get our region
switch(region) { //see which region is specified horizontally
case BEFORE:
origin = 0;
span = spanBefore;
break;
case MIDDLE:
origin = spanBefore;
span = spanMiddle;
break;
case AFTER:
origin = spanBefore + spanMiddle;
span = spanAfter;
break;
default:
throw new AssertionError("Unknown region " + region);
}
return origin + getAlignment() * (span - extent); //align the object in the span and then compensate for the origin
}
}
/**
* A position based upon a region.
* @author Garret Wilson
*/
public static class RegionPosition implements Position {
/** The region-based location along the X axis. */
private final AxisLocation locationX;
/** @return The region-based location along the X axis. */
public AxisLocation getLocationX() {
return locationX;
}
/** The region-based location along the Y axis. */
private final AxisLocation locationY;
/** @return The region-based location along the X axis. */
public AxisLocation getLocationY() {
return locationY;
}
/**
* Constructs a position aligned in a region.
* @param locationX The region-based location along the X axis.
* @param locationY The region-based location along the Y axis.
*/
public RegionPosition(final AxisLocation locationX, final AxisLocation locationY) {
this.locationX = locationX; //save the region location along the X axis
this.locationY = locationY; //save the region location along the Y axis
}
/**
* @return A clone of the position.
* @throws CloneNotSupportedException if the clone operation fails.
*/
public Object clone() throws CloneNotSupportedException {
return super.clone(); //return a clone of the position
}
}
/**
* A position based upon a location.
* @author Garret Wilson
*/
public static class LocationPosition implements Position {
/** The location coordinates. */
private Point location;
/** @return The location coordinates. */
public Point getLocation() {
return location;
}
/** Whether the component should be centered at its location. */
private final boolean centered;
/** @return Whether the component should be centered at its location. */
public boolean isCentered() {
return centered;
}
/**
* Constructs a position at a location.
* @param location The location coordinates.
* @param centered Whether the component should be centered at its location.
* @throws NullPointerException if the location is null
.
*/
public LocationPosition(final Point location, final boolean centered) {
this.location = checkInstance(location, "Location cannot be null."); //save the location
this.centered = centered; //save the centered specification
}
/**
* @return A clone of the position.
* @throws CloneNotSupportedException if the clone operation fails.
*/
public Object clone() throws CloneNotSupportedException {
final LocationPosition locationPosition = (LocationPosition)super.clone(); //create a clone of the position
locationPosition.location = (Point)location.clone(); //clone the location
return locationPosition; //return the location
}
}
/** The view for which components will be managed. */
private final View view;
/** @return The view for which components will be managed. */
protected View getView() {
return view;
}
/**
* The map of component information, each keyed to a component being managed.
* @see #ComponentInfo
*/
protected final Map componentInfoMap = new HashMap();
/** @return A read-only set of components managed by this object. */
public Set getComponents() {
return unmodifiableSet(componentInfoMap.keySet()); //return a read-only set of components
}
/** @return A read-only collection of component information managed by this object. */
public Collection getComponentInfos() {
return unmodifiableCollection(componentInfoMap.values()); //return a read-only set of component information
}
/**
* Retrieves the component information for a specific component.
* @param component The component for which information should be retrieved.
* @return The managed component's information, null
if there is no information stored for the specified component.
*/
/*TODO del if not needed
protected ComponentInfo getComponentInfo(final Component component)
{
return componentInfoMap.get(component); //get the component information for the component
}
*/
/** The current location of the view. */
protected final Point location = new Point();
/** The unscaled width. */
protected float fullWidth = -1;
/** The unscaled height. */
protected float fullHeight = -1;
/** The current scaled width. */
protected float scaledWidth = -1;
/** The current scaled height. */
protected float scaledHeight = -1;
/** The current ratio of scaled width to full width. */
protected float xMultiplier = 1.0f;
/** The current ratio of scaled height to full height. */
protected float yMultiplier = 1.0f;
/**
* Whether we are currently being shown. Used so that new components can be shown or hidden appropriately when they are first added.
*/
private boolean showing = false;
/** The minimum space needed for components in the left inset. */
private int minimumLeftInset = 0;
/** @return The minimum space needed for components in the left inset. */
public int getMinimumLeftInset() {
return minimumLeftInset;
}
/** The minimum space needed for components in the right inset. */
private int minimumRightInset = 0;
/** @return The minimum space needed for components in the right inset. */
public int getMinimumRightInset() {
return minimumRightInset;
}
/** The minimum space needed for components in the top inset. */
private int minimumTopInset = 0;
/** @return The minimum space needed for components in the top inset. */
public int getMinimumTopInset() {
return minimumTopInset;
}
/** The minimum space needed for components in the bottom inset. */
private int minimumBottomInset = 0;
/** @return The minimum space needed for components in the bottom inset. */
public int getMinimumBottomInset() {
return minimumBottomInset;
}
/**
* Constructor that specifies a view for which components will be managed.
* @param ownerView The view that will contain Java AWT and/or Swing components.
*/
public ViewComponentManager(final View ownerView) {
view = ownerView; //save the view for which components will be managed
}
/**
* Adds a component to be managed. Sets the component's visibility based upon the current showing status.
* @param component The component to be managed.
*/
/*TODO del
public synchronized void add(final Component component)
{
add(new ComponentInfo(component)); //add the component with default component info
}
*/
/**
* Adds a component to be managed, along with its location, which will also be managed. The component location will automatically be scaled when the view size
* changes, provided the manager is notified of the size change.
* @param component The component to be managed.
* @param x The horizontal position of the component, relative to the view.
* @param y The vertical position of the component, relative to the view.
*/
public synchronized void add(final Component component, final int x, final int y) {
add(new ComponentInfo(component, x, y)); //add the component with its component info
}
/**
* Adds a component to be managed, along with its location, which will also be managed. The component location will automatically be scaled when the view size
* changes, provided the manager is notified of the size change.
* @param component The component to be managed.
* @param location The position of the component, relative to the view.
*/
public synchronized void add(final Component component, final Point location) {
add(component, location.x, location.y); //add the component with the location information
}
/**
* Adds a component to be managed, along with its location, which will also be managed. The component is specified as centered or not centered around the
* location. The component location will automatically be scaled when the view size changes, provided the manager is notified of the size change.
* @param component The component to be managed.
* @param location The position of the component, relative to the view.
* @param centered Whether the component should be centered at its location.
*/
public synchronized void add(final Component component, final Point location, final boolean centered) {
add(component, location.x, location.y, centered); //add the component with the location information
}
/**
* Adds a component to be managed, along with its location, which will also be managed. The component is specified as centered or not centered around the
* location. Specifies a location for the component, which will automatically be scaled when the view size changes, provided the manager is notified of the
* size change.
* @param component The component to be managed.
* @param x The horizontal position of the component, relative to the view.
* @param y The vertical position of the component, relative to the view.
* @param centered Whether the component should be centered at its location.
*/
public synchronized void add(final Component component, final int x, final int y, final boolean centered) {
add(new ComponentInfo(component, x, y, centered)); //add the component with its component info
}
/**
* Adds a component to be managed, along with its location and size, which will also be managed. The component location and size will automatically be scaled
* when the view size changes, provided the manager is notified of the size change.
* @param component The component to be managed.
* @param x The horizontal position of the component, relative to the view.
* @param y The vertical position of the component, relative to the view.
* @param width The width of the component, relative to the view width.
* @param height The height of the component, relative to the view width.
*/
public synchronized void add(final Component component, final int x, final int y, final int width, final int height) {
add(new ComponentInfo(component, x, y, width, height)); //add the component with its component info
}
/**
* Adds a component to be managed, along with its location and size, which will also be managed. The component location and size will automatically be scaled
* when the view size changes, provided the manager is notified of the size change.
* @param component The component to be managed.
* @param location The position of the component, relative to the view.
* @param size The size of the component, relative to the view size.
*/
public synchronized void add(final Component component, final Point location, final Dimension size) {
add(component, location.x, location.y, size.width, size.height); //add the component with its location and size information
}
/**
* Adds a component to be managed, along with its location and size, which will also be managed. The component location and size will automatically be scaled
* when the view size changes, provided the manager is notified of the size change.
* @param component The component to be managed.
* @param rectangle The location and size of the component, relative to the view.
*/
public synchronized void add(final Component component, final Rectangle rectangle) {
add(component, rectangle.x, rectangle.y, rectangle.width, rectangle.height); //add the component with its location and size information
}
/**
* Adds a component to be managed, along with its location and size, which will also be managed. The component is specified as centered or not centered around
* the location. The component location and size will automatically be scaled when the view size changes, provided the manager is notified of the size change.
* @param component The component to be managed.
* @param location The position of the component, relative to the view.
* @param size The size of the component, relative to the view size.
* @param centered Whether the component should be centered at its location.
*/
public synchronized void add(final Component component, final Point location, final Dimension size, final boolean centered) {
add(component, location.x, location.y, size.width, size.height, centered); //add the component with its location and size information
}
/**
* Adds a component to be managed, along with its location and size, which will also be managed. The component is specified as centered or not centered around
* the location. The component location and size will automatically be scaled when the view size changes, provided the manager is notified of the size change.
* @param component The component to be managed.
* @param x The horizontal position of the component, relative to the view.
* @param y The vertical position of the component, relative to the view.
* @param width The width of the component, relative to the view width.
* @param height The height of the component, relative to the view width.
* @param centered Whether the component should be centered at its location.
*/
public synchronized void add(final Component component, final int x, final int y, final int width, final int height, final boolean centered) {
add(new ComponentInfo(component, x, y, width, height, centered)); //add the component with its component info
}
/**
* Adds a component to be managed, along with a position.
* @param component The component to be managed.
* @param regionX The region along the X axis relative to the origin.
* @param alignmentX The alignment along the X axis (0.0 to 1.0, inclusive) relative to the origin.
* @param regionY The region along the Y axis relative to the origin.
* @param alignmentY The alignment along the Y axis (0.0 to 1.0, inclusive) relative to the origin.
* @throws IllegalArgumentException if the alignment is less than 0.0 or greater than 1.0.
*/
public synchronized void add(final Component component, final AxisLocation.Region regionX, final float alignmentX, final AxisLocation.Region regionY,
final float alignmentY) {
add(new ComponentInfo(component, regionX, alignmentX, regionY, alignmentY)); //add the component with its position information
}
/**
* Adds a component to be managed, along with its size, which will also be managed. The position is also specified. The component location and size will
* automatically be scaled when the view size changes, provided the manager is notified of the size change.
* @param component The component to be managed.
* @param regionX The region along the X axis relative to the origin.
* @param alignmentX The alignment along the X axis (0.0 to 1.0, inclusive) relative to the origin.
* @param regionY The region along the Y axis relative to the origin.
* @param alignmentY The alignment along the Y axis (.0 to 1.0, inclusive) relative to the origin.
* @param size The size of the component, relative to the view size.
* @throws IllegalArgumentException if the alignment is less than 0.0 or greater than 1.0.
*/
public synchronized void add(final Component component, final AxisLocation.Region regionX, final float alignmentX, final AxisLocation.Region regionY,
final float alignmentY, final Dimension size) {
add(component, regionX, alignmentX, regionY, alignmentY, size.width, size.height); //add the component with its size and border information
}
/**
* Adds a component to be managed, along with its size, which will also be managed. The position is also specified. The component location and size will
* automatically be scaled when the view size changes, provided the manager is notified of the size change.
* @param component The component to be managed.
* @param regionX The region along the X axis relative to the origin.
* @param alignmentX The alignment along the X axis (0.0 to 1.0, inclusive) relative to the origin.
* @param regionY The region along the Y axis relative to the origin.
* @param alignmentY The alignment along the Y axis (0.0 to 1.0, inclusive) relative to the origin.
* @param width The width of the component, relative to the view width.
* @param height The height of the component, relative to the view width.
* @throws IllegalArgumentException if the alignment is less than 0.0 or greater than 1.0.
*/
public synchronized void add(final Component component, final AxisLocation.Region regionX, final float alignmentX, final AxisLocation.Region regionY,
final float alignmentY, final int width, final int height) {
add(new ComponentInfo(component, regionX, alignmentX, regionY, alignmentY, width, height)); //add the component with its component info
}
/**
* Adds a component to be managed, along with its associated component information. Sets the component's visibility based upon the current showing status.
* @param componentInfo The information about the component, which will be managed as well
*/
public synchronized void add(final ComponentInfo componentInfo) {
final Component component = componentInfo.getComponent(); //get the component to be managed
componentInfoMap.put(component, componentInfo); //store the information in the component information map, keyed to the component we're managing
component.setSize(component.getPreferredSize()); //set the component's size to whatever it prefers
component.validate(); //tell the component to validate itself, laying out its child components if needed
updateComponentScaledPosition(componentInfo); //update the component's scaled location and size
setShowing(component, showing); //show or hide the component appropriately
}
/**
* Called when the view is being hidden by a parent that hides views, such as a paged view. All managed components will be hidden.
* @param newShowing true
if the view is beginning to be shown, false
if the view is beginning to be hidden.
*/
public synchronized void setShowing(final boolean newShowing) {
/*TODO del
Log.trace("****setShowing()"); //TODO del
Log.trace("set showing, old: ", new Boolean(showing)); //TODO del
Log.trace("set showing, new: ", new Boolean(newShowing)); //TODO del
Log.traceStack(); //TODO del
*/
showing = newShowing; //update our showing status
for(final Component component : getComponents()) { //for each component
setShowing(component, newShowing); //show or hide this component
}
}
/**
* Sets a component to be showing or not showing appropriately. If the component should be showing, it is set to be visible and is added to the container if
* it isn't added already. If the component should not be showing, it is hidden and removed from the container.
* @param component The component to be shown or hidden.
* @param showing true
if the component should be shown, false
if its should be hidden.
*/
protected void setShowing(final Component component, final boolean showing) {
//TODO del Log.trace("setting component showing: ", new Boolean(showing)); //TODO del
component.setVisible(showing); //show or hide the component appropriately
final Container container = getView().getContainer(); //get the container the view is placed in
if(showing) { //if we're now showing the component
//TODO del Log.trace("showing component"); //TODO del
if(container != null && component.getParent() != container) { //if we have a valid container, and the component isn't already in the container
//TODO del Log.trace("component into container"); //TODO del
//TODO del System.out.println("component size before added to container: "+component.getSize().getWidth()+" height: "+component.getSize().getHeight()); //TODO del
container.add(component); //add the component to the container
//TODO del System.out.println("component size after added to container: "+component.getSize().getWidth()+" height: "+component.getSize().getHeight()); //TODO del
}
} else /*TODO del if(!showing)*///if we're now being hidden (even if we were already hidden, container.remove(component) shouldn't hurt if the component was already removed)
{
//TODO del Log.trace("hiding component"); //TODO del
//TODO testing a way to remove the component from the container
//TODO del Log.trace("Container: ", container); //TODO del
if(container != null && component.getParent() == container) { //if we have a valid container, and the component is in the container
//TODO del Log.trace("removing component from container"); //TODO del
container.remove(component); //remove the component from the container
}
}
}
/**
* Indicates the view size is changing, and modifies the locations of all components appropriately that have registered a location relative to the absolute
* view size. This version sets the full size to match the scaled size.
* @param newScaledWidth The current scaled width (>=0).
* @param newScaledHeight The current scaled height (>=0).
* @see #setSize(float, float, float, float)
*/
public void setSize(final float newScaledWidth, final float newScaledHeight) {
setSize(newScaledWidth, newScaledHeight, newScaledWidth, newScaledHeight); //use the same full and scaled size
}
/**
* Indicates the view size is changing, and modifies the locations of all components appropriately that have registered a location relative to the absolute
* view size. The absolute size of the view must first have been set.
* @param newFullWidth The unscaled width (>=0).
* @param newFullHeight The unscaled height (>=0).
* @param newScaledWidth The current scaled width (>=0).
* @param newScaledHeight The current scaled height (>=0).
* @see #updateComponentScaledPositions()
*/
public void setSize(final float newFullWidth, final float newFullHeight, final float newScaledWidth, final float newScaledHeight) {
if(fullWidth != newFullWidth || fullHeight != newFullHeight || scaledWidth != newScaledWidth || scaledHeight != newScaledHeight) { //if one of the values are changing
fullWidth = newFullWidth; //update the values
fullHeight = newFullHeight;
scaledWidth = newScaledWidth;
scaledHeight = newScaledHeight;
//if we have valid values for everything
if(fullWidth > 0 && fullHeight > 0 && scaledWidth > 0 && scaledHeight > 0) {
xMultiplier = scaledWidth / fullWidth; //calculate the radio of scaled with to full width
yMultiplier = scaledHeight / fullHeight; //calculate the raio of scaled height to full height
updateComponentScaledPositions(); //update all component locations and sizes with the new information
} else { //if we don't have valid values for some of the widths and heights
xMultiplier = 1.0f; //don't scale horizontally
yMultiplier = 1.0f; //don't scale vertically
}
}
}
/**
* Updates the allocation given to the view, which in turn updates the view location. All components the locations of which are managed are updated so that
* their locations are correctly scaled relative to the scaled size of the view. The size of the allocation is ignored. This is a convenience function so that
* paint()
does not have to extract information from the Shape
it receives.
* @param allocation The allocated region the view is to render into.
* @see #setLocation(int, int)
*/
public void setLocation(final Shape allocation) {
//get the bounding rectangle of the allocation
final Rectangle rectangle = (allocation instanceof Rectangle) ? (Rectangle)allocation : allocation.getBounds();
setLocation(rectangle.x, rectangle.y); //tell the component manager our new location, even though we're managing the component
}
/**
* Updates the view location. All components the locations of which are managed are updated so that their locations are correctly scaled relative to the
* scaled size of the view.
* @param x The new horizontal position of the view.
* @param y The new vertical position of the view.
*/
public void setLocation(final int x, final int y) {
if(location.x != x || location.y != y) { //if the location is really changing
location.x = x; //update the position
location.y = y;
updateComponentPositions(); //update the locations and sizes of the components
}
}
/**
* Updates the scaled locations and sizes of all components we're keepting track of, based upon the current view size compared to its unscaled size. The
* absolute locations of the components are also updated.
*/
protected void updateComponentScaledPositions() {
//if we have valid values for everything
if(fullWidth > 0 && fullHeight > 0 && scaledWidth > 0 && scaledHeight > 0) {
for(final ComponentInfo componentInfo : getComponentInfos()) { //for each component information
updateComponentScaledPosition(componentInfo); //update this component's scaled location and size
}
}
}
/**
* Updates the scaled location of given component, if the manager is keeping track of that component's location. The component's absolute location is also
* updated.
* @param componentInfo The component information that contains the scaled location information.
* @see #updateComponentPosition
*/
protected void updateComponentScaledPosition(final ComponentInfo componentInfo) {
final Dimension relativeSize = componentInfo.getSize(); //get the relative size of this component, if we have it
final Dimension actualSize; //we'll determine the current display size, which will be the scaled size or the actual size if there is no scaled size
if(relativeSize != null) { //if we have a preferred size for this component
actualSize = new Dimension(relativeSize); //create a new scaled size based on the preferred location
actualSize.width = Math.round(actualSize.width * xMultiplier); //scale the size horizontally
actualSize.height = Math.round(actualSize.height * yMultiplier); //scale the size vertically
componentInfo.setScaledSize(actualSize); //store the scaled size
} else { //if we don't have a preferred size for the component
actualSize = componentInfo.getComponent().getSize(); //just use the size of the component
}
final Position position = componentInfo.getPosition(); //get the position of the component
if(position instanceof RegionPosition) { //if the position specifies a region
final RegionPosition regionPosition = (RegionPosition)position; //get the position as a region position
final View view = getView(); //get a reference to the view
final Insets insets = view instanceof Inset ? ((Inset)view).getInsets() : new Insets(0, 0, 0, 0); //get the insets of the view, if the view reports its insets
final float x = regionPosition.getLocationX().getCoordinate(insets.left, scaledWidth - insets.left - insets.right, insets.right, actualSize.width); //determine the X coordinate
final float y = regionPosition.getLocationY().getCoordinate(insets.top, scaledHeight - insets.top - insets.bottom, insets.bottom, actualSize.height); //determine the Y coordinate
componentInfo.setScaledLocation(new Point(Math.round(x), Math.round(y))); //store the scaled location
} else if(position instanceof LocationPosition) { //if the position specifies an absolute location
final LocationPosition locationPosition = (LocationPosition)position; //get the position as a location position
final Point location = locationPosition.getLocation(); //get the location position's location
float x = location.x * xMultiplier; //scale the position horizontally
float y = location.y * yMultiplier; //scale the position vertically
if(locationPosition.isCentered()) { //if we should center the component at the location
x -= scaledWidth / 2; //center the component horizontally
y -= scaledHeight / 2; //center the component vertically
}
componentInfo.setScaledLocation(new Point(Math.round(x), Math.round(y))); //store the scaled location
}
updateComponentPosition(componentInfo); //update the component's absolute location and size
}
/**
* Updates the absolute locations of all components we're keepting track of, based upon the current view position and the scaled locations of the components.
*/
protected void updateComponentPositions() {
//if we have valid values for everything
if(fullWidth > 0 && fullHeight > 0 && scaledWidth > 0 && scaledHeight > 0) {
for(final ComponentInfo componentInfo : getComponentInfos()) { //for each component information
updateComponentPosition(componentInfo); //update this component's absolute location
}
}
}
/**
* Updates the absolute location of given component, if the manager is keeping track of that component's location.
* @param componentInfo The component information that contains the scaled location information.
*/
protected void updateComponentPosition(ComponentInfo componentInfo) {
final Component component = componentInfo.getComponent(); //get the component being managed
final Point scaledLocation = componentInfo.getScaledLocation(); //get the scaled location of this component, if we have it
if(scaledLocation != null) { //if we have a scaled location for this component
if(location.x >= 0 && location.y >= 0) { //if we have a valid view position
int x = location.x + scaledLocation.x; //offset the component from the horizontal view origin
int y = location.y + scaledLocation.y; //offset the component from the vertial view origin
/*TODO del when works
if(componentInfo.isCentered()) { //if we should center the component at the location
x-=component.getWidth()/2; //center the component horizontally
y-=component.getHeight()/2; //center the component vertically
}
*/
component.setLocation(x, y); //update the component's absolute location to be its scaled location relative to the location of the view, centered if necessary
final Dimension scaledSize = componentInfo.getScaledSize(); //get the scaled size of this component, if we have it
if(scaledSize != null) { //if we have a scaled size for this component
component.setSize(scaledSize); //update the component's size (sizes are absolute, and do not have to be offset from the view origin)
}
component.validate(); //tell the component to validate itself, laying out its child components if needed
/*TODO del; sizes are relative, and don't need to be updated relative to the view origin
final Dimension scaledSize=componentInfo.getScaledSize(); //get the scaled size of this component, if we have it
if(scaledSize!=null) { //if we have a scaled size for this component
int width=location.x+scaledLocation.x; //offset the component from the horizontal view origin
int y=location.y+scaledLocation.y; //offset the component from the vertial view origin
if(componentInfo.isCentered()) { //if we should center the component
x-=component.getWidth()/2; //center the component horizontally
y-=component.getHeight()/2; //center the component vertically
}
component.setLocation(x, y); //update the component's absolute location to be its scaled location relative to the location of the view, centered if necessary
*/
}
}
updateMinimumInsets(); //update all the inset calculations, now that a component has changed its position and/or size
}
/**
* Updates the minimum insets based upon the current positions of all components. The component positions of interest are primarily those with region-based
* positioning that are either in BEFORE
or AFTER
positions. The component's current actual size is used for calculating minimum
* insets, which means it is assumed that updateComponentPosition()
has already been called.
*/
protected void updateMinimumInsets() {
minimumLeftInset = minimumRightInset = minimumTopInset = minimumBottomInset = 0; //reset the insets to zero
for(final ComponentInfo componentInfo : getComponentInfos()) { //for each component information
final Dimension componentSize = componentInfo.getComponent().getSize(); //get the size of the component
final Position position = componentInfo.getPosition(); //get the position of the component
if(position instanceof RegionPosition) { //if the position specifies a region
final RegionPosition regionPosition = (RegionPosition)position; //get the position as a region position TODO compensate for orientation for all the following updates
switch(regionPosition.getLocationX().getRegion()) { //check the horizontal region
case BEFORE:
minimumLeftInset = max(minimumLeftInset, componentSize.width); //update the minimum left inset
break;
case AFTER:
minimumRightInset = max(minimumRightInset, componentSize.width); //update the minimum right inset
break;
}
switch(regionPosition.getLocationY().getRegion()) { //check the vertical region
case BEFORE:
minimumTopInset = max(minimumTopInset, componentSize.height); //update the minimum top inset
break;
case AFTER:
minimumBottomInset = max(minimumBottomInset, componentSize.height); //update the minimum bottom inset
break;
}
}
}
}
/** The class which encapsulates information about a component being managed. */
public static class ComponentInfo implements Cloneable {
/** The component being managed. */
private final Component component;
/** @return The component being managed. */
public Component getComponent() {
return component;
}
/** The position of the component. */
private Position position;
/** @return The position of the component. */
public Position getPosition() {
return position;
}
/**
* The scaled location of the component relative to the scaled size of the view, or null
if the scaled location isn't available.
*/
private Point scaledLocation = null;
/**
* @return The scaled location of the component relative to the scaled size of the view, or null
if the scaled location isn't available.
*/
public Point getScaledLocation() {
return scaledLocation;
}
/**
* Sets the scaled location of the component.
* @param newScaledLocation The new scaled location of the component relative to the scaled size of the view, or null
if the scaled location
* isn't available.
*/
protected void setScaledLocation(final Point newScaledLocation) {
scaledLocation = newScaledLocation;
}
/**
* The preferred size of the component relative to the original size of the view, or null
if the size isn't available.
*/
private Dimension size = null;
/**
* @return The preferred size of the component relative to the original size of the view, or null
if the size isn't available.
*/
public Dimension getSize() {
return size;
}
/**
* The scaled size of the component relative to the scaled size of the view, or null
if the scaled size isn't available.
*/
private Dimension scaledSize = null;
/**
* @return The scaled size of the component relative to the scaled size of the view, or null
if the scaled size isn't available.
*/
public Dimension getScaledSize() {
return scaledSize;
}
/**
* Sets the scaled size of the component.
* @param newScaledSize The new scaled size of the component relative to the scaled size of the view, or null
if the scaled size isn't
* available.
*/
protected void setScaledSize(final Dimension newScaledSize) {
scaledSize = newScaledSize;
}
/**
* Component constructor.
* @param component The component being managed.
*/
/*TODO del
public ComponentInfo(final Component component)
{
this.component=component; //save the component
border=null; //show that there is no border specified
centered=false; //show that the component is not centered
}
*/
/**
* Position constructor.
* @param component The component being managed.
* @param x The horizontal position of the component, relative to the view.
* @param y The vertical position of the component, relative to the view.
*/
public ComponentInfo(final Component component, final int x, final int y) {
this(component, x, y, false); //do the default constructing, not centering the component
}
/**
* Position constructor that accepts whether the component wants to be centered.
* @param component The component being managed.
* @param x The horizontal position of the component, relative to the view.
* @param y The vertical position of the component, relative to the view.
* @param newCentered Whether the component should be centered at its location.
*/
public ComponentInfo(final Component component, final int x, final int y, final boolean newCentered) {
this.component = component; //save the component
position = new LocationPosition(new Point(x, y), newCentered); //store the component's preferred location
}
/**
* Position and size constructor that accepts whether the component wants to be centered.
* @param component The component being managed.
* @param x The horizontal position of the component, relative to the view.
* @param y The vertical position of the component, relative to the view.
* @param width The width of the component, relative to the view width.
* @param height The height of the component, relative to the view width.
* @param newCentered Whether the component should be centered at its location.
*/
public ComponentInfo(final Component component, final int x, final int y, final int width, final int height, final boolean newCentered) {
this(component, x, y, newCentered); //do the default location construction
size = new Dimension(width, height); //store the component's preferred size
}
/**
* Position and size constructor.
* @param component The component being managed.
* @param x The horizontal position of the component, relative to the view.
* @param y The vertical position of the component, relative to the view.
* @param width The width of the component, relative to the view width.
* @param height The height of the component, relative to the view width.
*/
public ComponentInfo(final Component component, final int x, final int y, final int width, final int height) {
this(component, x, y, width, height, false); //do the default construction, not centering the component
}
/**
* Position constructor that accepts a border position.
* @param component The component being managed.
* @param regionX The region along the X axis relative to the origin.
* @param alignmentX The alignment along the X axis (0.0 to 1.0, inclusive) relative to the origin.
* @param regionY The region along the Y axis relative to the origin.
* @param alignmentY The alignment along the Y axis (0.0 to 1.0, inclusive) relative to the origin.
* @throws IllegalArgumentException if the alignment is less than 0.0 or greater than 1.0.
*/
public ComponentInfo(final Component component, final AxisLocation.Region regionX, final float alignmentX, final AxisLocation.Region regionY,
final float alignmentY) {
this.component = component; //save the component
position = new RegionPosition(new AxisLocation(regionX, alignmentX), new AxisLocation(regionY, alignmentY)); //create a position based upon the region
}
/**
* Size constructor with optional border specification.
* @param component The component being managed.
* @param regionX The region along the X axis relative to the origin.
* @param alignmentX The alignment along the X axis (0.0 to 1.0, inclusive) relative to the origin.
* @param regionY The region along the Y axis relative to the origin.
* @param alignmentY The alignment along the Y axis (0.0 to 1.0, inclusive) relative to the origin.
* @param width The width of the component, relative to the view width.
* @param height The height of the component, relative to the view width.
* @throws IllegalArgumentException if the alignment is less than 0.0 or greater than 1.0.
*/
public ComponentInfo(final Component component, final AxisLocation.Region regionX, final float alignmentX, final AxisLocation.Region regionY,
final float alignmentY, final int width, final int height) {
this(component, regionX, alignmentX, regionY, alignmentY); //do the default construction
size = new Dimension(width, height); //store the component's preferred size
}
/**
* @return A deep clone of the component info, while keeping a reference to the same component.
* @throws CloneNotSupportedException if the clone operation fails.
*/
public Object clone() throws CloneNotSupportedException {
final ComponentInfo componentInfo = (ComponentInfo)super.clone(); //create a clone of the component info
componentInfo.position = (Position)position.clone(); //clone the position
if(componentInfo.scaledLocation != null) { //if there is a scaled location associated with this component
componentInfo.scaledLocation = (Point)scaledLocation.clone(); //clone the scaled location
}
if(componentInfo.size != null) { //if there is a size associated with this component
componentInfo.size = (Dimension)size.clone(); //clone the size
}
if(componentInfo.scaledSize != null) { //if there is a scaled size associated with this component
componentInfo.scaledSize = (Dimension)scaledSize.clone(); //clone the scaled size
}
return componentInfo; //return the cloned component information
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy