All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.wings.SGridBagLayout Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2000,2005 wingS development team.
 *
 * This file is part of wingS (http://wingsframework.org).
 *
 * wingS 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 2.1
 * of the License, or (at your option) any later version.
 *
 * Please see COPYING for the complete licence.
 */
package org.wings;

import org.wings.event.SComponentEvent;
import org.wings.event.SComponentListener;

import java.awt.*;
import java.util.HashMap;

/**
 * Tries to simulate swing GridBag behaviour as close as possible.
 * 

* This layout is similar to Swing's GridBagLayout, though it can't * implement all functionalities because of the limitations of * HTML-table. It probably doesn't work exactly like its * Swing-counterpart - as a general hint: don't be too clever... *

*

* SComponents are usually added using an instance of * java.awt.GridBagConstraints which is copied while adding it (so you * might reuse it to add other SComponents). There are basically two * ways of adding: explicitly setting gridx and gridy or leaving * those at the default (RELATIVE) and let SGridBagLayout decide where * to put them. Normally they will be added horizontally, unless you * explicitly set gridx, which will add the SComponents * vertically. With setting gridy you can choose a row in which the * SComponents will be added. If you want to finish a row/column, you * can set gridwidth/gridheight to REMAINDER or RELATIVE - REMAINDER * marks the row/column to be finished while RELATIVE tells * SGridBagLayout that the next added SComponent will be the * last cell of the row/column which will always be placed at the end * (while the 'RELATIVE'-SComponent will be expanded to fill the gap). *

*

* Important: When choosing a new row/column, the next * gridx/gridy-value that SGridLayout will choose will always be 0, * even if there is already a SComponent at that position. If you * really need to be clever, explicitly set gridx and gridy, * especially if you plan to dynamically add and remove SComponents. *

*

* The size of a cell can be influenced in two ways: either set * gridwidth/gridheight to a value larger than 1 to say how many * regular cells this cell should span or use weightx/weighty to tell * the browser how much of the empty space this cell should eat up * (e.g. if there are 3 cells with each weight=1, they will all get * 33%). The last method has two disadvantages: firstly, it uses the * deprecated width/height-parameters of the HTML-td statement and * secondly, it must be carefully used to get the correct result: all * cells of a row/column should have the same weighty/weightx or 0, so * it might be easier to set these values only in the first * column/row. *

*

* GridBagConstraints has many more options than those described * above, but the current implementation can't use them. * * @author Jochen Scharrlach */ public class SGridBagLayout extends SAbstractLayoutManager implements SComponentListener { /** * Map of all managed components (key: component, value: constraint) */ private HashMap components = new HashMap(); /** * @see #getBorder */ protected int border = 0; /** * The horizontal gap (in pixels) specifiying the space * between columns. They can be changed at any time. * This should be a non-negative integer. */ protected int hgap = -1; /** * The vertical gap (in pixels) which specifiying the space * between rows. They can be changed at any time. * This should be a non negative integer. */ protected int vgap = -1; /** * @see #getHeader */ protected boolean header = false; /** * The defaults to use if the addComponent()-call does not give * the constraints. */ protected GridBagConstraints defaultConstraints = new GridBagConstraints(); /** * Contains a pre-calculated grid (or null) */ protected transient Grid currentGrid; /** * Indicates that the corresponding SComponent should be at the * end of the row/column. This value is only for internal use and * cannot be used with addComponent. */ public static final int LAST_CELL = -1; /** * creats a new gridbag layout */ public SGridBagLayout() { setPreferredSize(SDimension.FULLWIDTH); } /** * Add the given component with the given constraints to the * layout. * * @param comp the component to add * @param constraint instance of GridBagConstraints or null * @param index ignored */ @Override public void addComponent(SComponent comp, Object constraint, int index) { // The grid has to be rebuilt currentGrid = null; GridBagConstraints c = (GridBagConstraints) constraint; if (c == null) { c = defaultConstraints; } c = (GridBagConstraints) c.clone(); comp.addComponentListener(this); components.put(comp, c); } @Override public void removeComponent(SComponent c) { // The grid has to be rebuilt currentGrid = null; components.remove(c); c.removeComponentListener(this); } @Override public void componentHidden(SComponentEvent e) { // The grid has to be rebuilt currentGrid = null; } @Override public void componentMoved(SComponentEvent e) { // ignored } @Override public void componentResized(SComponentEvent e) { // ignored } @Override public void componentShown(SComponentEvent e) { // The grid has to be rebuilt currentGrid = null; } /** * Gets the horizontal gap between components in pixel. Rendered half as margin left and margin right * Some PLAFs might ignore this property. * * @return the horizontal gap between components */ public int getHgap() { return hgap; } /** * Sets the horizontal gap between components to the specified value in pixe. Rendered half as margin left and margin right * Some PLAFs might ignore this property. * * @param hgap the horizontal gap between components */ public void setHgap(int hgap) { this.hgap = hgap; } /** * Gets the vertical gap between components in pixel. Rendered half as margin top and margin bottom * Some PLAFs might ignore this property. * * @return the vertical gap between components */ public int getVgap() { return vgap; } /** * Sets the vertical gap between components to the specified value in pixel. * Rendered half as margin top and margin bottom. Some PLAFs might ignore this property. * * @param vgap the vertical gap between components */ public void setVgap(int vgap) { this.vgap = vgap; } /** * Set the border width. * * @param pixel the new border width in pixels */ @Override public void setBorder(int pixel) { border = pixel; } /** * Get the border width. * * @return the border width in pixels */ @Override public int getBorder() { return border; } /** * Specify if the first row should be printed as header * * @param b true=the first row is used as header */ public void setHeader(boolean b) { header = b; } /** * Query if the first row will be printed as header * * @return true=the first row is used as header */ public boolean getHeader() { return header; } // Some helper functions for CGs /** * This class prepares all information necessary to plot the * layout to the output device. The information will be outdated as * soon as components will be added or removed from the layout. */ public class Grid { /** * Number of columns */ public int cols; /** * Number of rows */ public int rows; /** * The matrix with all known SComponents. A SComponent might * appear in more than one cell, indicating that it spans more * than one cell - usually it will only be plotted if its * value for gridx/gridy matches the current cell (exception: * gridx/gridy might also be set to LAST_CELL). */ public SComponent[][] grid; /** * The total column-weight of a row(!). The cumulated weightx * of all cells of a row.. */ public double[] colweight; /** * The total row-weight of a column(!). The cumulated weighty * of all cells of a column.. */ public double[] rowweight; /** * The first row that contains cells */ public int firstRow; /** * The first column that contains cells */ public int firstCol; /** * Row for the next horizontal add (gridx=RELATIVE). If gridy is * not RELATIVE and does not match nextHorRow, the SComponent will * be added at gridx=0. */ private int nextHorRow = 0; /** * Column for the next horizontal add (gridx=RELATIVE) */ private int nextHorCol = 0; /** * Row for the next vertical add (gridx != RELATIVE, gridy = * RELATIVE). */ private int nextVertRow = 0; /** * Column for the next vertical add (gridx != RELATIVE, gridy = * RELATIVE). If gridx does not match nextVertCol, the SComponent * will be added at gridy=0. */ private int nextVertCol = 0; private final HashMap modifiedConstraints = new HashMap(components.size()); /** * Initialize all members */ public Grid() { cols = 0; rows = 0; for (Object o1 : getContainer().getComponentList()) { SComponent comp = (SComponent) o1; if (!comp.isVisible()) { //continue; } GridBagConstraints c = (GridBagConstraints) components.get(comp); c = (GridBagConstraints) c.clone(); modifiedConstraints.put(comp, c); if (c.gridx >= 0) { if (c.gridx != nextVertCol) { nextVertRow = 0; } if (c.gridy < 0) { c.gridy = nextVertRow; } } else { if (c.gridy >= 0 && c.gridy != nextHorRow) { nextHorCol = 0; } if (c.gridy < 0) { c.gridy = nextHorRow; } else if (c.gridy != nextHorRow) { nextHorCol = 0; } c.gridx = nextHorCol; } if (c.gridx == LAST_CELL) { if (c.gridy == LAST_CELL) { nextHorRow = 0; nextVertRow = 0; } else { nextHorRow = c.gridy + 1; nextVertRow = c.gridy + 1; } nextHorCol = 0; nextVertCol = 0; } else { if (c.gridy == LAST_CELL) { nextHorRow = 0; nextVertRow = 0; nextHorCol = c.gridx + 1; nextVertCol = c.gridx + 1; } else { nextHorCol = c.gridx; nextVertCol = c.gridx; nextHorRow = c.gridy; nextVertRow = c.gridy; if (c.gridwidth == GridBagConstraints.RELATIVE) { nextHorCol = LAST_CELL; } else if (c.gridwidth == GridBagConstraints.REMAINDER) { nextHorCol = 0; nextHorRow++; } else { if (c.gridwidth > 0) { nextHorCol += c.gridwidth; } else { nextHorCol++; } } if (c.gridheight == GridBagConstraints.RELATIVE) { nextVertRow = LAST_CELL; } else if (c.gridheight == GridBagConstraints.REMAINDER) { nextVertRow = 0; nextVertCol++; } else { if (c.gridheight > 0) { nextVertRow += c.gridheight; } else { nextVertRow++; } } } } if (c.gridx != SGridBagLayout.LAST_CELL) { int col = c.gridx; if (c.gridwidth == GridBagConstraints.RELATIVE) { col++; } else if (c.gridwidth > 1) { col += c.gridwidth - 1; } int row = c.gridy; if (c.gridheight == GridBagConstraints.RELATIVE) { row++; } else if (c.gridheight > 1) { row += c.gridheight - 1; } if (col >= cols) { cols = col + 1; } if (row >= rows) { rows = row + 1; } } } grid = new SComponent[cols][rows]; rowweight = new double[cols]; colweight = new double[rows]; for (Object o : getContainer().getComponentList()) { SComponent comp = (SComponent) o; if (!comp.isVisible()) { //continue; } GridBagConstraints c = (GridBagConstraints) modifiedConstraints.get(comp); int maxcol = c.gridx + c.gridwidth; int maxrow = c.gridy + c.gridheight; if (c.gridwidth == GridBagConstraints.RELATIVE) { maxcol = cols - 1; } else if (c.gridwidth == GridBagConstraints.REMAINDER) { maxcol = cols; } if (c.gridheight == GridBagConstraints.RELATIVE) { maxrow = rows - 1; } else if (c.gridheight == GridBagConstraints.REMAINDER) { maxrow = rows; } int col = c.gridx; if (col == SGridBagLayout.LAST_CELL) { col = cols - 1; maxcol = cols; } int row = c.gridy; if (row == SGridBagLayout.LAST_CELL) { row = rows - 1; maxrow = rows; } for (; col < maxcol; col++) { rowweight[col] += c.weighty; for (int r = row; r < maxrow; r++) { grid[col][r] = comp; colweight[r] += c.weightx; } } } /* for (firstRow = 0; firstRow < rows; firstRow++) { int col; for (col = 0; col < cols; col++) { if (grid[col][firstRow] != null) { break; } } if (col < cols) { break; } } for (firstCol = 0; firstCol < cols; firstCol++) { int row; for (row = 0; row < rows; row++) { if (grid[firstCol][row] != null) { break; } } if (row < rows) { break; } } */ } } /** * Build a grid from the current configuration. Make sure the * layout is not altered while using the Grid! * * @return the Grid-instance */ public Grid getGrid() { if (currentGrid == null) { currentGrid = new Grid(); } return currentGrid; } /** * Retrieve the constraint of a SComponent. The constraint must * not be altered! * * @param comp the component * @return the constraint or null if the component is unknown */ public GridBagConstraints getConstraints(SComponent comp) { // It might be better to return a copy of the constraint, // but that would hurt the performance return (GridBagConstraints) getGrid().modifiedConstraints.get(comp); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy