Home » openjdk-7 » javax » swing » [javadoc | source]

    1   /*
    2    * Copyright (c) 2001, 2005, Oracle and/or its affiliates. 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.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   package javax.swing;
   26   
   27   import java.awt.Component;
   28   
   29   /**
   30    *  An instance of the <code>Spring</code> class holds three properties that
   31    *  characterize its behavior: the <em>minimum</em>, <em>preferred</em>, and
   32    *  <em>maximum</em> values. Each of these properties may be involved in
   33    *  defining its fourth, <em>value</em>, property based on a series of rules.
   34    *  <p>
   35    *  An instance of the <code>Spring</code> class can be visualized as a
   36    *  mechanical spring that provides a corrective force as the spring is compressed
   37    *  or stretched away from its preferred value. This force is modelled
   38    *  as linear function of the distance from the preferred value, but with
   39    *  two different constants -- one for the compressional force and one for the
   40    *  tensional one. Those constants are specified by the minimum and maximum
   41    *  values of the spring such that a spring at its minimum value produces an
   42    *  equal and opposite force to that which is created when it is at its
   43    *  maximum value. The difference between the <em>preferred</em> and
   44    *  <em>minimum</em> values, therefore, represents the ease with which the
   45    *  spring can be compressed and the difference between its <em>maximum</em>
   46    *  and <em>preferred</em> values, indicates the ease with which the
   47    *  <code>Spring</code> can be extended.
   48    *  See the {@link #sum} method for details.
   49    *
   50    *  <p>
   51    *  By defining simple arithmetic operations on <code>Spring</code>s,
   52    *  the behavior of a collection of <code>Spring</code>s
   53    *  can be reduced to that of an ordinary (non-compound) <code>Spring</code>. We define
   54    *  the "+", "-", <em>max</em>, and <em>min</em> operators on
   55    *  <code>Spring</code>s so that, in each case, the result is a <code>Spring</code>
   56    *  whose characteristics bear a useful mathematical relationship to its constituent
   57    *  springs.
   58    *
   59    *  <p>
   60    *  A <code>Spring</code> can be treated as a pair of intervals
   61    *  with a single common point: the preferred value.
   62    *  The following rules define some of the
   63    *  arithmetic operators that can be applied to intervals
   64    *  (<code>[a, b]</code> refers to the interval
   65    *  from <code>a</code>
   66    *  to <code>b</code>,
   67    *  where <code>a &lt;= b</code>).
   68    *  <p>
   69    *  <pre>
   70    *          [a1, b1] + [a2, b2] = [a1 + a2, b1 + b2]
   71    *
   72    *                      -[a, b] = [-b, -a]
   73    *
   74    *      max([a1, b1], [a2, b2]) = [max(a1, a2), max(b1, b2)]
   75    *  </pre>
   76    *  <p>
   77    *
   78    *  If we denote <code>Spring</code>s as <code>[a, b, c]</code>,
   79    *  where <code>a &lt;= b &lt;= c</code>, we can define the same
   80    *  arithmetic operators on <code>Spring</code>s:
   81    *  <p>
   82    *  <pre>
   83    *          [a1, b1, c1] + [a2, b2, c2] = [a1 + a2, b1 + b2, c1 + c2]
   84    *
   85    *                           -[a, b, c] = [-c, -b, -a]
   86    *
   87    *      max([a1, b1, c1], [a2, b2, c2]) = [max(a1, a2), max(b1, b2), max(c1, c2)]
   88    *  </pre>
   89    *  <p>
   90    *  With both intervals and <code>Spring</code>s we can define "-" and <em>min</em>
   91    *  in terms of negation:
   92    *  <p>
   93    *  <pre>
   94    *      X - Y = X + (-Y)
   95    *
   96    *      min(X, Y) = -max(-X, -Y)
   97    *  </pre>
   98    *  <p>
   99    *  For the static methods in this class that embody the arithmetic
  100    *  operators, we do not actually perform the operation in question as
  101    *  that would snapshot the values of the properties of the method's arguments
  102    *  at the time the static method is called. Instead, the static methods
  103    *  create a new <code>Spring</code> instance containing references to
  104    *  the method's arguments so that the characteristics of the new spring track the
  105    *  potentially changing characteristics of the springs from which it
  106    *  was made. This is a little like the idea of a <em>lazy value</em>
  107    *  in a functional language.
  108    * <p>
  109    * If you are implementing a <code>SpringLayout</code> you
  110    * can find further information and examples in
  111    * <a
  112    href="http://java.sun.com/docs/books/tutorial/uiswing/layout/spring.html">How to Use SpringLayout</a>,
  113    * a section in <em>The Java Tutorial.</em>
  114    * <p>
  115    * <strong>Warning:</strong>
  116    * Serialized objects of this class will not be compatible with
  117    * future Swing releases. The current serialization support is
  118    * appropriate for short term storage or RMI between applications running
  119    * the same version of Swing.  As of 1.4, support for long term storage
  120    * of all JavaBeans<sup><font size="-2">TM</font></sup>
  121    * has been added to the <code>java.beans</code> package.
  122    * Please see {@link java.beans.XMLEncoder}.
  123    *
  124    * @see SpringLayout
  125    * @see SpringLayout.Constraints
  126    *
  127    * @author      Philip Milne
  128    * @since       1.4
  129    */
  130   public abstract class Spring {
  131   
  132       /**
  133        * An integer value signifying that a property value has not yet been calculated.
  134        */
  135       public static final int UNSET = Integer.MIN_VALUE;
  136   
  137       /**
  138        * Used by factory methods to create a <code>Spring</code>.
  139        *
  140        * @see #constant(int)
  141        * @see #constant(int, int, int)
  142        * @see #max
  143        * @see #minus
  144        * @see #sum
  145        * @see SpringLayout.Constraints
  146        */
  147       protected Spring() {}
  148   
  149       /**
  150        * Returns the <em>minimum</em> value of this <code>Spring</code>.
  151        *
  152        * @return the <code>minimumValue</code> property of this <code>Spring</code>
  153        */
  154       public abstract int getMinimumValue();
  155   
  156       /**
  157        * Returns the <em>preferred</em> value of this <code>Spring</code>.
  158        *
  159        * @return the <code>preferredValue</code> of this <code>Spring</code>
  160        */
  161       public abstract int getPreferredValue();
  162   
  163       /**
  164        * Returns the <em>maximum</em> value of this <code>Spring</code>.
  165        *
  166        * @return the <code>maximumValue</code> property of this <code>Spring</code>
  167        */
  168       public abstract int getMaximumValue();
  169   
  170       /**
  171        * Returns the current <em>value</em> of this <code>Spring</code>.
  172        *
  173        * @return  the <code>value</code> property of this <code>Spring</code>
  174        *
  175        * @see #setValue
  176        */
  177       public abstract int getValue();
  178   
  179       /**
  180        * Sets the current <em>value</em> of this <code>Spring</code> to <code>value</code>.
  181        *
  182        * @param   value the new setting of the <code>value</code> property
  183        *
  184        * @see #getValue
  185        */
  186       public abstract void setValue(int value);
  187   
  188       private double range(boolean contract) {
  189           return contract ? (getPreferredValue() - getMinimumValue()) :
  190                             (getMaximumValue() - getPreferredValue());
  191       }
  192   
  193       /*pp*/ double getStrain() {
  194           double delta = (getValue() - getPreferredValue());
  195           return delta/range(getValue() < getPreferredValue());
  196       }
  197   
  198       /*pp*/ void setStrain(double strain) {
  199           setValue(getPreferredValue() + (int)(strain * range(strain < 0)));
  200       }
  201   
  202       /*pp*/ boolean isCyclic(SpringLayout l) {
  203           return false;
  204       }
  205   
  206       /*pp*/ static abstract class AbstractSpring extends Spring {
  207           protected int size = UNSET;
  208   
  209           public int getValue() {
  210               return size != UNSET ? size : getPreferredValue();
  211           }
  212   
  213           public final void setValue(int size) {
  214               if (this.size == size) {
  215                   return;
  216               }
  217               if (size == UNSET) {
  218                   clear();
  219               } else {
  220                   setNonClearValue(size);
  221               }
  222           }
  223   
  224           protected void clear() {
  225               size = UNSET;
  226           }
  227   
  228           protected void setNonClearValue(int size) {
  229               this.size = size;
  230           }
  231       }
  232   
  233       private static class StaticSpring extends AbstractSpring {
  234           protected int min;
  235           protected int pref;
  236           protected int max;
  237   
  238           public StaticSpring(int pref) {
  239               this(pref, pref, pref);
  240           }
  241   
  242           public StaticSpring(int min, int pref, int max) {
  243               this.min = min;
  244               this.pref = pref;
  245               this.max = max;
  246           }
  247   
  248            public String toString() {
  249                return "StaticSpring [" + min + ", " + pref + ", " + max + "]";
  250            }
  251   
  252            public int getMinimumValue() {
  253               return min;
  254           }
  255   
  256           public int getPreferredValue() {
  257               return pref;
  258           }
  259   
  260           public int getMaximumValue() {
  261               return max;
  262           }
  263       }
  264   
  265       private static class NegativeSpring extends Spring {
  266           private Spring s;
  267   
  268           public NegativeSpring(Spring s) {
  269               this.s = s;
  270           }
  271   
  272   // Note the use of max value rather than minimum value here.
  273   // See the opening preamble on arithmetic with springs.
  274   
  275           public int getMinimumValue() {
  276               return -s.getMaximumValue();
  277           }
  278   
  279           public int getPreferredValue() {
  280               return -s.getPreferredValue();
  281           }
  282   
  283           public int getMaximumValue() {
  284               return -s.getMinimumValue();
  285           }
  286   
  287           public int getValue() {
  288               return -s.getValue();
  289           }
  290   
  291           public void setValue(int size) {
  292               // No need to check for UNSET as
  293               // Integer.MIN_VALUE == -Integer.MIN_VALUE.
  294               s.setValue(-size);
  295           }
  296   
  297           /*pp*/ boolean isCyclic(SpringLayout l) {
  298               return s.isCyclic(l);
  299           }
  300       }
  301   
  302       private static class ScaleSpring extends Spring {
  303           private Spring s;
  304           private float factor;
  305   
  306           private ScaleSpring(Spring s, float factor) {
  307               this.s = s;
  308               this.factor = factor;
  309           }
  310   
  311           public int getMinimumValue() {
  312               return Math.round((factor < 0 ? s.getMaximumValue() : s.getMinimumValue()) * factor);
  313           }
  314   
  315           public int getPreferredValue() {
  316               return Math.round(s.getPreferredValue() * factor);
  317           }
  318   
  319           public int getMaximumValue() {
  320               return Math.round((factor < 0 ? s.getMinimumValue() : s.getMaximumValue()) * factor);
  321           }
  322   
  323           public int getValue() {
  324               return Math.round(s.getValue() * factor);
  325           }
  326   
  327           public void setValue(int value) {
  328               if (value == UNSET) {
  329                   s.setValue(UNSET);
  330               } else {
  331                   s.setValue(Math.round(value / factor));
  332               }
  333           }
  334   
  335           /*pp*/ boolean isCyclic(SpringLayout l) {
  336               return s.isCyclic(l);
  337           }
  338       }
  339   
  340       /*pp*/ static class WidthSpring extends AbstractSpring {
  341           /*pp*/ Component c;
  342   
  343           public WidthSpring(Component c) {
  344               this.c = c;
  345           }
  346   
  347           public int getMinimumValue() {
  348               return c.getMinimumSize().width;
  349           }
  350   
  351           public int getPreferredValue() {
  352               return c.getPreferredSize().width;
  353           }
  354   
  355           public int getMaximumValue() {
  356               // We will be doing arithmetic with the results of this call,
  357               // so if a returned value is Integer.MAX_VALUE we will get
  358               // arithmetic overflow. Truncate such values.
  359               return Math.min(Short.MAX_VALUE, c.getMaximumSize().width);
  360           }
  361       }
  362   
  363        /*pp*/  static class HeightSpring extends AbstractSpring {
  364           /*pp*/ Component c;
  365   
  366           public HeightSpring(Component c) {
  367               this.c = c;
  368           }
  369   
  370           public int getMinimumValue() {
  371               return c.getMinimumSize().height;
  372           }
  373   
  374           public int getPreferredValue() {
  375               return c.getPreferredSize().height;
  376           }
  377   
  378           public int getMaximumValue() {
  379               return Math.min(Short.MAX_VALUE, c.getMaximumSize().height);
  380           }
  381       }
  382   
  383      /*pp*/ static abstract class SpringMap extends Spring {
  384          private Spring s;
  385   
  386          public SpringMap(Spring s) {
  387              this.s = s;
  388          }
  389   
  390          protected abstract int map(int i);
  391   
  392          protected abstract int inv(int i);
  393   
  394          public int getMinimumValue() {
  395              return map(s.getMinimumValue());
  396          }
  397   
  398          public int getPreferredValue() {
  399              return map(s.getPreferredValue());
  400          }
  401   
  402          public int getMaximumValue() {
  403              return Math.min(Short.MAX_VALUE, map(s.getMaximumValue()));
  404          }
  405   
  406          public int getValue() {
  407              return map(s.getValue());
  408          }
  409   
  410          public void setValue(int value) {
  411              if (value == UNSET) {
  412                  s.setValue(UNSET);
  413              } else {
  414                  s.setValue(inv(value));
  415              }
  416          }
  417   
  418          /*pp*/ boolean isCyclic(SpringLayout l) {
  419              return s.isCyclic(l);
  420          }
  421      }
  422   
  423   // Use the instance variables of the StaticSpring superclass to
  424   // cache values that have already been calculated.
  425       /*pp*/ static abstract class CompoundSpring extends StaticSpring {
  426           protected Spring s1;
  427           protected Spring s2;
  428   
  429           public CompoundSpring(Spring s1, Spring s2) {
  430               super(UNSET);
  431               this.s1 = s1;
  432               this.s2 = s2;
  433           }
  434   
  435           public String toString() {
  436               return "CompoundSpring of " + s1 + " and " + s2;
  437           }
  438   
  439           protected void clear() {
  440               super.clear();
  441               min = pref = max = UNSET;
  442               s1.setValue(UNSET);
  443               s2.setValue(UNSET);
  444           }
  445   
  446           protected abstract int op(int x, int y);
  447   
  448           public int getMinimumValue() {
  449               if (min == UNSET) {
  450                   min = op(s1.getMinimumValue(), s2.getMinimumValue());
  451               }
  452               return min;
  453           }
  454   
  455           public int getPreferredValue() {
  456               if (pref == UNSET) {
  457                   pref = op(s1.getPreferredValue(), s2.getPreferredValue());
  458               }
  459               return pref;
  460           }
  461   
  462           public int getMaximumValue() {
  463               if (max == UNSET) {
  464                   max = op(s1.getMaximumValue(), s2.getMaximumValue());
  465               }
  466               return max;
  467           }
  468   
  469           public int getValue() {
  470               if (size == UNSET) {
  471                   size = op(s1.getValue(), s2.getValue());
  472               }
  473               return size;
  474           }
  475   
  476           /*pp*/ boolean isCyclic(SpringLayout l) {
  477               return l.isCyclic(s1) || l.isCyclic(s2);
  478           }
  479       };
  480   
  481        private static class SumSpring extends CompoundSpring {
  482            public SumSpring(Spring s1, Spring s2) {
  483                super(s1, s2);
  484            }
  485   
  486            protected int op(int x, int y) {
  487                return x + y;
  488            }
  489   
  490            protected void setNonClearValue(int size) {
  491                super.setNonClearValue(size);
  492                s1.setStrain(this.getStrain());
  493                s2.setValue(size - s1.getValue());
  494            }
  495        }
  496   
  497       private static class MaxSpring extends CompoundSpring {
  498   
  499           public MaxSpring(Spring s1, Spring s2) {
  500               super(s1, s2);
  501           }
  502   
  503           protected int op(int x, int y) {
  504               return Math.max(x, y);
  505           }
  506   
  507           protected void setNonClearValue(int size) {
  508               super.setNonClearValue(size);
  509               s1.setValue(size);
  510               s2.setValue(size);
  511           }
  512       }
  513   
  514       /**
  515        * Returns a strut -- a spring whose <em>minimum</em>, <em>preferred</em>, and
  516        * <em>maximum</em> values each have the value <code>pref</code>.
  517        *
  518        * @param  pref the <em>minimum</em>, <em>preferred</em>, and
  519        *         <em>maximum</em> values of the new spring
  520        * @return a spring whose <em>minimum</em>, <em>preferred</em>, and
  521        *         <em>maximum</em> values each have the value <code>pref</code>
  522        *
  523        * @see Spring
  524        */
  525        public static Spring constant(int pref) {
  526            return constant(pref, pref, pref);
  527        }
  528   
  529       /**
  530        * Returns a spring whose <em>minimum</em>, <em>preferred</em>, and
  531        * <em>maximum</em> values have the values: <code>min</code>, <code>pref</code>,
  532        * and <code>max</code> respectively.
  533        *
  534        * @param  min the <em>minimum</em> value of the new spring
  535        * @param  pref the <em>preferred</em> value of the new spring
  536        * @param  max the <em>maximum</em> value of the new spring
  537        * @return a spring whose <em>minimum</em>, <em>preferred</em>, and
  538        *         <em>maximum</em> values have the values: <code>min</code>, <code>pref</code>,
  539        *         and <code>max</code> respectively
  540        *
  541        * @see Spring
  542        */
  543        public static Spring constant(int min, int pref, int max) {
  544            return new StaticSpring(min, pref, max);
  545        }
  546   
  547   
  548       /**
  549        * Returns <code>-s</code>: a spring running in the opposite direction to <code>s</code>.
  550        *
  551        * @return <code>-s</code>: a spring running in the opposite direction to <code>s</code>
  552        *
  553        * @see Spring
  554        */
  555       public static Spring minus(Spring s) {
  556           return new NegativeSpring(s);
  557       }
  558   
  559       /**
  560        * Returns <code>s1+s2</code>: a spring representing <code>s1</code> and <code>s2</code>
  561        * in series. In a sum, <code>s3</code>, of two springs, <code>s1</code> and <code>s2</code>,
  562        * the <em>strains</em> of <code>s1</code>, <code>s2</code>, and <code>s3</code> are maintained
  563        * at the same level (to within the precision implied by their integer <em>value</em>s).
  564        * The strain of a spring in compression is:
  565        * <pre>
  566        *         value - pref
  567        *         ------------
  568        *          pref - min
  569        * </pre>
  570        * and the strain of a spring in tension is:
  571        * <pre>
  572        *         value - pref
  573        *         ------------
  574        *          max - pref
  575        * </pre>
  576        * When <code>setValue</code> is called on the sum spring, <code>s3</code>, the strain
  577        * in <code>s3</code> is calculated using one of the formulas above. Once the strain of
  578        * the sum is known, the <em>value</em>s of <code>s1</code> and <code>s2</code> are
  579        * then set so that they are have a strain equal to that of the sum. The formulas are
  580        * evaluated so as to take rounding errors into account and ensure that the sum of
  581        * the <em>value</em>s of <code>s1</code> and <code>s2</code> is exactly equal to
  582        * the <em>value</em> of <code>s3</code>.
  583        *
  584        * @return <code>s1+s2</code>: a spring representing <code>s1</code> and <code>s2</code> in series
  585        *
  586        * @see Spring
  587        */
  588        public static Spring sum(Spring s1, Spring s2) {
  589            return new SumSpring(s1, s2);
  590        }
  591   
  592       /**
  593        * Returns <code>max(s1, s2)</code>: a spring whose value is always greater than (or equal to)
  594        *         the values of both <code>s1</code> and <code>s2</code>.
  595        *
  596        * @return <code>max(s1, s2)</code>: a spring whose value is always greater than (or equal to)
  597        *         the values of both <code>s1</code> and <code>s2</code>
  598        * @see Spring
  599        */
  600       public static Spring max(Spring s1, Spring s2) {
  601           return new MaxSpring(s1, s2);
  602       }
  603   
  604       // Remove these, they're not used often and can be created using minus -
  605       // as per these implementations.
  606   
  607       /*pp*/ static Spring difference(Spring s1, Spring s2) {
  608           return sum(s1, minus(s2));
  609       }
  610   
  611       /*
  612       public static Spring min(Spring s1, Spring s2) {
  613           return minus(max(minus(s1), minus(s2)));
  614       }
  615       */
  616   
  617       /**
  618        * Returns a spring whose <em>minimum</em>, <em>preferred</em>, <em>maximum</em>
  619        * and <em>value</em> properties are each multiples of the properties of the
  620        * argument spring, <code>s</code>. Minimum and maximum properties are
  621        * swapped when <code>factor</code> is negative (in accordance with the
  622        * rules of interval arithmetic).
  623        * <p>
  624        * When factor is, for example, 0.5f the result represents 'the mid-point'
  625        * of its input - an operation that is useful for centering components in
  626        * a container.
  627        *
  628        * @param s the spring to scale
  629        * @param factor amount to scale by.
  630        * @return  a spring whose properties are those of the input spring <code>s</code>
  631        * multiplied by <code>factor</code>
  632        * @throws NullPointerException if <code>s</code> is null
  633        * @since 1.5
  634        */
  635       public static Spring scale(Spring s, float factor) {
  636           checkArg(s);
  637           return new ScaleSpring(s, factor);
  638       }
  639   
  640       /**
  641        * Returns a spring whose <em>minimum</em>, <em>preferred</em>, <em>maximum</em>
  642        * and <em>value</em> properties are defined by the widths of the <em>minimumSize</em>,
  643        * <em>preferredSize</em>, <em>maximumSize</em> and <em>size</em> properties
  644        * of the supplied component. The returned spring is a 'wrapper' implementation
  645        * whose methods call the appropriate size methods of the supplied component.
  646        * The minimum, preferred, maximum and value properties of the returned spring
  647        * therefore report the current state of the appropriate properties in the
  648        * component and track them as they change.
  649        *
  650        * @param c Component used for calculating size
  651        * @return  a spring whose properties are defined by the horizontal component
  652        * of the component's size methods.
  653        * @throws NullPointerException if <code>c</code> is null
  654        * @since 1.5
  655        */
  656       public static Spring width(Component c) {
  657           checkArg(c);
  658           return new WidthSpring(c);
  659       }
  660   
  661       /**
  662        * Returns a spring whose <em>minimum</em>, <em>preferred</em>, <em>maximum</em>
  663        * and <em>value</em> properties are defined by the heights of the <em>minimumSize</em>,
  664        * <em>preferredSize</em>, <em>maximumSize</em> and <em>size</em> properties
  665        * of the supplied component. The returned spring is a 'wrapper' implementation
  666        * whose methods call the appropriate size methods of the supplied component.
  667        * The minimum, preferred, maximum and value properties of the returned spring
  668        * therefore report the current state of the appropriate properties in the
  669        * component and track them as they change.
  670        *
  671        * @param c Component used for calculating size
  672        * @return  a spring whose properties are defined by the vertical component
  673        * of the component's size methods.
  674        * @throws NullPointerException if <code>c</code> is null
  675        * @since 1.5
  676        */
  677       public static Spring height(Component c) {
  678           checkArg(c);
  679           return new HeightSpring(c);
  680       }
  681   
  682   
  683       /**
  684        * If <code>s</code> is null, this throws an NullPointerException.
  685        */
  686       private static void checkArg(Object s) {
  687           if (s == null) {
  688               throw new NullPointerException("Argument must not be null");
  689           }
  690       }
  691   }

Home » openjdk-7 » javax » swing » [javadoc | source]