import java.awt.*; import javax.swing.*; /** * The DragLayout is used as a layout manager for a Container that supports * random dragging of components with the Container. * * The location of the component will not be managed by the layout manager. * * The size of the component can be either the preferred size of the component, * or the actual size of the component. * * The preferred size of the container will calculated normally based on the * actual location and size of each component. * * A Component cannot have a location outside the bounds of the parent container. * That is the x/y coordinate must be withing the Insets of the Container. If * any component is outside the bounds, then the location of all components * will be adjusted by the same amount. */ public class DragLayout implements LayoutManager, java.io.Serializable { private boolean usePreferredSize; /** * Convenience constructor */ public DragLayout() { this(true); } /** * Create a DragLayout and indicate how the component size is determined. * * @param usePreferred size see setPreferredSize() for values. */ public DragLayout(boolean usePreferredSize) { setUsePreferredSize( usePreferredSize ); } /** * Set the use preferred size property * * @param usePreferredSize when true, use the preferred size of the component * in layout calculations. When false, use the size * of the component, unless the size is 0, in which * case use the preferred size as a default. */ public void setUsePreferredSize(boolean usePreferredSize) { this.usePreferredSize = usePreferredSize; } /** * Get the use Preferred Size property * *@return the use preferred size property */ public boolean isUsePreferredSize() { return usePreferredSize; } /** * Adds the specified component with the specified name to the layout. * @param name the name of the component * @param comp the component to be added */ @Override public void addLayoutComponent(String name, Component comp) {} /** * Removes the specified component from the layout. * * @param comp the component to be removed */ @Override public void removeLayoutComponent(Component component) { } /** * Determine the minimum size on the Container * * @param target the container in which to do the layout * @return the minimum dimensions needed to lay out the * subcomponents of the specified container */ @Override public Dimension minimumLayoutSize(Container parent) { synchronized (parent.getTreeLock()) { return preferredLayoutSize(parent); } } /** * Determine the preferred size on the Container * * @param parent the container in which to do the layout * @return the preferred dimensions to lay out the * subcomponents of the specified container */ @Override public Dimension preferredLayoutSize(Container parent) { synchronized (parent.getTreeLock()) { return getLayoutSize(parent); } } /* * The calculation for minimum/preferred size is the same. * * @param parent the container in which to do the layout */ private Dimension getLayoutSize(Container parent) { Insets parentInsets = parent.getInsets(); int x = parentInsets.left; int y = parentInsets.top; int width = 0; int height = 0; // Get extreme values of the components on the container. // The x/y values represent the starting point relative to the // top/left of the container. The width/height values represent // the bottom/right value within the container. for (Component component: parent.getComponents()) { if (component.isVisible()) { Point p = component.getLocation(); Dimension d = getActualSize(component); x = Math.min(x, p.x); y = Math.min(y, p.y); width = Math.max(width, p.x + d.width); height = Math.max(height, p.y + d.height); } } // Width/Height is adjusted if any component is outside left/top edge if (x < parentInsets.left) width += parentInsets.left - x; if (y < parentInsets.top) height += parentInsets.top - y; // Adjust for insets width += parentInsets.right; height += parentInsets.bottom; Dimension d = new Dimension(width, height); return d; } private Dimension getActualSize(Component component) { if (usePreferredSize) return component.getPreferredSize(); // Use the preferred size as a default when a size has not been set. Dimension d = component.getSize(); if (d.width == 0 || d.height == 0) return component.getPreferredSize(); else return d; } /** * Lays out the specified container using this layout. * * @param target the container in which to do the layout */ @Override public void layoutContainer(Container parent) { synchronized (parent.getTreeLock()) { Insets parentInsets = parent.getInsets(); int x = parentInsets.left; int y = parentInsets.top; // Get x/y location of any component outside the bounds of the panel. // All components will be adjust by the x/y values, if necessary. for (Component component: parent.getComponents()) { if (component.isVisible()) { Point location = component.getLocation(); x = Math.min(x, location.x); y = Math.min(y, location.y); } } x = (x < parentInsets.left) ? parentInsets.left - x : 0; y = (y < parentInsets.top) ? parentInsets.top - y : 0; // Set bounds of each component for (Component component: parent.getComponents()) { if (component.isVisible()) { Point p = component.getLocation(); Dimension d = getActualSize(component); component.setBounds(p.x + x, p.y + y, d.width, d.height); } } }} /** * Returns the string representation of this column layout's values. * * @return a string representation of this layout */ @Override public String toString() { return "[" + getClass().getName() + "]"; } }