/* * NAME * $RCSfile$ - * DESCRIPTION * [given below in javadoc format] * DELTA * $Revision: 11553 $ * CREATED * $Date: 2007-06-05 15:06:23 -0700 (星期二, 05 六月 2007) $ by birgit * COPYRIGHT * West Consulting bv * TO DO * */ package tablelayout; // TableVector Methods //======================= // Each TableLayout Manager has two TableVectors: // one describes the columns, and the other describes the rows. // // The TableVector is an abstract class. For the column use TableCol, for the // row use TableRow. // // The table vectors are created based on information in the layout // of the Manager, hence they must be created after the layout, and they // must be updated when the layout changes. The layout data upon // which the vectors depend is: number of cols, number of rows, options (only // W and H). // // This class used to be abstract, but since MSIE could not handle it // I removed the "abstract" notation. /** * Each TableLayout Manager has two * TableVectors: * one describes the columns, and the other describes the rows. * * The <b>TableVector</b> is an abstract class. For the column use * <b>TableCol</b>, for the row use <b>TableRow</b>. * * The table vector is created, based on information of the * layout * of the TableLayout Manager, hence they must be created after the * layout, and they must be updated when the layout changes. * * The TableVec is an array of TableVecRec, which * contains the size information of each component in a row of column. * * @see tablelayout.TableVecRec * @see tablelayout.TableLoc * @see tablelayout.TableCol * @see tablelayout.TableRow * * @see tablelayout.TableLayout * @author Birgit Arkesteijn * @version $Revision: 11553 $ $Date: 2007-06-05 15:06:23 -0700 (星期二, 05 六月 2007) $ */ abstract public class TableVec extends Object { private static final String version_id = "@(#)$Id: TableVec.java 11553 2007-06-05 22:06:23Z duns $ Copyright West Consulting bv"; // Table Vector Structs //======================== // A table has two of these vectors: one for columns, and one for rows. // static final int TBL_VEC_MINIMIZE = 0x01; static final int TBL_VEC_LOCK = 0x02; static final int TBL_VEC_NOGROW = (TBL_VEC_MINIMIZE | TBL_VEC_LOCK); static final boolean DO_ACTUAL = true; static final boolean DO_PREFERRED = false; /** * Vector with the sizes of the elements (columns or rows) */ public TableVecRec vec[]; /** * The layout parent */ public TableLayout parent; /** * Number of elements (columns or rows) */ public int size; /** * Changes the cells to its minimum size. */ abstract public void minimize(); /** * Returns the total (minimum) size */ abstract public int totalSize(); /** * Returns the preferred size */ abstract public int getPreferredSize(); /** * Calculates the size of the layout */ abstract public int layoutSize(boolean do_actual); /** * Returns the TableVecRec size information on a given position * * @exception java.lang.ArrayIndexOutOfBoundsException if the index if out of * bound * @param index the index of the information * @see tablelayout.TableVecRec */ public TableVecRec elementAt(int index) { if (index < 0 || index > size-1) { throw new ArrayIndexOutOfBoundsException(index); } else return (TableVecRec) vec[index]; } // Adjust rows or columns //========================== // When a parent re-sizes a Table, it can make it larger or smaller. The // adjustment is distributed as a ratio of the preferred sizes of the // col/row, so small ones change slower than larger ones. // // Nowhere in the logic below is there any mechanism which prevents things // from shrinking smaller than the preferred size. // There is, however, mechanisms to prevent any col or row from becoming // smaller than 1. // // If resize makes the Table larger than before: First, all col/row // smaller that preferred size are stretched up until their preferred // size. The rest of the change is distributed evenly to un-locked col/row, // but if all are locked, then all are stretched. // // If the table is being made smaller, then the inverse is applied: all // unlocked (or all if all are locked) are made smaller down to their // preferred sizes, then all are made smaller by the same amount. // // Adjustments to the vectors are made on a relative basis. Big slots // change more than small slots. Therefore, the adjustment delta is // computed for each slot which might change. // // While adjusting the vectors, there are too things to watch out for: lots of // slots to change, yet not much change, integer truncation then leaves the // delta zero. In this case we make the delta 1, which means the change gets // used up before all the slots are seen. We use the same algorithm for // growing and shrinking, so there should be no perceivable problems. The // second problem is when the delta would consume too much change, again due // to integer truncation. In this case, we must simply make the delta equal // to the remaining change. // // Notice that there are two resize algorithms used: one applies when // everything is smaller than preferred, and another applies when everything // is bigger. // When smaller, everything gets changed relatively. When larger, change // is influenced by the table slot being locked (TBL_VEC_LOCK). Slots which // are locked are not adjusted unless ALL slots are locked, then all are // adjusted relatively. // /** * Adjust the row or column after a resize * * @param change the number of pixel the row or column should grow or * shrink */ public void adjust(int change) { int vec_inx, remaining, amt; int total_pref; int can_change, can_change_pref; int too_small; int too_big, too_big_pref; if (0 == change) return; total_pref = can_change = can_change_pref = 0; too_small = too_big = too_big_pref = 0; for (vec_inx=0; vec_inx < size; vec_inx++) { // NOTE: total_pref can be zero if all pref_value are 0! total_pref += vec[vec_inx].pref_value; if (change > 0) { if (0 == (vec[vec_inx].options & TBL_VEC_LOCK)) { // NOTE: can_change_pref can be zero if all pref_value are 0! can_change++; can_change_pref += vec[vec_inx].pref_value; } if (vec[vec_inx].value < vec[vec_inx].pref_value) { too_small++; } } else { if (vec[vec_inx].value > vec[vec_inx].pref_value) { // NOTE: too_big_pref can be zero if all pref_value are 0! too_big++; too_big_pref += vec[vec_inx].pref_value; } } } if (change > 0) { //================= Make columns wider or rows taller =============== int still_too_small; remaining = change; still_too_small = 1; while (still_too_small != 0) { // Expand everything smaller than preferred up to preferred still_too_small = 0; for (vec_inx=0; vec_inx < size; vec_inx++) { if (vec[vec_inx].value < vec[vec_inx].pref_value) { // Make this one bigger, up to preferred size if (0 == total_pref) amt = change / (too_small!=0?too_small:size); else amt = change * vec[vec_inx].pref_value / total_pref; if (0 == amt) amt = 1; else if (remaining < amt) amt = remaining; if (vec[vec_inx].value + amt < vec[vec_inx].pref_value) { vec[vec_inx].value += amt; ++still_too_small; } else { amt = vec[vec_inx].pref_value - vec[vec_inx].value; vec[vec_inx].value = vec[vec_inx].pref_value; } remaining -= amt; if (remaining <= 0) return; // used up all change } } change = remaining; } // All are at least preferred size, and there is change remaining. // If none of the vector slots can stretch, then we still must // force them all to stretch. if (0 == can_change) can_change_pref = total_pref; // maintain relative sizes while (true) // until remaining goes to zero or negative above { for (vec_inx = 0; vec_inx < size; vec_inx++) { if (0 == can_change || 0 == (vec[vec_inx].options & TBL_VEC_LOCK)) { // Add relative amount to all which can change. if (0 == can_change_pref) amt = change / (can_change!=0?can_change:size); else amt = change * vec[vec_inx].pref_value/can_change_pref; if (0 == amt) amt = 1; else if (remaining < amt) amt = remaining; vec[vec_inx].value += amt; remaining -= amt; if (remaining <= 0) return; // used up all change } } // We have gone thru vector, adding space, but due to truncation // there may still be more change to distribute. change = remaining; } } else // (change < 0) { //================= Make columns narrower or rows shorter ============== int still_too_big, num_larger_than_1; // For conceptual clarity, switch the sign on change change = -change; remaining = change; still_too_big = too_big; while (still_too_big !=0) { // Shrink all which are larger than preferred still_too_big = 0; for (vec_inx = 0; vec_inx < size; vec_inx++) { if (vec[vec_inx].value > vec[vec_inx].pref_value) { if (0 == too_big_pref) amt = change / (too_big !=0?too_big:size); else amt = change * vec[vec_inx].pref_value / too_big_pref; if (0 == amt) amt = 1; else if (remaining < amt) amt = remaining; if (vec[vec_inx].value - amt < vec[vec_inx].pref_value) { amt = vec[vec_inx].value - vec[vec_inx].pref_value; vec[vec_inx].value = vec[vec_inx].pref_value; } else { vec[vec_inx].value -= amt; still_too_big++; } remaining -= amt; if (remaining <= 0) return; // used up all change } } // We have made a pass through all slots change = remaining; } // Now all stretchable are preferred sizes, or all were already smaller // than preferred sizes, yet more change is remaining to be absorbed. // // Shrink evenly, but since none can become smaller than 1, we may need // to make multiple passes over vector until total change is absorbed, // or all are of size 1. num_larger_than_1 = 1; while (num_larger_than_1 != 0) { num_larger_than_1 = 0; for (vec_inx = 0; vec_inx < size; vec_inx++) { if (0 == total_pref) amt = change / size; else amt = change * vec[vec_inx].pref_value / total_pref; if (0 == amt) amt = 1; else if (remaining < amt) amt = remaining; if (amt < vec[vec_inx].value) { vec[vec_inx].value -= amt; ++num_larger_than_1; } else { amt = vec[vec_inx].value - 1; vec[vec_inx].value = 1; } remaining -= amt; if (remaining <= 0) return; // used up all change } // We have made a pass through all slots change = remaining; } return; // all are shrunk to absolute minimum size (1) } } // end of adjust() // Set Upper Left Corner Coordinates of Each Cell //================================================== // Note that it is not worth doing this until the actual correct size of // the rows and columns have been computed. // /** * Sets the upper left corner coordinate of each component within the * container * * @param margin the margin of the container * @param gap the gap between each component in the container */ public void computeOffsets(int margin, int gap) { int i; int offset = margin; for (i = 0; i < size; i++) { vec[i].offset = offset; offset = offset + vec[i].value + gap; } } /** * Returns the String representation */ public String toString() { String st = new String ( "TableVec [" + " size " + size); for (int i=0; i<size; i++) { st = st + "\n" + vec[i].toString(); } st = st + " ]"; return (st); } }