Save This Page
Home » jcommon-1.0.13 » org.jfree » chart » block » [javadoc | source]
    1   /* ===========================================================
    2    * JFreeChart : a free chart library for the Java(tm) platform
    3    * ===========================================================
    4    *
    5    * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
    6    *
    7    * Project Info:  http://www.jfree.org/jfreechart/index.html
    8    *
    9    * This library is free software; you can redistribute it and/or modify it 
   10    * under the terms of the GNU Lesser General Public License as published by 
   11    * the Free Software Foundation; either version 2.1 of the License, or 
   12    * (at your option) any later version.
   13    *
   14    * This library is distributed in the hope that it will be useful, but 
   15    * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
   16    * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
   17    * License for more details.
   18    *
   19    * You should have received a copy of the GNU Lesser General Public
   20    * License along with this library; if not, write to the Free Software
   21    * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
   22    * USA.  
   23    *
   24    * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
   25    * in the United States and other countries.]
   26    *
   27    * --------------------
   28    * FlowArrangement.java
   29    * --------------------
   30    * (C) Copyright 2004-2007, by Object Refinery Limited.
   31    *
   32    * Original Author:  David Gilbert (for Object Refinery Limited);
   33    * Contributor(s):   -;
   34    *
   35    * Changes:
   36    * --------
   37    * 22-Oct-2004 : Version 1 (DG);
   38    * 04-Feb-2005 : Implemented equals() and made serializable (DG);
   39    * 08-Feb-2005 : Updated for changes in RectangleConstraint (DG);
   40    * 
   41    */
   42   
   43   package org.jfree.chart.block;
   44   
   45   import java.awt.Graphics2D;
   46   import java.awt.geom.Rectangle2D;
   47   import java.io.Serializable;
   48   import java.util.ArrayList;
   49   import java.util.List;
   50   
   51   import org.jfree.ui.HorizontalAlignment;
   52   import org.jfree.ui.Size2D;
   53   import org.jfree.ui.VerticalAlignment;
   54   
   55   /**
   56    * Arranges blocks in a flow layout.  This class is immutable.
   57    */
   58   public class FlowArrangement implements Arrangement, Serializable {
   59   
   60       /** For serialization. */
   61       private static final long serialVersionUID = 4543632485478613800L;
   62       
   63       /** The horizontal alignment of blocks. */
   64       private HorizontalAlignment horizontalAlignment;
   65       
   66       /** The vertical alignment of blocks within each row. */
   67       private VerticalAlignment verticalAlignment;
   68       
   69       /** The horizontal gap between items within rows. */
   70       private double horizontalGap;
   71       
   72       /** The vertical gap between rows. */
   73       private double verticalGap;
   74       
   75       /**
   76        * Creates a new instance.
   77        */
   78       public FlowArrangement() {   
   79           this(HorizontalAlignment.CENTER, VerticalAlignment.CENTER, 2.0, 2.0);
   80       }
   81        
   82       /**
   83        * Creates a new instance.
   84        * 
   85        * @param hAlign  the horizontal alignment (currently ignored).
   86        * @param vAlign  the vertical alignment (currently ignored).
   87        * @param hGap  the horizontal gap.
   88        * @param vGap  the vertical gap.
   89        */
   90       public FlowArrangement(HorizontalAlignment hAlign, VerticalAlignment vAlign,
   91                              double hGap, double vGap) {   
   92           this.horizontalAlignment = hAlign;
   93           this.verticalAlignment = vAlign;
   94           this.horizontalGap = hGap;
   95           this.verticalGap = vGap;
   96       }
   97       
   98       /**
   99        * Adds a block to be managed by this instance.  This method is usually 
  100        * called by the {@link BlockContainer}, you shouldn't need to call it 
  101        * directly.
  102        * 
  103        * @param block  the block.
  104        * @param key  a key that controls the position of the block.
  105        */
  106       public void add(Block block, Object key) {
  107           // since the flow layout is relatively straightforward, 
  108           // no information needs to be recorded here
  109       }
  110       
  111       /**
  112        * Calculates and sets the bounds of all the items in the specified 
  113        * container, subject to the given constraint.  The <code>Graphics2D</code>
  114        * can be used by some items (particularly items containing text) to 
  115        * calculate sizing parameters.
  116        * 
  117        * @param container  the container whose items are being arranged.
  118        * @param constraint  the size constraint.
  119        * @param g2  the graphics device.
  120        * 
  121        * @return The size of the container after arrangement of the contents.
  122        */
  123       public Size2D arrange(BlockContainer container, Graphics2D g2,
  124                             RectangleConstraint constraint) {
  125           
  126           LengthConstraintType w = constraint.getWidthConstraintType();
  127           LengthConstraintType h = constraint.getHeightConstraintType();
  128           if (w == LengthConstraintType.NONE) {
  129               if (h == LengthConstraintType.NONE) {
  130                   return arrangeNN(container, g2);  
  131               }
  132               else if (h == LengthConstraintType.FIXED) {
  133                   return arrangeNF(container, g2, constraint);  
  134               }
  135               else if (h == LengthConstraintType.RANGE) {
  136                   throw new RuntimeException("Not implemented.");  
  137               }
  138           }
  139           else if (w == LengthConstraintType.FIXED) {
  140               if (h == LengthConstraintType.NONE) {
  141                   return arrangeFN(container, g2, constraint);  
  142               }
  143               else if (h == LengthConstraintType.FIXED) {
  144                   return arrangeFF(container, g2, constraint);  
  145               }
  146               else if (h == LengthConstraintType.RANGE) {
  147                   return arrangeFR(container, g2, constraint);  
  148               }
  149           }
  150           else if (w == LengthConstraintType.RANGE) {
  151               if (h == LengthConstraintType.NONE) {
  152                   return arrangeRN(container, g2, constraint);  
  153               }
  154               else if (h == LengthConstraintType.FIXED) {
  155                   return arrangeRF(container, g2, constraint);  
  156               }
  157               else if (h == LengthConstraintType.RANGE) {
  158                   return arrangeRR(container, g2, constraint);   
  159               }
  160           }
  161           throw new RuntimeException("Unrecognised constraint type.");
  162           
  163       }
  164   
  165       /**
  166        * Arranges the blocks in the container with a fixed width and no height 
  167        * constraint.
  168        * 
  169        * @param container  the container.
  170        * @param constraint  the constraint.
  171        * @param g2  the graphics device.
  172        * 
  173        * @return The size.
  174        */
  175       protected Size2D arrangeFN(BlockContainer container, Graphics2D g2,
  176                                  RectangleConstraint constraint) {
  177           
  178           List blocks = container.getBlocks();
  179           double width = constraint.getWidth();
  180           
  181           double x = 0.0;
  182           double y = 0.0;
  183           double maxHeight = 0.0;
  184           List itemsInRow = new ArrayList();
  185           for (int i = 0; i < blocks.size(); i++) {
  186               Block block = (Block) blocks.get(i);
  187               Size2D size = block.arrange(g2, RectangleConstraint.NONE);
  188               if (x + size.width <= width) {
  189                   itemsInRow.add(block);
  190                   block.setBounds(
  191                       new Rectangle2D.Double(x, y, size.width, size.height)
  192                   );
  193                   x = x + size.width + this.horizontalGap;
  194                   maxHeight = Math.max(maxHeight, size.height);
  195               }
  196               else {
  197                   if (itemsInRow.isEmpty()) {
  198                       // place in this row (truncated) anyway
  199                       block.setBounds(
  200                           new Rectangle2D.Double(
  201                               x, y, Math.min(size.width, width - x), size.height
  202                           )
  203                       );
  204                       x = 0.0;
  205                       y = y + size.height + this.verticalGap;
  206                   }
  207                   else {
  208                       // start new row
  209                       itemsInRow.clear();
  210                       x = 0.0;
  211                       y = y + maxHeight + this.verticalGap;
  212                       maxHeight = size.height;
  213                       block.setBounds(
  214                           new Rectangle2D.Double(
  215                               x, y, Math.min(size.width, width), size.height
  216                           )
  217                       );
  218                       x = size.width + this.horizontalGap;
  219                       itemsInRow.add(block);
  220                   }
  221               }
  222           }
  223           return new Size2D(constraint.getWidth(), y + maxHeight);  
  224       }
  225       
  226       /**
  227        * Arranges the blocks in the container with a fixed width and a range
  228        * constraint on the height.
  229        * 
  230        * @param container  the container.
  231        * @param constraint  the constraint.
  232        * @param g2  the graphics device.
  233        * 
  234        * @return The size following the arrangement.
  235        */
  236       protected Size2D arrangeFR(BlockContainer container, Graphics2D g2,
  237                                  RectangleConstraint constraint) {
  238   
  239           Size2D s = arrangeFN(container, g2, constraint);
  240           if (constraint.getHeightRange().contains(s.height)) {
  241               return s;   
  242           }
  243           else {
  244               RectangleConstraint c = constraint.toFixedHeight(
  245                   constraint.getHeightRange().constrain(s.getHeight())
  246               );
  247               return arrangeFF(container, g2, c);
  248           }
  249       }
  250   
  251       /**
  252        * Arranges the blocks in the container with the overall height and width
  253        * specified as fixed constraints.
  254        * 
  255        * @param container  the container.
  256        * @param constraint  the constraint.
  257        * @param g2  the graphics device.
  258        * 
  259        * @return The size following the arrangement.
  260        */
  261       protected Size2D arrangeFF(BlockContainer container, Graphics2D g2,
  262                                  RectangleConstraint constraint) {
  263   
  264           // TODO: implement this properly
  265           return arrangeFN(container, g2, constraint);
  266       }
  267   
  268       /**
  269        * Arranges the blocks with the overall width and height to fit within 
  270        * specified ranges.
  271        * 
  272        * @param container  the container.
  273        * @param constraint  the constraint.
  274        * @param g2  the graphics device.
  275        * 
  276        * @return The size after the arrangement.
  277        */
  278       protected Size2D arrangeRR(BlockContainer container, Graphics2D g2,
  279                                  RectangleConstraint constraint) {
  280   
  281           // first arrange without constraints, and see if this fits within
  282           // the required ranges...
  283           Size2D s1 = arrangeNN(container, g2);
  284           if (constraint.getWidthRange().contains(s1.width)) {
  285               return s1;  // TODO: we didn't check the height yet
  286           }
  287           else {
  288               RectangleConstraint c = constraint.toFixedWidth(
  289                   constraint.getWidthRange().getUpperBound()
  290               );
  291               return arrangeFR(container, g2, c);
  292           }
  293       }
  294       
  295       /**
  296        * Arranges the blocks in the container with a range constraint on the
  297        * width and a fixed height.
  298        * 
  299        * @param container  the container.
  300        * @param constraint  the constraint.
  301        * @param g2  the graphics device.
  302        * 
  303        * @return The size following the arrangement.
  304        */
  305       protected Size2D arrangeRF(BlockContainer container, Graphics2D g2,
  306                                  RectangleConstraint constraint) {
  307   
  308           Size2D s = arrangeNF(container, g2, constraint);
  309           if (constraint.getWidthRange().contains(s.width)) {
  310               return s;   
  311           }
  312           else {
  313               RectangleConstraint c = constraint.toFixedWidth(
  314                   constraint.getWidthRange().constrain(s.getWidth())
  315               );
  316               return arrangeFF(container, g2, c);
  317           }
  318       }
  319   
  320       /**
  321        * Arranges the block with a range constraint on the width, and no 
  322        * constraint on the height.
  323        * 
  324        * @param container  the container.
  325        * @param constraint  the constraint.
  326        * @param g2  the graphics device.
  327        * 
  328        * @return The size following the arrangement.
  329        */
  330       protected Size2D arrangeRN(BlockContainer container, Graphics2D g2,
  331                                  RectangleConstraint constraint) {
  332           // first arrange without constraints, then see if the width fits
  333           // within the required range...if not, call arrangeFN() at max width
  334           Size2D s1 = arrangeNN(container, g2);
  335           if (constraint.getWidthRange().contains(s1.width)) {
  336               return s1;   
  337           }
  338           else {
  339               RectangleConstraint c = constraint.toFixedWidth(
  340                   constraint.getWidthRange().getUpperBound()
  341               );
  342               return arrangeFN(container, g2, c);
  343           }
  344       }
  345       
  346       /**
  347        * Arranges the blocks without any constraints.  This puts all blocks
  348        * into a single row.
  349        * 
  350        * @param container  the container.
  351        * @param g2  the graphics device.
  352        * 
  353        * @return The size after the arrangement.
  354        */
  355       protected Size2D arrangeNN(BlockContainer container, Graphics2D g2) {
  356           double x = 0.0;
  357           double width = 0.0;
  358           double maxHeight = 0.0;
  359           List blocks = container.getBlocks();
  360           int blockCount = blocks.size();
  361           if (blockCount > 0) {
  362               Size2D[] sizes = new Size2D[blocks.size()];
  363               for (int i = 0; i < blocks.size(); i++) {
  364                   Block block = (Block) blocks.get(i);
  365                   sizes[i] = block.arrange(g2, RectangleConstraint.NONE);
  366                   width = width + sizes[i].getWidth();
  367                   maxHeight = Math.max(sizes[i].height, maxHeight);
  368                   block.setBounds(
  369                       new Rectangle2D.Double(
  370                           x, 0.0, sizes[i].width, sizes[i].height
  371                       )
  372                   );
  373                   x = x + sizes[i].width + this.horizontalGap;
  374               }
  375               if (blockCount > 1) {
  376                   width = width + this.horizontalGap * (blockCount - 1);   
  377               }
  378               if (this.verticalAlignment != VerticalAlignment.TOP) {
  379                   for (int i = 0; i < blocks.size(); i++) {
  380                       //Block b = (Block) blocks.get(i);
  381                       if (this.verticalAlignment == VerticalAlignment.CENTER) {
  382                           //TODO: shift block down by half
  383                       }
  384                       else if (this.verticalAlignment 
  385                               == VerticalAlignment.BOTTOM) {
  386                           //TODO: shift block down to bottom
  387                       }
  388                   }            
  389               }
  390           }
  391           return new Size2D(width, maxHeight);
  392       }
  393       
  394       /**
  395        * Arranges the blocks with no width constraint and a fixed height 
  396        * constraint.  This puts all blocks into a single row.
  397        * 
  398        * @param container  the container.
  399        * @param constraint  the constraint.
  400        * @param g2  the graphics device.
  401        * 
  402        * @return The size after the arrangement.
  403        */
  404       protected Size2D arrangeNF(BlockContainer container, Graphics2D g2,
  405                                  RectangleConstraint constraint) {
  406           // TODO: for now we are ignoring the height constraint
  407           return arrangeNN(container, g2);
  408       }
  409       
  410       /**
  411        * Clears any cached information.
  412        */
  413       public void clear() {
  414           // no action required.
  415       }
  416       
  417       /**
  418        * Tests this instance for equality with an arbitrary object.
  419        * 
  420        * @param obj  the object (<code>null</code> permitted).
  421        * 
  422        * @return A boolean.
  423        */
  424       public boolean equals(Object obj) {
  425           if (obj == this) {
  426               return true;   
  427           }
  428           if (!(obj instanceof FlowArrangement)) {
  429               return false;   
  430           }
  431           FlowArrangement that = (FlowArrangement) obj;
  432           if (this.horizontalAlignment != that.horizontalAlignment) {
  433               return false;
  434           }
  435           if (this.verticalAlignment != that.verticalAlignment) {
  436               return false;
  437           }
  438           if (this.horizontalGap != that.horizontalGap) {
  439               return false;   
  440           }
  441           if (this.verticalGap != that.verticalGap) {
  442               return false;   
  443           }
  444           return true;
  445       }
  446       
  447   }

Save This Page
Home » jcommon-1.0.13 » org.jfree » chart » block » [javadoc | source]