TableLayout.java
上传用户:haobig99
上传日期:2022-06-15
资源大小:369k
文件大小:16k
源码类别:

J2ME

开发平台:

Java

  1. /*
  2.  * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
  3.  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4.  *
  5.  * This code is free software; you can redistribute it and/or modify it
  6.  * under the terms of the GNU General Public License version 2 only, as
  7.  * published by the Free Software Foundation.  Sun designates this
  8.  * particular file as subject to the "Classpath" exception as provided
  9.  * by Sun in the LICENSE file that accompanied this code.
  10.  *
  11.  * This code is distributed in the hope that it will be useful, but WITHOUT
  12.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14.  * version 2 for more details (a copy is included in the LICENSE file that
  15.  * accompanied this code).
  16.  *
  17.  * You should have received a copy of the GNU General Public License version
  18.  * 2 along with this work; if not, write to the Free Software Foundation,
  19.  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20.  *
  21.  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22.  * CA 95054 USA or visit www.sun.com if you need additional information or
  23.  * have any questions.
  24.  */
  25. package com.sun.lwuit.table;
  26. import com.sun.lwuit.layouts.*;
  27. import com.sun.lwuit.Component;
  28. import com.sun.lwuit.Container;
  29. import com.sun.lwuit.Display;
  30. import com.sun.lwuit.geom.Dimension;
  31. import com.sun.lwuit.plaf.Style;
  32. /**
  33.  * Layout manager similar in spirit to HTML tables allowing rows and columns 
  34.  * of varying width/height.
  35.  *
  36.  * @author Shai Almog
  37.  */
  38. public class TableLayout extends Layout {
  39.     private int currentRow;
  40.     private int currentColumn;
  41.     private static int minimumSizePerColumn = 10;
  42.     private Constraint[][] tablePositions;
  43.     /**
  44.      * Special case marker SPAN constraint reserving place for other elements
  45.      */
  46.     private static final Constraint SPAN_CONSTRAINT = new Constraint();
  47.     private boolean[] rigidColumns;
  48.     private static int defaultColumnWidth = -1;
  49.     private static int defaultRowHeight = -1;
  50.     /**
  51.      * A table must declare the amount of rows and columns in advance
  52.      *
  53.      * @param rows rows of the table
  54.      * @param columns columns of the table
  55.      */
  56.     public TableLayout(int rows, int columns) {
  57.         tablePositions = new Constraint[rows][columns];
  58.         rigidColumns = new boolean[columns];
  59.     }
  60.     /**
  61.      * Allows indicating that the given column should not be resized to fit into the available display width/height
  62.      *
  63.      * @param column the column to define as rigid
  64.      * @param rigid whether the column should be rigid or should it shrink
  65.      */
  66.     public void setRigidColumn(int column, boolean rigid) {
  67.         rigidColumns[column] = rigid;
  68.     }
  69.     /**
  70.      * Returns the component at the given row/column
  71.      * 
  72.      * @param row the row of the component
  73.      * @param column the column of the component
  74.      * @return the component instance
  75.      */
  76.     public Component getComponentAt(int row, int column) {
  77.         return tablePositions[row][column].parent;
  78.     }
  79.     /**
  80.      * @inheritDoc
  81.      */
  82.     public void layoutContainer(Container parent) {
  83.         // column and row size in pixels
  84.         Style s = parent.getStyle();
  85.         int top = s.getPadding(false, Component.TOP);
  86.         int left = s.getPadding(parent.isRTL(), Component.LEFT);
  87.         int bottom = s.getPadding(false, Component.BOTTOM);
  88.         int right = s.getPadding(parent.isRTL(), Component.RIGHT);
  89.         boolean rtl = parent.isRTL();
  90.         int[] columnSizes = new int[tablePositions[0].length];
  91.         int[] columnPositions = new int[tablePositions[0].length];
  92.         int[] rowSizes = new int[tablePositions.length];
  93.         int[] rowPositions = new int[tablePositions.length];
  94.         int pWidth = parent.getLayoutWidth() - parent.getSideGap() - left - right;
  95.         int pHeight = parent.getLayoutHeight() - parent.getBottomGap() - top - bottom;
  96.         int currentX = left;
  97.         for(int iter = 0 ; iter < columnSizes.length ; iter++) {
  98.             if(parent.isScrollableX()) {
  99.                 columnSizes[iter] = getColumnWidthPixels(iter, pWidth, pWidth);
  100.             } else {
  101.                 int leave = minimumSizePerColumn * (columnSizes.length - iter);
  102.                 columnSizes[iter] = getColumnWidthPixels(iter, pWidth, pWidth - currentX - leave);
  103.             }
  104.             if(rtl) {
  105.                 currentX += columnSizes[iter];
  106.                 columnPositions[iter] = pWidth - currentX;
  107.             } else {
  108.                 columnPositions[iter] = currentX;
  109.                 currentX += columnSizes[iter];
  110.             }
  111.         }
  112.         int currentY = top;
  113.         for(int iter = 0 ; iter < rowSizes.length ; iter++) {
  114.             if(parent.isScrollableY()) {
  115.                 rowSizes[iter] = getRowHeightPixels(iter, pHeight, -1);
  116.             } else {
  117.                 rowSizes[iter] = getRowHeightPixels(iter, pHeight, pHeight - currentY);
  118.             }
  119.             rowPositions[iter] = currentY;
  120.             currentY += rowSizes[iter];
  121.         }
  122.         for(int r = 0 ; r < rowSizes.length ; r++) {
  123.             for(int c = 0 ; c < columnSizes.length ; c++) {
  124.                 Constraint con = tablePositions[r][c];
  125.                 if(con != null && con != SPAN_CONSTRAINT) {
  126.                     Style componentStyle = con.parent.getStyle();
  127.                     int leftMargin = componentStyle.getMargin(parent.isRTL(), Component.LEFT);
  128.                     int topMargin = componentStyle.getMargin(false, Component.TOP);
  129.                     con.parent.setX(left + leftMargin + columnPositions[c]);
  130.                     con.parent.setY(top + topMargin + rowPositions[r]);
  131.                     if(con.spanHorizontal > 1) {
  132.                         int w = columnSizes[c];
  133.                         for(int sh = 1 ; sh < con.spanHorizontal ; sh++) {
  134.                             w += columnSizes[c + sh];
  135.                         }
  136.                         // for RTL we need to move the component to the side so spanning will work
  137.                         if(rtl) {
  138.                             con.parent.setX(left + leftMargin + columnPositions[c + con.spanHorizontal - 1]);
  139.                         }
  140.                         con.parent.setWidth(w - leftMargin - componentStyle.getMargin(parent.isRTL(), Component.RIGHT));
  141.                     } else {
  142.                         con.parent.setWidth(columnSizes[c] - leftMargin - componentStyle.getMargin(parent.isRTL(), Component.RIGHT));
  143.                     }
  144.                     if(con.spanVertical > 1) {
  145.                         int h = rowSizes[r];
  146.                         for(int sv = 1 ; sv < con.spanVertical ; sv++) {
  147.                             h += rowSizes[r + sv];
  148.                         }
  149.                         con.parent.setHeight(h - topMargin - componentStyle.getMargin(false, Component.BOTTOM));
  150.                     } else {
  151.                         con.parent.setHeight(rowSizes[r] - topMargin - componentStyle.getMargin(false, Component.BOTTOM));
  152.                     }
  153.                 }
  154.             }
  155.         }
  156.     }
  157.     private int getColumnWidthPixels(int column, int percentageOf, int available) {
  158.         int current = 0;
  159.         for(int iter = 0 ; iter < tablePositions.length ; iter++) {
  160.             Constraint c = tablePositions[iter][column];
  161.             if(c == null || c == SPAN_CONSTRAINT || c.spanHorizontal > 1) {
  162.                 continue;
  163.             }
  164.             // width in percentage of the parent container
  165.             if(c.width > 0) {
  166.                 current = Math.max(current, c.width * percentageOf / 100);
  167.             } else {
  168.                 Style s = c.parent.getStyle();
  169.                 current = Math.max(current, c.parent.getPreferredW() + s.getMargin(false, Component.LEFT) + s.getMargin(false, Component.RIGHT));
  170.             }
  171.             if(available > -1) {
  172.                 current = Math.min(available, current);
  173.             }
  174.         }
  175.         return current;
  176.     }
  177.     private int getRowHeightPixels(int row, int percentageOf, int available) {
  178.         int current = 0;
  179.         for(int iter = 0 ; iter < tablePositions[row].length ; iter++) {
  180.             Constraint c = tablePositions[row][iter];
  181.             if(c == null || c == SPAN_CONSTRAINT || c.spanVertical > 1) {
  182.                 continue;
  183.             }
  184.             // height in percentage of the parent container
  185.             if(c.height > 0) {
  186.                 current = Math.max(current, c.height * percentageOf / 100);
  187.             } else {
  188.                 Style s = c.parent.getStyle();
  189.                 current = Math.max(current, c.parent.getPreferredH() + s.getMargin(false, Component.BOTTOM) + s.getMargin(false, Component.TOP));
  190.             }
  191.             if(available > -1) {
  192.                 current = Math.min(available, current);
  193.             }
  194.         }
  195.         return current;
  196.     }
  197.     /**
  198.      * @inheritDoc
  199.      */
  200.     public Dimension getPreferredSize(Container parent) {
  201.         Style s = parent.getStyle();
  202.         int w = s.getPadding(false, Component.LEFT) + s.getPadding(false, Component.RIGHT);
  203.         int h = s.getPadding(false, Component.TOP) + s.getPadding(false, Component.BOTTOM);
  204.         for(int iter = 0 ; iter < tablePositions[0].length ; iter++) {
  205.             w += getColumnWidthPixels(iter, Integer.MAX_VALUE, -1);
  206.         }
  207.         for(int iter = 0 ; iter < tablePositions.length ; iter++) {
  208.             h += getRowHeightPixels(iter, Integer.MAX_VALUE, -1);
  209.         }
  210.         return new Dimension(w, h);
  211.     }
  212.     /**
  213.      * @inheritDoc
  214.      */
  215.     public void addLayoutComponent(Object value, Component comp, Container c) {
  216.         Constraint con = (Constraint)value;
  217.         if(con == null) {
  218.             con = createConstraint();
  219.         } else {
  220.             if(con.parent != null) {
  221.                 throw new IllegalArgumentException("Constraint already associated with component!");
  222.             }
  223.         }
  224.         if(con.row < 0) {
  225.             con.row = currentRow;
  226.         }
  227.         if(con.column < 0) {
  228.             con.column = currentColumn;
  229.         }
  230.         con.parent = comp;
  231.         if(tablePositions[con.row][con.column] != null) {
  232.             throw new IllegalArgumentException("Row: " + con.row + " and column: " + con.column + " already occupied");
  233.         }
  234.         tablePositions[con.row][con.column] = con;
  235.         if(con.spanHorizontal > 1 || con.spanVertical > 1) {
  236.             for(int sh = 0 ; sh < con.spanHorizontal ; sh++) {
  237.                 for(int sv = 0 ; sv < con.spanVertical ; sv++) {
  238.                     if(sh > 0 || sv > 0) {
  239.                         if(tablePositions[con.row + sv][con.column + sh] == null) {
  240.                             tablePositions[con.row + sv][con.column + sh] = SPAN_CONSTRAINT;
  241.                         }
  242.                     }
  243.                 }
  244.             }
  245.         }
  246.         updateRowColumn();
  247.     }
  248.     private void updateRowColumn() {
  249.         if(currentRow >= tablePositions.length) {
  250.             return;
  251.         }
  252.         while(tablePositions[currentRow][currentColumn] != null) {
  253.             currentColumn++;
  254.             if(currentColumn >= tablePositions[0].length) {
  255.                 currentColumn = 0;
  256.                 currentRow++;
  257.                 if(currentRow >= tablePositions.length) {
  258.                     return;
  259.                 }
  260.             }
  261.         }
  262.     }
  263.     /**
  264.      * @inheritDoc
  265.      */
  266.     public void removeLayoutComponent(Component comp) {
  267.         for(int r = 0 ; r < tablePositions.length ; r++) {
  268.             for(int c = 0 ; c < tablePositions[r].length ; c++) {
  269.                 if(tablePositions[r][c].parent == comp) {
  270.                     tablePositions[r][c] = null;
  271.                     return;
  272.                 }
  273.             }
  274.         }
  275.     }
  276.     /**
  277.      * @inheritDoc
  278.      */
  279.     public Object getComponentConstraint(Component comp) {
  280.         for(int r = 0 ; r < tablePositions.length ; r++) {
  281.             for(int c = 0 ; c < tablePositions[r].length ; c++) {
  282.                 if(tablePositions[r][c] != null && tablePositions[r][c].parent == comp) {
  283.                     return tablePositions[r][c];
  284.                 }
  285.             }
  286.         }
  287.         return null;
  288.     }
  289.     /**
  290.      * Creates a new Constraint instance to add to the layout
  291.      *
  292.      * @return the default constraint
  293.      */
  294.     public Constraint createConstraint() {
  295.         return new Constraint();
  296.     }
  297.     /**
  298.      * Creates a new Constraint instance to add to the layout
  299.      *
  300.      * @param row the row for the table starting with 0
  301.      * @param column the column for the table starting with 0
  302.      * @return the new constraint
  303.      */
  304.     public Constraint createConstraint(int row, int column) {
  305.         Constraint c = createConstraint();
  306.         c.row = row;
  307.         c.column = column;
  308.         return c;
  309.     }
  310.     /**
  311.      * Sets the minimum size for a column in the table, this is applicable for tables that are
  312.      * not scrollable on the X axis. This will force the earlier columns to leave room for
  313.      * the latter columns.
  314.      *
  315.      * @param minimumSize the minimum width of the column
  316.      */
  317.     public static void setMinimumSizePerColumn(int minimumSize) {
  318.         minimumSizePerColumn = minimumSize;
  319.     }
  320.     /**
  321.      * Indicates the minimum size for a column in the table, this is applicable for tables that are
  322.      * not scrollable on the X axis. This will force the earlier columns to leave room for
  323.      * the latter columns.
  324.      *
  325.      * @return  the minimum width of the column
  326.      */
  327.     public static int getMinimumSizePerColumn() {
  328.         return minimumSizePerColumn;
  329.     }
  330.     /**
  331.      * Indicates the default (in percentage) for the column width, -1 indicates
  332.      * automatic sizing
  333.      *
  334.      * @param w width in percentage
  335.      */
  336.     public static void setDefaultColumnWidth(int w) {
  337.         defaultColumnWidth = w;
  338.     }
  339.     /**
  340.      * Indicates the default (in percentage) for the column width, -1 indicates
  341.      * automatic sizing
  342.      *
  343.      * @return width in percentage
  344.      */
  345.     public static int getDefaultColumnWidth() {
  346.         return defaultColumnWidth;
  347.     }
  348.     /**
  349.      * Indicates the default (in percentage) for the row height, -1 indicates
  350.      * automatic sizing
  351.      *
  352.      * @param h height in percentage
  353.      */
  354.     public static void setDefaultRowHeight(int h) {
  355.         defaultRowHeight = h;
  356.     }
  357.     /**
  358.      * Indicates the default (in percentage) for the row height, -1 indicates
  359.      * automatic sizing
  360.      *
  361.      * @return height in percentage
  362.      */
  363.     public static int getDefaultRowHeight() {
  364.         return defaultRowHeight;
  365.     }
  366.     /**
  367.      * Represents the layout constraint for an entry within the table indicating
  368.      * the desired position/behavior of the component.
  369.      */
  370.     public static class Constraint {
  371.         private Component parent;
  372.         private int row = -1;
  373.         private int column = -1;
  374.         private int width = defaultColumnWidth;
  375.         private int height = defaultRowHeight;
  376.         private int spanHorizontal = 1;
  377.         private int spanVertical = 1;
  378.         /**
  379.          * Sets the cells to span vertically, this number must never be smaller than 1
  380.          *
  381.          * @param span a number larger than 1
  382.          */
  383.         public void setVerticalSpan(int span) {
  384.             if(span < 1) {
  385.                 throw new IllegalArgumentException("Illegal span");
  386.             }
  387.             spanVertical = span;
  388.         }
  389.         /**
  390.          * Sets the cells to span horizontally, this number must never be smaller than 1
  391.          *
  392.          * @param span a number larger than 1
  393.          */
  394.         public void setHorizontalSpan(int span) {
  395.             if(span < 1) {
  396.                 throw new IllegalArgumentException("Illegal span");
  397.             }
  398.             spanHorizontal = span;
  399.         }
  400.         /**
  401.          * Sets the column width based on percentage of the parent
  402.          *
  403.          * @param width negative number indicates ignoring this member
  404.          */
  405.         public void setWidthPercentage(int width) {
  406.             this.width = width;
  407.         }
  408.         /**
  409.          * Sets the row height based on percentage of the parent
  410.          *
  411.          * @param height negative number indicates ignoring this member
  412.          */
  413.         public void setHeightPercentage(int height) {
  414.             this.height = height;
  415.         }
  416.     }
  417. }