alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 *//*
 * AutoGridLayout.java
 *
 * Created on 04 October 2003, 16:01
 */

package org.openide.explorer.propertysheet;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Toolkit;
import java.util.Arrays;
import java.util.Comparator;

/**A layout manager which can layout like-heighted components in a grid
 * pattern based on their preferred sizes.  Can be used in packed or unpacked
 * mode.  Column positions are based on the preferred sizes of the first row
 * of components.

* When packed, the components are sorted from narrowest to widest; * subsequent rows will use these columns, with components two wide for a * single column spanning two or more columns.

* When not packed, the components are sorted from widest to narrowest, * resulting in more whitespace, but consistent rows of columns - no * component will span more than one column.

* Used by RadioInplaceEditor to manage the set of radio * buttons representing property editor tags. * * @author Tim Boudreau */ class AutoGridLayout implements LayoutManager { int gapY = 5; boolean pack; public AutoGridLayout(boolean pack) { this.pack = pack; } public void addLayoutComponent(String name, Component comp) { //Do nothing } public void removeLayoutComponent(Component comp) { //Do nothing } private Comparator comparator() { return new PreferredSizeComparator(pack); } public void layoutContainer(Container parent) { Component[] c = parent.getComponents(); if (c.length > 3) { Arrays.sort(c, comparator()); } if (c.length == 2) { //we're probably a radio button editor in the property sheet - //make sure that both buttons are displayed, even if some clipping //would occur - we don't have another row to go to Dimension d0 = c[0].getPreferredSize(); Dimension d1 = c[1].getPreferredSize(); c[0].setBounds(0,0,d0.width, d0.height); c[1].setBounds(d0.width, 0, d1.width, d1.height); return; } Insets insets = parent.getInsets(); int w = parent.getWidth() - insets.right; int h = parent.getHeight() - insets.bottom; int currx=insets.left; int curry=insets.top; boolean done=false; int cols = -1; //Layout the first row of components according to their preferred //sizes. Their positions will act as column positions. If sorted //narrowest-first, results in a smaller, packedAutoGridLayout. If sorted //widest-first, results in nice consistent columns, but uses more //space to do it. for (int i=0; i < c.length; i++) { Dimension d = c[i].getPreferredSize(); if (d.width == 0 || d.height == 0) { //Can happen for foreign components that can't do //a proper preferred size w/o a graphics context d = PropUtils.getMinimumPanelSize(); } if (currx + d.width > w) { curry+= d.height +gapY; currx = insets.left; if (cols == -1) { cols = i; break; } } c[i].setBounds(currx, curry, d.width, d.height); currx+= d.width; } if (cols == -1) { cols = c.length; } int currCol=0; for (int i=cols; i < c.length; i++) { Dimension d = c[i].getPreferredSize(); if (currx + d.width > w) { //will only happen with inverse sort - we're starting //the loop with a position that won't fit, and should flip //to the next line curry += d.height + gapY; currx = insets.left; currCol=0; } //see if we're out of horizontal space and should punt done = curry + d.height > h; if (!done) { //fetch the width of this column, as the width of the first row component int currColWidth = c[currCol].getWidth(); //will we fit at all? if (d.width <= w) { int colspan = 1; //loop until we know how many columns we need while (currColWidth <= d.width) { currCol++; if (currCol > cols) { //out of columns? Flip to the next line currCol = 0; curry += d.height + gapY; currx = insets.left; currColWidth = 0; colspan = 1; } //note the combined column width - it will be the //next iteration's starting x position currColWidth += c[currCol].getWidth(); colspan++; } c[i].setBounds(currx, curry, d.width, d.height); currx += currColWidth; } else { //Okay, we've got a component wider than its parent - give up c[i].setBounds(currx, curry, d.width, d.height); currx+= d.width; //just clip it if it's wider than max } if (currx > w) { //see if we should flip to the next row or if there may //still be space currx = insets.left; curry += d.height + gapY; currCol=0; } else { currCol++; } } else { //If we get here, we've run out of horizontal space - no //point in trying to do something reasonable with the component c[i].setBounds(0,0,0,0); } } } public Dimension minimumLayoutSize(java.awt.Container parent) { return preferredLayoutSize(parent); } public Dimension preferredLayoutSize(java.awt.Container parent) { Component[] c = parent.getComponents(); if (c.length > 3) { Arrays.sort(c, comparator()); } Dimension max = Toolkit.getDefaultToolkit().getScreenSize(); max.width /= 2; max.height /=2; Insets insets = parent.getInsets(); int w = max.width - insets.right; int currx = insets.left; int cols = -1; int baseHeight=0; Dimension[] dims = new Dimension[c.length]; Dimension result = new Dimension(); //establish the base columns and populate the dimensions array for (int i=0; i < c.length; i++) { dims[i] = c[i].getPreferredSize(); if (dims[i].width == 0 || dims[i].height == 0) { //Can happen for foreign components that can't do //a proper preferred size w/o a graphics context dims[i] = PropUtils.getMinimumPanelSize(); } baseHeight = Math.max (baseHeight, dims[i].height); if (cols == -1) { if (currx + dims[i].width > w) { result.width = currx; cols = i; } } if (cols != -1) { //Make sure we don't have one element wider than all the //column sizes result.width = Math.max (result.width, dims[i].width + insets.left + insets.right); } currx += dims[i].width; } if (cols == -1) { //we didn't overstretch the available width cols = c.length; result.width = currx; } if (!pack && c.length > 3) { //Then we can take a short cust - we know all will be 1 item per cell int rows = (c.length / cols) + (c.length % cols != 0 ? 1 : 0); result.height = (baseHeight * rows) + (gapY * rows) + insets.top + insets.bottom; result.width += 6; assert result.width >= 0 && result.height >= 0; return result; } int currRow = 0; int currCol=0; currx = insets.left; //iterate the rest of the array, incrementing the row index //when the content won't fit, to find out the total rows needed for (int i=cols; i < c.length; i++) { int colspan = 1; int colwidth = dims[currCol].width; while (dims[i].width > colwidth) { currCol++; colwidth += dims[currCol].width; colspan++; if (colwidth + currx > max.width) { currCol=0; currRow++; colspan=1; colwidth = dims[currCol].width; } } currCol += colspan; currx += colwidth; if (currCol > cols && i != c.length-1) { currCol = 0; currRow++; currx = insets.left; } } result.height = (baseHeight * currRow) + insets.top + insets.bottom + (gapY * currRow); return result; } private static final class PreferredSizeComparator implements Comparator { boolean smallFirst; public PreferredSizeComparator(boolean smallFirst) { this.smallFirst = smallFirst; } public int compare(Object o1, Object o2) { Component c1 = (Component) o1; Component c2 = (Component) o2; Dimension d1 = c1.getPreferredSize(); Dimension d2 = c2.getPreferredSize(); return smallFirst ? d1.width - d2.width : d2.width - d1.width; } } }

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.