Coverage report

  %line %branch
se.datadosen.component.RiverLayout
0% 
0% 

 1  
 package se.datadosen.component;
 2  
 
 3  
 import java.awt.*;
 4  
 import java.util.*;
 5  
 
 6  
 /**
 7  
  * <p>RiverLayout makes it very simple to construct user interfaces as components
 8  
  * are laid out similar to how text is added to a word processor (Components flow
 9  
  * like a "river". RiverLayout is however much more powerful than FlowLayout:
 10  
  * Components added with the add() method generally gets laid out horizontally,
 11  
  * but one may add a string before the component being added to specify "constraints"
 12  
  * like this:
 13  
  * add("br hfill", new JTextField("Your name here");
 14  
  * The code above forces a "line break" and extends the added component horizontally.
 15  
  * Without the "hfill" constraint, the component would take on its preferred size.
 16  
  *</p>
 17  
  * <p>
 18  
  * List of constraints:<ul>
 19  
  * <li>br - Add a line break
 20  
  * <li>p - Add a paragraph break
 21  
  * <li>tab - Add a tab stop (handy for constructing forms with labels followed by fields)
 22  
  * <li>hfill - Extend component horizontally
 23  
  * <li>vfill - Extent component vertically (currently only one allowed)
 24  
  * <li>left - Align following components to the left (default)
 25  
  * <li>center - Align following components horizontally centered
 26  
  * <li>right - Align following components to the right
 27  
  * <li>vtop - Align following components vertically top aligned
 28  
  * <li>vcenter - Align following components vertically centered (default)
 29  
  * </ul>
 30  
  * </p>
 31  
  * RiverLayout is LGPL licenced - use it freely in free and commercial programs
 32  
  *
 33  
  * @author David Ekholm
 34  
  * @version 1.0
 35  
  */
 36  
 public class RiverLayout
 37  
     extends FlowLayout
 38  
     implements LayoutManager, java.io.Serializable {
 39  
 
 40  
    public static final String LINE_BREAK = "br";
 41  
    public static final String PARAGRAPH_BREAK = "p";
 42  
    public static final String TAB_STOP = "tab";
 43  
    public static final String HFILL = "hfill";
 44  
    public static final String VFILL = "vfill";
 45  
    public static final String LEFT = "left";
 46  
    public static final String RIGHT = "right";
 47  
    public static final String CENTER = "center";
 48  
    public static final String VTOP = "vtop";
 49  
    public static final String VCENTER = "vcenter";
 50  
 
 51  0
    Map constraints = new HashMap();
 52  0
    String valign = VCENTER;
 53  
    int hgap;
 54  
    int vgap;
 55  
    Insets extraInsets;
 56  0
    Insets totalInsets = new Insets(0, 0, 0, 0);// Dummy values. Set by getInsets()
 57  
 
 58  
 
 59  
    public RiverLayout() {
 60  0
       this(10, 5);
 61  0
    }
 62  
 
 63  0
    public RiverLayout(int hgap, class="keyword">int vgap) {
 64  0
       this.hgap = hgap;
 65  0
       this.vgap = vgap;
 66  0
       setExtraInsets(new Insets(0, hgap, hgap, hgap));
 67  0
    }
 68  
 
 69  
    /**
 70  
     * Gets the horizontal gap between components.
 71  
     */
 72  
    public int getHgap() {
 73  0
        return hgap;
 74  
    }
 75  
 
 76  
    /**
 77  
     * Sets the horizontal gap between components.
 78  
     */
 79  
    public void setHgap(int hgap) {
 80  0
        this.hgap = hgap;
 81  0
    }
 82  
 
 83  
    /**
 84  
     * Gets the vertical gap between components.
 85  
     */
 86  
    public int getVgap() {
 87  0
        return vgap;
 88  
    }
 89  
 
 90  
    public Insets getExtraInsets() {
 91  0
       return extraInsets;
 92  
    }
 93  
 
 94  
    public void setExtraInsets(Insets newExtraInsets) {
 95  0
      extraInsets = newExtraInsets;
 96  0
    }
 97  
 
 98  
    protected Insets getInsets(Container target) {
 99  0
       Insets insets = target.getInsets();
 100  0
       totalInsets.top = insets.top + extraInsets.top;
 101  0
       totalInsets.left = insets.left + extraInsets.left;
 102  0
       totalInsets.bottom = insets.bottom + extraInsets.bottom;
 103  0
       totalInsets.right = insets.right + extraInsets.right;
 104  0
       return totalInsets;
 105  
    }
 106  
 
 107  
    /**
 108  
     * Sets the vertical gap between components.
 109  
     */
 110  
    public void setVgap(int vgap) {
 111  0
        this.vgap = vgap;
 112  0
    }
 113  
 
 114  
 
 115  
    /**
 116  
     * @param name the name of the component
 117  
     * @param comp the component to be added
 118  
     */
 119  
    public void addLayoutComponent(String name, Component comp) {
 120  0
       constraints.put(comp, name);
 121  0
    }
 122  
 
 123  
    /**
 124  
     * Removes the specified component from the layout. Not used by
 125  
     * this class.
 126  
     * @param comp the component to remove
 127  
     * @see       java.awt.Container#removeAll
 128  
     */
 129  
    public void removeLayoutComponent(Component comp) {
 130  0
       constraints.remove(comp);
 131  0
    }
 132  
 
 133  
    boolean isFirstInRow(Component comp) {
 134  0
       String cons = (String) constraints.get(comp);
 135  0
       return cons != null && (cons.indexOf(RiverLayout.LINE_BREAK) != -1 ||
 136  
                               cons.indexOf(RiverLayout.PARAGRAPH_BREAK) != -1);
 137  
    }
 138  
 
 139  
    boolean hasHfill(Component comp) {
 140  0
       return hasConstraint(comp, RiverLayout.HFILL);
 141  
    }
 142  
 
 143  
    boolean hasVfill(Component comp) {
 144  0
       return hasConstraint(comp, RiverLayout.VFILL);
 145  
    }
 146  
 
 147  
    boolean hasConstraint(Component comp, String test) {
 148  0
       String cons = (String) constraints.get(comp);
 149  0
       if (cons == null) return false;
 150  0
       StringTokenizer tokens = new StringTokenizer(cons);
 151  0
       while (tokens.hasMoreTokens())
 152  0
          if (tokens.nextToken().equals(test)) return true;
 153  0
       return false;
 154  
    }
 155  
 
 156  
    /**
 157  
     * Figure out tab stop x-positions
 158  
     */
 159  
    protected Ruler calcTabs(Container target) {
 160  0
       Ruler ruler = new Ruler();
 161  0
       int nmembers = target.getComponentCount();
 162  
 
 163  0
       int x = 0;
 164  0
       int tabIndex = 0; // First tab stop
 165  0
       for (int i = 0; i < nmembers; i++) {
 166  0
          Component m = target.getComponent(i);
 167  
 //         if (m.isVisible()) {
 168  0
             if (isFirstInRow(m) || i == 0) {
 169  0
                x = 0;
 170  0
                tabIndex = 0;
 171  0
             }
 172  0
             else x+= hgap;
 173  0
             if (hasConstraint(m, TAB_STOP)) {
 174  0
                ruler.setTab(tabIndex, x); // Will only increase
 175  0
                x = ruler.getTab(tabIndex++); // Jump forward if neccesary
 176  
             }
 177  0
             Dimension d = m.getPreferredSize();
 178  0
             x += d.width;
 179  
          }
 180  
 //      }
 181  0
       return ruler;
 182  
    }
 183  
 
 184  
    /**
 185  
     * Returns the preferred dimensions for this layout given the
 186  
     * <i>visible</i> components in the specified target container.
 187  
     * @param target the component which needs to be laid out
 188  
     * @return    the preferred dimensions to lay out the
 189  
     *            subcomponents of the specified container
 190  
     * @see Container
 191  
     * @see #minimumLayoutSize
 192  
     * @see       java.awt.Container#getPreferredSize
 193  
     */
 194  
    public Dimension preferredLayoutSize(Container target) {
 195  0
       synchronized (target.getTreeLock()) {
 196  0
          Dimension dim = new Dimension(0, 0);
 197  0
          Dimension rowDim = new Dimension(0, 0);
 198  0
          int nmembers = target.getComponentCount();
 199  0
          boolean firstVisibleComponent = true;
 200  0
          int tabIndex = 0;
 201  0
          Ruler ruler = calcTabs(target);
 202  
 
 203  0
          for (int i = 0; i < nmembers; i++) {
 204  0
             Component m = target.getComponent(i);
 205  
 //            if (m.isVisible()) {
 206  0
                if (isFirstInRow(m)) {
 207  0
                   tabIndex = 0;
 208  0
                   dim.width = Math.max(dim.width, rowDim.width);
 209  0
                   dim.height += rowDim.height + vgap;
 210  0
                   if (hasConstraint(m, PARAGRAPH_BREAK)) dim.height += 2*vgap;
 211  0
                   rowDim = new Dimension(0, 0);
 212  
                }
 213  0
                if (hasConstraint(m, TAB_STOP)) rowDim.width = ruler.getTab(tabIndex++);
 214  0
                Dimension d = m.getPreferredSize();
 215  0
                rowDim.height = Math.max(rowDim.height, d.height);
 216  0
                if (firstVisibleComponent) {
 217  0
                   firstVisibleComponent = false;
 218  0
                }
 219  
                else {
 220  0
                   rowDim.width += hgap;
 221  
                }
 222  0
                rowDim.width += d.width;
 223  
   //          }
 224  
          }
 225  0
          dim.width = Math.max(dim.width, rowDim.width);
 226  0
          dim.height += rowDim.height;
 227  
 
 228  0
          Insets insets = getInsets(target);
 229  0
          dim.width += insets.left + insets.right;// + hgap * 2;
 230  0
          dim.height += insets.top + insets.bottom;// + vgap * 2;
 231  0
          return dim;
 232  0
       }
 233  
    }
 234  
 
 235  
    /**
 236  
     * Returns the minimum dimensions needed to layout the <i>visible</i>
 237  
     * components contained in the specified target container.
 238  
     * @param target the component which needs to be laid out
 239  
     * @return    the minimum dimensions to lay out the
 240  
     *            subcomponents of the specified container
 241  
     * @see #preferredLayoutSize
 242  
     * @see       java.awt.Container
 243  
     * @see       java.awt.Container#doLayout
 244  
     */
 245  
    public Dimension minimumLayoutSize(Container target) {
 246  0
       synchronized (target.getTreeLock()) {
 247  0
          Dimension dim = new Dimension(0, 0);
 248  0
          Dimension rowDim = new Dimension(0, 0);
 249  0
          int nmembers = target.getComponentCount();
 250  0
          boolean firstVisibleComponent = true;
 251  0
          int tabIndex = 0;
 252  0
          Ruler ruler = calcTabs(target);
 253  
 
 254  0
          for (int i = 0; i < nmembers; i++) {
 255  0
             Component m = target.getComponent(i);
 256  
   //          if (m.isVisible()) {
 257  0
                if (isFirstInRow(m)) {
 258  0
                   tabIndex = 0;
 259  0
                   dim.width = Math.max(dim.width, rowDim.width);
 260  0
                   dim.height += rowDim.height + vgap;
 261  0
                   if (hasConstraint(m, PARAGRAPH_BREAK)) dim.height += 2*vgap;
 262  0
                   rowDim = new Dimension(0, 0);
 263  
                }
 264  0
                if (hasConstraint(m, TAB_STOP)) rowDim.width = ruler.getTab(tabIndex++);
 265  0
                Dimension d = m.getMinimumSize();
 266  0
                rowDim.height = Math.max(rowDim.height, d.height);
 267  0
                if (firstVisibleComponent) {
 268  0
                   firstVisibleComponent = false;
 269  0
                }
 270  
                else {
 271  0
                   rowDim.width += hgap;
 272  
                }
 273  0
                rowDim.width += d.width;
 274  
 //            }
 275  
          }
 276  0
          dim.width = Math.max(dim.width, rowDim.width);
 277  0
          dim.height += rowDim.height;
 278  
 
 279  0
          Insets insets = getInsets(target);
 280  0
          dim.width += insets.left + insets.right;// + hgap * 2;
 281  0
          dim.height += insets.top + insets.bottom;// + vgap * 2;
 282  0
          return dim;
 283  0
       }
 284  
    }
 285  
 
 286  
    /**
 287  
     * Centers the elements in the specified row, if there is any slack.
 288  
     * @param target the component which needs to be moved
 289  
     * @param x the x coordinate
 290  
     * @param y the y coordinate
 291  
     * @param width the width dimensions
 292  
     * @param height the height dimensions
 293  
     * @param rowStart the beginning of the row
 294  
     * @param rowEnd the the ending of the row
 295  
     */
 296  
    protected void moveComponents(Container target, int x, class="keyword">int y, class="keyword">int width,
 297  
                                int height,
 298  
                                int rowStart, class="keyword">int rowEnd, boolean ltr, Ruler ruler) {
 299  0
       synchronized (target.getTreeLock()) {
 300  0
          switch (getAlignment()) {
 301  
             case FlowLayout.LEFT:
 302  0
                x += ltr ? 0 : width;
 303  0
                break;
 304  
             case FlowLayout.CENTER:
 305  0
                x += width / 2;
 306  0
                break;
 307  
             case FlowLayout.RIGHT:
 308  0
                x += ltr ? width : 0;
 309  0
                break;
 310  
             case LEADING:
 311  0
                break;
 312  
             case TRAILING:
 313  0
                x += width;
 314  
                break;
 315  
          }
 316  0
          int tabIndex = 0;
 317  0
          for (int i = rowStart; i < rowEnd; i++) {
 318  0
             Component m = target.getComponent(i);
 319  
 //          if (m.isVisible()) {
 320  0
                if (hasConstraint(m, TAB_STOP)) x = getInsets(target).left + ruler.getTab(tabIndex++);
 321  0
                int dy = (valign == VTOP) ? 0 : (height - m.getHeight()) / 2;
 322  0
                if (ltr) {
 323  0
                   m.setLocation(x, y + dy);
 324  0
                }
 325  
                else {
 326  0
                   m.setLocation(target.getWidth() - x - m.getWidth(),
 327  
                                 y + dy);
 328  
                }
 329  0
                x += m.getWidth() + hgap;
 330  
 //            }
 331  
          }
 332  0
       }
 333  0
    }
 334  
 
 335  
 
 336  
    protected void relMove(Container target, int dx, class="keyword">int dy, class="keyword">int rowStart,
 337  
                         int rowEnd) {
 338  0
       synchronized (target.getTreeLock()) {
 339  0
          for (int i = rowStart; i < rowEnd; i++) {
 340  0
             Component m = target.getComponent(i);
 341  
 //            if (m.isVisible()) {
 342  0
                m.setLocation(m.getX() + dx, m.getY() + dy);
 343  
 //            }
 344  
          }
 345  
 
 346  0
       }
 347  0
    }
 348  
 
 349  
    protected void adjustAlignment(Component m) {
 350  0
       if (hasConstraint(m, RiverLayout.LEFT)) setAlignment(FlowLayout.LEFT);
 351  0
       else if (hasConstraint(m, RiverLayout.RIGHT)) setAlignment(FlowLayout.RIGHT);
 352  0
       else if (hasConstraint(m, RiverLayout.CENTER)) setAlignment(FlowLayout.CENTER);
 353  0
       if (hasConstraint(m, RiverLayout.VTOP)) valign = VTOP;
 354  0
       else if (hasConstraint(m, RiverLayout.VCENTER)) valign = VCENTER;
 355  
 
 356  0
    }
 357  
    /**
 358  
     * Lays out the container. This method lets each component take
 359  
     * its preferred size by reshaping the components in the
 360  
     * target container in order to satisfy the constraints of
 361  
     * this <code>FlowLayout</code> object.
 362  
     * @param target the specified component being laid out
 363  
     * @see Container
 364  
     * @see       java.awt.Container#doLayout
 365  
     */
 366  
    public void layoutContainer(Container target) {
 367  0
       setAlignment(FlowLayout.LEFT);
 368  0
       synchronized (target.getTreeLock()) {
 369  0
          Insets insets = getInsets(target);
 370  0
          int maxwidth = target.getWidth() -
 371  
              (insets.left + insets.right);
 372  0
          int maxheight = target.getHeight() -
 373  
              (insets.top + insets.bottom);
 374  
 
 375  0
          int nmembers = target.getComponentCount();
 376  0
          int x = 0, y = insets.top + vgap;
 377  0
          int rowh = 0, start = 0, moveDownStart = 0;
 378  
 
 379  0
          boolean ltr = target.getComponentOrientation().isLeftToRight();
 380  0
          Component toHfill = null;
 381  0
          Component toVfill = null;
 382  0
          Ruler ruler = calcTabs(target);
 383  0
          int tabIndex = 0;
 384  
 
 385  0
          for (int i = 0; i < nmembers; i++) {
 386  0
             Component m = target.getComponent(i);
 387  
             //if (m.isVisible()) {
 388  0
                Dimension d = m.getPreferredSize();
 389  0
                m.setSize(d.width, d.height);
 390  
 
 391  0
                if (isFirstInRow(m)) tabIndex = 0;
 392  0
                if (hasConstraint(m, TAB_STOP)) x = ruler.getTab(tabIndex++);
 393  0
                if (!isFirstInRow(m)) {
 394  0
                   if (i > 0 && !hasConstraint(m, TAB_STOP)) {
 395  0
                      x += hgap;
 396  
                   }
 397  0
                   x += d.width;
 398  0
                   rowh = Math.max(rowh, d.height);
 399  0
                }
 400  
                else {
 401  0
                   if (toVfill != null && moveDownStart == 0) {
 402  0
                      moveDownStart = i;
 403  
                   }
 404  0
                   if (toHfill != null) {
 405  0
                      toHfill.setSize(toHfill.getWidth() + maxwidth - x,
 406  
                                      toHfill.getHeight());
 407  0
                      x = maxwidth;
 408  
                   }
 409  0
                   moveComponents(target, insets.left, y,
 410  
                                  maxwidth - x,
 411  
                                  rowh, start, i, ltr, ruler);
 412  0
                   x = d.width;
 413  0
                   y += vgap + rowh;
 414  0
                   if (hasConstraint(m, PARAGRAPH_BREAK)) y += 2*vgap;
 415  0
                   rowh = d.height;
 416  0
                   start = i;
 417  0
                   toHfill = null;
 418  
                }
 419  
             //}
 420  0
             if (hasHfill(m)) {
 421  0
                toHfill = m;
 422  
             }
 423  0
             if (hasVfill(m)) {
 424  0
                toVfill = m;
 425  
             }
 426  0
             adjustAlignment(m);
 427  
          }
 428  
 
 429  0
          if (toVfill != null && moveDownStart == 0) {  // Don't move anything if hfill component is last component
 430  0
             moveDownStart = nmembers;
 431  
          }
 432  0
          if (toHfill != null) { // last component
 433  0
             toHfill.setSize(toHfill.getWidth() + maxwidth - x,
 434  
                             toHfill.getHeight());
 435  0
             x = maxwidth;
 436  
          }
 437  0
          moveComponents(target, insets.left, y, maxwidth - x, rowh,
 438  
                         start, nmembers, ltr, ruler);
 439  0
          int yslack = maxheight - (y+rowh);
 440  0
          if (yslack > 0 && toVfill != null) {
 441  0
             toVfill.setSize(toVfill.getWidth(), yslack + toVfill.getHeight());
 442  0
             relMove(target, 0, yslack, moveDownStart, nmembers);
 443  
          }
 444  0
       }
 445  0
    }
 446  
 
 447  
 }
 448  
 
 449  
 class Ruler {
 450  
    private Vector tabs = new Vector();
 451  
 
 452  
    public void setTab(int num, class="keyword">int xpos) {
 453  
       if (num >= tabs.size()) tabs.add(num, new Integer(xpos));
 454  
       else {
 455  
          // Transpose all tabs from this tab stop and onwards
 456  
          int delta = xpos - getTab(num);
 457  
          if (delta > 0) {
 458  
             for (int i = num; i < tabs.size(); i++) {
 459  
                tabs.set(i, new Integer(getTab(i) + delta));
 460  
             }
 461  
          }
 462  
       }
 463  
    }
 464  
 
 465  
    public int getTab(class="keyword">int num) {
 466  
       return ((Integer)tabs.get(num)).intValue();
 467  
    }
 468  
 
 469  
    public String toString() {
 470  
       StringBuffer ret = new StringBuffer(getClass().getName() + " {");
 471  
       for (int i=0; i<tabs.size(); i++) {
 472  
          ret.append(tabs.get(i));
 473  
          if (i < tabs.size()-1) ret.append(',');
 474  
       }
 475  
       ret.append('}');
 476  
       return ret.toString();
 477  
    }
 478  
 
 479  
    public static void main(String[] args) {
 480  
       Ruler r = new Ruler();
 481  
       r.setTab(0,10);
 482  
       r.setTab(1,20);
 483  
       r.setTab(2,30);
 484  
       System.out.println(r);
 485  
       r.setTab(1,25);
 486  
       System.out.println(r);
 487  
       System.out.println(r.getTab(0));
 488  
    }
 489  
 }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.