org.nuiton.widget.GridFlowLayout Maven / Gradle / Ivy
Show all versions of nuiton-widgets Show documentation
/* *##% Graphical Widget
* Copyright (C) 2004 - 2008 CodeLutin
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* . ##%*
/* *
* GridFlowLayout.java
*
* Created: Wed May 8 2002
*
* @author POUSSIN Benjamin
* Copyright Code Lutin
* @version $Revision: 184 $
*
* Mise a jour: $Date: 2009-05-16 06:01:36 +0200 (sam., 16 mai 2009) $
* par : $Author: tchemit $
*/
package org.nuiton.widget;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager2;
import java.util.HashMap;
import java.util.HashSet;
import javax.swing.JViewport;
/**
* Ce layout place les composants de gauche à droite ou de droite à gauche selon
* la valeur de {@link java.awt.Component#getComponentOrientation}. Si un
* composant n'a pas assez de place pour se mettre sur la ligne courant, il est
* mis sur la ligne suivante et les composants sont redimensionnés pour prendre
* le maximum de place disponible sur la ligne. Si le container est dans un
* {@link javax.swing.JViewport} (ou {@link javax.swing.JScrollPane}), ce layout
* essai de ne jamais faire apparaitre le ScrollBar horizontal.
*
*
* Tous les composants ont la même taille.
*/
public class GridFlowLayout implements LayoutManager2 { // GridFlowLayout
protected java.util.Map positions = new HashMap();
int hgap;
int vgap;
/**
* GridFlowLayout constructor make a GridFlowLayout with default value (1)
* for gap
*/
public GridFlowLayout() {
this(1, 1);
}
/**
* GridFlowLayout constructor
*
* @param hgap the horizontal gap between two components
* @param vgap the vertical gap between two components
*/
public GridFlowLayout(int hgap, int vgap) {
this.hgap = hgap;
this.vgap = vgap;
}
// ////////////////////////////////////////////////////////////////////
/**
* Gets the horizontal gap between components.
*
* @return the horizontal gap between components
* @see #setHgap
*/
public int getHgap() {
return hgap;
}
/**
* Sets the horizontal gap between components.
*
* @param hgap the horizontal gap between components
* @see #getHgap
*/
public void setHgap(int hgap) {
this.hgap = hgap;
}
/**
* Gets the vertical gap between components.
*
* @return the vertical gap between components
* @see #setVgap
*/
public int getVgap() {
return vgap;
}
/**
* Sets the vertical gap between components.
*
* @param vgap the vertical gap between components
* @see #getVgap
*/
public void setVgap(int vgap) {
this.vgap = vgap;
}
// ////////////////////////////////////////////////////////////////////
/**
* Method addLayoutComponent
*
* @param comp the component to add
* @param constraints a constraint which is a Number (position)
*/
@Override
public void addLayoutComponent(Component comp, Object constraints) {
if (constraints instanceof Number) {
positions.put(comp, constraints);
}
}
/**
* Method setConstraints
*
* @param comp the compoenent
* @param constraints
*/
public void setConstraints(Component comp, Number constraints) {
positions.put(comp, constraints);
}
/**
* Method getConstraints
*
* @param comp
* @return a number that corresponding to the constraint
*/
public Number getConstraints(Component comp) {
return (Number) positions.get(comp);
}
/**
* Method getLayoutAlignmentX
*
* @param target
* @return the X layout alignement
*/
@Override
public float getLayoutAlignmentX(Container target) {
return 0.5f;
}
/**
* Method getLayoutAlignmentY
*
* @param target
* @return the Y layout alignement
*/
@Override
public float getLayoutAlignmentY(Container target) {
return 0.5f;
}
/**
* Method invalidateLayout
*
* @param target
*/
@Override
public void invalidateLayout(Container target) {
}
/**
* Method addLayoutComponent
*
* @param name
* @param comp
*/
@Override
public void addLayoutComponent(String name, Component comp) {
}
/**
* Method minimumLayoutSize
*
* @param parent
* @return the minimum dimension of the layout
*/
@Override
public Dimension minimumLayoutSize(Container parent) {
synchronized (parent.getTreeLock()) {
return getMinWidthHeight(parent);
}
}
/**
* Method preferredLayoutSize
*
* @param parent
* @return the preferred dimension of the layout
*/
@Override
public Dimension preferredLayoutSize(Container parent) {
synchronized (parent.getTreeLock()) {
Dimension result = getMaxWidthHeight(parent);
Insets insets = parent.getInsets();
int nbChild = getComponentVisibleCount(parent);
int nbColumn = (int) Math.round(Math.sqrt(nbChild));
// si un de nom parent est un JViewPort ou dit que l'on
// peut etre plus petit que prevu pour eviter le scroll vertical
Container container = parent;
while (container != null && container.getWidth() != 0) {
if (container instanceof JViewport) {
nbColumn = (container.getWidth() - insets.left - insets.right)
/ ((int) result.getWidth() + 2 * hgap);
break;
}
container = container.getParent();
}
if (nbColumn == 0) {
nbColumn++;
}
int nbRow = (int) Math.ceil((double) nbChild / (double) nbColumn);
result.width *= nbColumn;
result.height *= nbRow;
result.width += hgap * 2 * nbColumn;
result.height += vgap * 2 * nbRow;
result.width += insets.left + insets.right;
result.height += insets.top + insets.bottom;
return result;
}
}
/**
* Method maximumLayoutSize
*
* @param target
* @return the max dimension of the layout
*/
@Override
public Dimension maximumLayoutSize(Container target) {
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
/**
* Method removeLayoutComponent
*
* @param comp
*/
@Override
public void removeLayoutComponent(Component comp) {
positions.remove(comp);
}
/**
* Method layoutContainer
*
* @param parent
*/
@Override
public void layoutContainer(Container parent) {
synchronized (parent.getTreeLock()) {
Component components[] = parent.getComponents();
if (components.length == 0) {
return;
}
// on met les composants dans l'ordre demande par l'utilisateur.
components = computeOrder(components);
Dimension max = getMaxWidthHeight(parent);
int w = (int) max.getWidth();
int h = (int) max.getHeight();
Insets insets = parent.getInsets();
int parentWidth = parent.getWidth();
boolean ltr = parent.getComponentOrientation().isLeftToRight();
// recalcul de la largeur et du nombre de colonne
int nbColumn = (parentWidth - insets.left - insets.right)
/ (w + 2 * hgap);
if (nbColumn == 0) {
nbColumn++;
}
w = (parentWidth - insets.left - insets.right) / nbColumn;
w -= 2 * hgap;
// nombre a soustraire pour commencer les lignes a gauche
// ou a droite
int ltrNb = 0;
int horizontalMargin = insets.left;
int verticalMargin = insets.top;
if (!ltr) {
ltrNb = nbColumn - 1;
horizontalMargin = insets.right;
}
int count = 0;
for (Component component : components) {
if (component.isVisible()) {
int column = count % nbColumn;
int row = count / nbColumn;
component.setBounds(
/* on calcul la position */Math.abs(ltrNb - column) * w
/* on ajoute la marge */+ horizontalMargin
/* on ajoute les intervales */+ (2 * column + 1) * hgap,
/* on calcul la position */row * h
/* on ajoute la marge */+ verticalMargin
/* on ajoute les intervales */+ (2 * row + 1) * vgap,
w, h);
count++;
}
}
}
}
// ////////////////////////////////////////////////////////////////////
/**
* Method getComponentVisibleCount
*
* @param parent
* @return an integer that corresponding to the number of visible components
*/
protected int getComponentVisibleCount(Container parent) {
int result = 0;
Component components[] = parent.getComponents();
for (Component component : components) {
if (component.isVisible()) {
result++;
}
}
return result;
}
/**
* Method getMaxWidthHeight
*
* @param parent
* @return the max size
*/
protected Dimension getMaxWidthHeight(Container parent) {
Component components[] = parent.getComponents();
Dimension result = new Dimension(0, 0);
for (Component component : components) {
if (component.isVisible()) {
Dimension d = component.getPreferredSize();
result.width = Math.max(result.width, d.width);
result.height = Math.max(result.height, d.height);
}
}
return result;
}
/**
* Method getMinWidthHeight
*
* @param parent
* @return the dimension of this layout
*/
protected Dimension getMinWidthHeight(Container parent) {
Component components[] = parent.getComponents();
Dimension result = new Dimension(0, 0);
for (Component component : components) {
if (component.isVisible()) {
Dimension d = component.getMinimumSize();
result.width = Math.max(result.width, d.width);
result.height = Math.max(result.height, d.height);
}
}
return result;
}
/**
* Method []
*
* @param components
* @return une tablean de composants contenus dans le layout
*/
public Component[] computeOrder(Component[] components) {
Component[] result = new Component[components.length];
// contient les composants dont la contrainte n'est pas bonne
// et que l'on place comme s'il n'avait pas de contraint.
HashSet inWait = new HashSet();
// on commence par mettre les composants dont on connait la position
for (Component comp : positions.keySet()) {
Number pos = (Number) positions.get(comp);
if (pos != null && -1 < pos.intValue()
&& pos.intValue() < result.length) {
result[pos.intValue()] = comp;
} else {
inWait.add(comp);
}
}
// on place les autres composants
int j = 0;
for (Component component : components) {
// si la contrainte etait fausse, ou qu'il n'y en avait pas
if (inWait.contains(component) || !positions.containsKey(component)) {
// on cherche la prochaine place vide
while (result[j] != null) {
j++;
}
// pour mettre le composant
result[j] = component;
}
}
return result;
}
// ////////////////////////////////////////////////////////////////////
public static void main(String[] args) {
javax.swing.JPanel panel = new javax.swing.JPanel(new GridFlowLayout(
10, 5));
for (int i = 0; i < 10; i++) {
panel.add(new javax.swing.JButton("label " + i), new Integer(i + 3));
}
javax.swing.JFrame frame = new javax.swing.JFrame("Test");
frame.getContentPane().add(new javax.swing.JScrollPane(panel));
frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
} // GridFlowLayout