Save This Page
Home » openjdk-7 » javax » swing » text » html » [javadoc | source]
    1   /*
    2    * Copyright 1997-2006 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 javax.swing.text.html;
   26   
   27   import java.util.Enumeration;
   28   import java.awt;
   29   import javax.swing.SizeRequirements;
   30   import javax.swing.border;
   31   import javax.swing.event.DocumentEvent;
   32   import javax.swing.text;
   33   
   34   /**
   35    * A view implementation to display a block (as a box)
   36    * with CSS specifications.
   37    *
   38    * @author  Timothy Prinzing
   39    */
   40   public class BlockView extends BoxView  {
   41   
   42       /**
   43        * Creates a new view that represents an
   44        * html box.  This can be used for a number
   45        * of elements.
   46        *
   47        * @param elem the element to create a view for
   48        * @param axis either View.X_AXIS or View.Y_AXIS
   49        */
   50       public BlockView(Element elem, int axis) {
   51           super(elem, axis);
   52       }
   53   
   54       /**
   55        * Establishes the parent view for this view.  This is
   56        * guaranteed to be called before any other methods if the
   57        * parent view is functioning properly.
   58        * <p>
   59        * This is implemented
   60        * to forward to the superclass as well as call the
   61        * {@link #setPropertiesFromAttributes()}
   62        * method to set the paragraph properties from the css
   63        * attributes.  The call is made at this time to ensure
   64        * the ability to resolve upward through the parents
   65        * view attributes.
   66        *
   67        * @param parent the new parent, or null if the view is
   68        *  being removed from a parent it was previously added
   69        *  to
   70        */
   71       public void setParent(View parent) {
   72           super.setParent(parent);
   73           if (parent != null) {
   74               setPropertiesFromAttributes();
   75           }
   76       }
   77   
   78       /**
   79        * Calculate the requirements of the block along the major
   80        * axis (i.e. the axis along with it tiles).  This is implemented
   81        * to provide the superclass behavior and then adjust it if the
   82        * CSS width or height attribute is specified and applicable to
   83        * the axis.
   84        */
   85       protected SizeRequirements calculateMajorAxisRequirements(int axis, SizeRequirements r) {
   86           if (r == null) {
   87               r = new SizeRequirements();
   88           }
   89           if (! spanSetFromAttributes(axis, r, cssWidth, cssHeight)) {
   90               r = super.calculateMajorAxisRequirements(axis, r);
   91           }
   92           else {
   93               // Offset by the margins so that pref/min/max return the
   94               // right value.
   95               SizeRequirements parentR = super.calculateMajorAxisRequirements(
   96                                         axis, null);
   97               int margin = (axis == X_AXIS) ? getLeftInset() + getRightInset() :
   98                                               getTopInset() + getBottomInset();
   99               r.minimum -= margin;
  100               r.preferred -= margin;
  101               r.maximum -= margin;
  102               constrainSize(axis, r, parentR);
  103           }
  104           return r;
  105       }
  106   
  107       /**
  108        * Calculate the requirements of the block along the minor
  109        * axis (i.e. the axis orthoginal to the axis along with it tiles).
  110        * This is implemented
  111        * to provide the superclass behavior and then adjust it if the
  112        * CSS width or height attribute is specified and applicable to
  113        * the axis.
  114        */
  115       protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) {
  116           if (r == null) {
  117               r = new SizeRequirements();
  118           }
  119   
  120           if (! spanSetFromAttributes(axis, r, cssWidth, cssHeight)) {
  121   
  122               /*
  123                * The requirements were not directly specified by attributes, so
  124                * compute the aggregate of the requirements of the children.  The
  125                * children that have a percentage value specified will be treated
  126                * as completely stretchable since that child is not limited in any
  127                * way.
  128                */
  129   /*
  130               int min = 0;
  131               long pref = 0;
  132               int max = 0;
  133               int n = getViewCount();
  134               for (int i = 0; i < n; i++) {
  135                   View v = getView(i);
  136                   min = Math.max((int) v.getMinimumSpan(axis), min);
  137                   pref = Math.max((int) v.getPreferredSpan(axis), pref);
  138                   if (
  139                   max = Math.max((int) v.getMaximumSpan(axis), max);
  140   
  141               }
  142               r.preferred = (int) pref;
  143               r.minimum = min;
  144               r.maximum = max;
  145               */
  146               r = super.calculateMinorAxisRequirements(axis, r);
  147           }
  148           else {
  149               // Offset by the margins so that pref/min/max return the
  150               // right value.
  151               SizeRequirements parentR = super.calculateMinorAxisRequirements(
  152                                         axis, null);
  153               int margin = (axis == X_AXIS) ? getLeftInset() + getRightInset() :
  154                                               getTopInset() + getBottomInset();
  155               r.minimum -= margin;
  156               r.preferred -= margin;
  157               r.maximum -= margin;
  158               constrainSize(axis, r, parentR);
  159           }
  160   
  161           /*
  162            * Set the alignment based upon the CSS properties if it is
  163            * specified.  For X_AXIS this would be text-align, for
  164            * Y_AXIS this would be vertical-align.
  165            */
  166           if (axis == X_AXIS) {
  167               Object o = getAttributes().getAttribute(CSS.Attribute.TEXT_ALIGN);
  168               if (o != null) {
  169                   String align = o.toString();
  170                   if (align.equals("center")) {
  171                       r.alignment = 0.5f;
  172                   } else if (align.equals("right")) {
  173                       r.alignment = 1.0f;
  174                   } else {
  175                       r.alignment = 0.0f;
  176                   }
  177               }
  178           }
  179           // Y_AXIS TBD
  180           return r;
  181       }
  182   
  183       boolean isPercentage(int axis, AttributeSet a) {
  184           if (axis == X_AXIS) {
  185               if (cssWidth != null) {
  186                   return cssWidth.isPercentage();
  187               }
  188           } else {
  189               if (cssHeight != null) {
  190                   return cssHeight.isPercentage();
  191               }
  192           }
  193           return false;
  194       }
  195   
  196       /**
  197        * Adjust the given requirements to the CSS width or height if
  198        * it is specified along the applicable axis.  Return true if the
  199        * size is exactly specified, false if the span is not specified
  200        * in an attribute or the size specified is a percentage.
  201        */
  202       static boolean spanSetFromAttributes(int axis, SizeRequirements r,
  203                                            CSS.LengthValue cssWidth,
  204                                            CSS.LengthValue cssHeight) {
  205           if (axis == X_AXIS) {
  206               if ((cssWidth != null) && (! cssWidth.isPercentage())) {
  207                   r.minimum = r.preferred = r.maximum = (int) cssWidth.getValue();
  208                   return true;
  209               }
  210           } else {
  211               if ((cssHeight != null) && (! cssHeight.isPercentage())) {
  212                   r.minimum = r.preferred = r.maximum = (int) cssHeight.getValue();
  213                   return true;
  214               }
  215           }
  216           return false;
  217       }
  218   
  219       /**
  220        * Performs layout for the minor axis of the box (i.e. the
  221        * axis orthoginal to the axis that it represents). The results
  222        * of the layout (the offset and span for each children) are
  223        * placed in the given arrays which represent the allocations to
  224        * the children along the minor axis.
  225        *
  226        * @param targetSpan the total span given to the view, which
  227        *  whould be used to layout the childre.
  228        * @param axis the axis being layed out
  229        * @param offsets the offsets from the origin of the view for
  230        *  each of the child views; this is a return value and is
  231        *  filled in by the implementation of this method
  232        * @param spans the span of each child view; this is a return
  233        *  value and is filled in by the implementation of this method
  234        */
  235       protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
  236           int n = getViewCount();
  237           Object key = (axis == X_AXIS) ? CSS.Attribute.WIDTH : CSS.Attribute.HEIGHT;
  238           for (int i = 0; i < n; i++) {
  239               View v = getView(i);
  240               int min = (int) v.getMinimumSpan(axis);
  241               int max;
  242   
  243               // check for percentage span
  244               AttributeSet a = v.getAttributes();
  245               CSS.LengthValue lv = (CSS.LengthValue) a.getAttribute(key);
  246               if ((lv != null) && lv.isPercentage()) {
  247                   // bound the span to the percentage specified
  248                   min = Math.max((int) lv.getValue(targetSpan), min);
  249                   max = min;
  250               } else {
  251                   max = (int)v.getMaximumSpan(axis);
  252               }
  253   
  254               // assign the offset and span for the child
  255               if (max < targetSpan) {
  256                   // can't make the child this wide, align it
  257                   float align = v.getAlignment(axis);
  258                   offsets[i] = (int) ((targetSpan - max) * align);
  259                   spans[i] = max;
  260               } else {
  261                   // make it the target width, or as small as it can get.
  262                   offsets[i] = 0;
  263                   spans[i] = Math.max(min, targetSpan);
  264               }
  265           }
  266       }
  267   
  268   
  269       /**
  270        * Renders using the given rendering surface and area on that
  271        * surface.  This is implemented to delegate to the css box
  272        * painter to paint the border and background prior to the
  273        * interior.
  274        *
  275        * @param g the rendering surface to use
  276        * @param allocation the allocated region to render into
  277        * @see View#paint
  278        */
  279       public void paint(Graphics g, Shape allocation) {
  280           Rectangle a = (Rectangle) allocation;
  281           painter.paint(g, a.x, a.y, a.width, a.height, this);
  282           super.paint(g, a);
  283       }
  284   
  285       /**
  286        * Fetches the attributes to use when rendering.  This is
  287        * implemented to multiplex the attributes specified in the
  288        * model with a StyleSheet.
  289        */
  290       public AttributeSet getAttributes() {
  291           if (attr == null) {
  292               StyleSheet sheet = getStyleSheet();
  293               attr = sheet.getViewAttributes(this);
  294           }
  295           return attr;
  296       }
  297   
  298       /**
  299        * Gets the resize weight.
  300        *
  301        * @param axis may be either X_AXIS or Y_AXIS
  302        * @return the weight
  303        * @exception IllegalArgumentException for an invalid axis
  304        */
  305       public int getResizeWeight(int axis) {
  306           switch (axis) {
  307           case View.X_AXIS:
  308               return 1;
  309           case View.Y_AXIS:
  310               return 0;
  311           default:
  312               throw new IllegalArgumentException("Invalid axis: " + axis);
  313           }
  314       }
  315   
  316       /**
  317        * Gets the alignment.
  318        *
  319        * @param axis may be either X_AXIS or Y_AXIS
  320        * @return the alignment
  321        */
  322       public float getAlignment(int axis) {
  323           switch (axis) {
  324           case View.X_AXIS:
  325               return 0;
  326           case View.Y_AXIS:
  327               if (getViewCount() == 0) {
  328                   return 0;
  329               }
  330               float span = getPreferredSpan(View.Y_AXIS);
  331               View v = getView(0);
  332               float above = v.getPreferredSpan(View.Y_AXIS);
  333               float a = (((int)span) != 0) ? (above * v.getAlignment(View.Y_AXIS)) / span: 0;
  334               return a;
  335           default:
  336               throw new IllegalArgumentException("Invalid axis: " + axis);
  337           }
  338       }
  339   
  340       public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
  341           super.changedUpdate(changes, a, f);
  342           int pos = changes.getOffset();
  343           if (pos <= getStartOffset() && (pos + changes.getLength()) >=
  344               getEndOffset()) {
  345               setPropertiesFromAttributes();
  346           }
  347       }
  348   
  349       /**
  350        * Determines the preferred span for this view along an
  351        * axis.
  352        *
  353        * @param axis may be either <code>View.X_AXIS</code>
  354        *           or <code>View.Y_AXIS</code>
  355        * @return   the span the view would like to be rendered into >= 0;
  356        *           typically the view is told to render into the span
  357        *           that is returned, although there is no guarantee;
  358        *           the parent may choose to resize or break the view
  359        * @exception IllegalArgumentException for an invalid axis type
  360        */
  361       public float getPreferredSpan(int axis) {
  362           return super.getPreferredSpan(axis);
  363       }
  364   
  365       /**
  366        * Determines the minimum span for this view along an
  367        * axis.
  368        *
  369        * @param axis may be either <code>View.X_AXIS</code>
  370        *           or <code>View.Y_AXIS</code>
  371        * @return  the span the view would like to be rendered into >= 0;
  372        *           typically the view is told to render into the span
  373        *           that is returned, although there is no guarantee;
  374        *           the parent may choose to resize or break the view
  375        * @exception IllegalArgumentException for an invalid axis type
  376        */
  377       public float getMinimumSpan(int axis) {
  378           return super.getMinimumSpan(axis);
  379       }
  380   
  381       /**
  382        * Determines the maximum span for this view along an
  383        * axis.
  384        *
  385        * @param axis may be either <code>View.X_AXIS</code>
  386        *           or <code>View.Y_AXIS</code>
  387        * @return   the span the view would like to be rendered into >= 0;
  388        *           typically the view is told to render into the span
  389        *           that is returned, although there is no guarantee;
  390        *           the parent may choose to resize or break the view
  391        * @exception IllegalArgumentException for an invalid axis type
  392        */
  393       public float getMaximumSpan(int axis) {
  394           return super.getMaximumSpan(axis);
  395       }
  396   
  397       /**
  398        * Update any cached values that come from attributes.
  399        */
  400       protected void setPropertiesFromAttributes() {
  401   
  402           // update attributes
  403           StyleSheet sheet = getStyleSheet();
  404           attr = sheet.getViewAttributes(this);
  405   
  406           // Reset the painter
  407           painter = sheet.getBoxPainter(attr);
  408           if (attr != null) {
  409               setInsets((short) painter.getInset(TOP, this),
  410                         (short) painter.getInset(LEFT, this),
  411                         (short) painter.getInset(BOTTOM, this),
  412                         (short) painter.getInset(RIGHT, this));
  413           }
  414   
  415           // Get the width/height
  416           cssWidth = (CSS.LengthValue) attr.getAttribute(CSS.Attribute.WIDTH);
  417           cssHeight = (CSS.LengthValue) attr.getAttribute(CSS.Attribute.HEIGHT);
  418       }
  419   
  420       protected StyleSheet getStyleSheet() {
  421           HTMLDocument doc = (HTMLDocument) getDocument();
  422           return doc.getStyleSheet();
  423       }
  424   
  425       /**
  426        * Constrains <code>want</code> to fit in the minimum size specified
  427        * by <code>min</code>.
  428        */
  429       private void constrainSize(int axis, SizeRequirements want,
  430                                  SizeRequirements min) {
  431           if (min.minimum > want.minimum) {
  432               want.minimum = want.preferred = min.minimum;
  433               want.maximum = Math.max(want.maximum, min.maximum);
  434           }
  435       }
  436   
  437       private AttributeSet attr;
  438       private StyleSheet.BoxPainter painter;
  439   
  440       private CSS.LengthValue cssWidth;
  441       private CSS.LengthValue cssHeight;
  442   
  443   }

Save This Page
Home » openjdk-7 » javax » swing » text » html » [javadoc | source]