Source for javax.swing.Spring

   1: /* Spring.java --
   2:    Copyright (C) 2004 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: package javax.swing;
  39: 
  40: import java.awt.Component;
  41: import java.awt.Dimension;
  42: 
  43: /**
  44:  * Calculates the space between component edges, that are layed out by
  45:  * {@link SpringLayout}.
  46:  * <p>
  47:  * A Spring defines a minimum, preferred and maximum distance for each edge
  48:  * (north, east, south, west) of a component.
  49:  * </p>
  50:  * However, springs are not static, their actual values are computed at
  51:  * runtime. That means, if a Spring C is defined as the sum of Spring A and
  52:  * Spring B, then the values (min, pref and max) are not calculated at
  53:  * creation of Spring C, but instead always when {@link #getValue} is
  54:  * called. So, when Spring A or Spring B changes, this is reflected in
  55:  * Spring C.
  56:  *
  57:  * @author Roman Kennke (roman@ontographics.com)
  58:  */
  59: public abstract class Spring
  60: {
  61: 
  62:   /** Indicates a not-set value. **/
  63:   public static final int UNSET = Integer.MIN_VALUE;
  64: 
  65:   /**
  66:    * Creates a new Spring object. This constructor is used by the static
  67:    * methods which create Springs.
  68:    */
  69:   protected Spring()
  70:   {
  71:     // Nothing to do here.
  72:   }
  73: 
  74:   /**
  75:    * Creates a Spring which min, pref and max values are all the same.
  76:    * These kind of Springs are 'struts'.
  77:    *
  78:    * @param val the constant for min, pref and max values.
  79:    * @return a Spring object with constant values for min, pref and max.
  80:    */
  81:   public static Spring constant(int val)
  82:   {
  83:     return new SimpleSpring(val, val, val);
  84:   }
  85: 
  86:   /** Creates a Spring which min, pref and max values are constants.
  87:    * @param min the constant for the minimum value.
  88:    * @param pref the constant for the preferred value.
  89:    * @param max the constant for the maximum value.
  90:    * @return a Spring object with constant values for min, pref and max.
  91:    */
  92:   public static Spring constant(int min, int pref, int max)
  93:   {
  94:     return new SimpleSpring(min, pref, max);
  95:   }
  96: 
  97:   /**
  98:    * Returns the maximum value of the Spring.
  99:    *
 100:    * @return the maximum value.
 101:    */
 102:   public abstract int getMaximumValue();
 103: 
 104:   /**
 105:    * Returns the minimum value of this Spring.
 106:    *
 107:    * @return the minimum value.
 108:    */
 109:   public abstract int getMinimumValue();
 110: 
 111:   /**
 112:    * Return the preferred value of this Spring.
 113:    *
 114:    * @return the preferred value.
 115:    */
 116:   public abstract int getPreferredValue();
 117: 
 118:   /**
 119:    * Return the actual value of this Spring.
 120:    *
 121:    * @return the actual value of this Spring.
 122:    */
 123:   public abstract int getValue();
 124: 
 125:   /**
 126:    * Creates and returns a Spring, which always has the maximum values
 127:    * min = max(min_s1, min_s2), pref = max(pref_s1, pref_s2), max =
 128:    * max(max_s1, max_s2).
 129:    *
 130:    * @param s1 the first summand of the max Spring.
 131:    * @param s2 the second summand of the max Spring.
 132:    * @return a Spring which is max(s1, s2).
 133:    */
 134:   public static Spring max(Spring s1, Spring s2)
 135:   {
 136:     return new MaxSpring(s1, s2);
 137:   }
 138: 
 139:   /**
 140:    * Creates and returns a Spring, which is always the negation of s.
 141:    * min = -min_s, pref = -pref_s, max = -max_pref.
 142:    *
 143:    * @param s the Spring to be negated.
 144:    * @return the negative of <code>s</code>.
 145:    */
 146:   public static Spring minus(Spring s)
 147:   {
 148:     return new MinusSpring(s);
 149:   }
 150: 
 151:   /**
 152:    * Sets the actual value. If <code>value</code> is out of the (min, max)
 153:    * bounds, then the value is adjusted, so that is inside these bounds.
 154:    *
 155:    * @param value the value to be set.
 156:    */
 157:   public abstract void setValue(int value);
 158: 
 159:   private int getShrinkRange()
 160:   {
 161:     return (getPreferredValue() - getMinimumValue());
 162:   }
 163: 
 164:   private int getExpandRange()
 165:   {
 166:     return (getMaximumValue() - getPreferredValue());
 167:   }
 168: 
 169:   double getStrain()
 170:   {
 171:     int v = getValue();
 172:     int p = getPreferredValue();
 173:     int r = (v < p) ? getShrinkRange() : getExpandRange();
 174:     if (r == 0)
 175:       r = 1;
 176:     return (double)(v - p) / r;
 177:   }
 178: 
 179:   void setStrain(double strain)
 180:   {
 181:     int r = (strain < 0) ? getShrinkRange() : getExpandRange();
 182:     int v = (getPreferredValue() + (int)(strain * r));
 183:     setValue(v);
 184:   }
 185: 
 186:   /**
 187:    * Creates and returns a Spring, which is always the sum of s1 and s2.
 188:    * min_sum = min_s1 + min_s2, pref_sum = pref_s1 + pref_s2, max_sum =
 189:    * max_s1 + max_s2.
 190:    *
 191:    * @param s1 the 1st summand of the sum Spring.
 192:    * @param s2 the 2nd summand of the sum Spring.
 193:    * @return a sum which is <code>s1 + s2</code>.
 194:    */
 195:   public static Spring sum(Spring s1, Spring s2)
 196:   {
 197:     return new AddSpring(s1, s2);
 198:   }
 199: 
 200:   /**
 201:    * Return a new Spring which computes its values by scaling
 202:    * the values of another spring by a constant factor.  If the
 203:    * factor is negative, the minimum and maximum values of
 204:    * the argument spring will be interchanged.
 205:    * @param spring the spring to track
 206:    * @param factor the factor by which to scale
 207:    * @return a new multiplicative Spring
 208:    * @since 1.5
 209:    */
 210:   public static Spring scale(final Spring spring, final float factor)
 211:   {
 212:     if (spring == null)
 213:       throw new NullPointerException("spring argument is null");
 214:     return new Spring()
 215:     {
 216:       public int getMaximumValue()
 217:       {
 218:         return (int) ((factor < 0 ? spring.getMinimumValue()
 219:                             : spring.getMaximumValue())
 220:                       * factor);
 221:       }
 222: 
 223:       public int getMinimumValue()
 224:       {
 225:         return (int) ((factor < 0 ? spring.getMaximumValue()
 226:                                   : spring.getMinimumValue())
 227:                             * factor);
 228:       }
 229: 
 230:       public int getPreferredValue()
 231:       {
 232:         return (int) (spring.getPreferredValue() * factor);
 233:       }
 234: 
 235:       public int getValue()
 236:       {
 237:         return (int) (spring.getValue() * factor);
 238:       }
 239: 
 240:       public void setValue(int value)
 241:       {
 242:         spring.setValue((int) (value / factor));
 243:       }
 244:     };
 245:   }
 246: 
 247:   /**
 248:    * Return a new Spring which takes its values from the specified
 249:    * Component.  In particular, the maximum value is taken from
 250:    * the maximumSize, the minimum value is taken from the minimumSize,
 251:    * the preferred value is taken from the preferredSize, and the
 252:    * value is taken from the component's current size.  These values
 253:    * change as the component changes size.
 254:    * @param component the component
 255:    * @return a new Spring which tracks the component's width
 256:    * @since 1.5
 257:    */
 258:   public static Spring width(final Component component)
 259:   {
 260:     return new Spring()
 261:     {
 262:       public int getMaximumValue()
 263:       {
 264:         return component.getMaximumSize().width;
 265:       }
 266: 
 267:       public int getMinimumValue()
 268:       {
 269:         return component.getMinimumSize().width;
 270:       }
 271: 
 272:       public int getPreferredValue()
 273:       {
 274:         return component.getPreferredSize().width;
 275:       }
 276: 
 277:       public int getValue()
 278:       {
 279:         return component.getSize().width;
 280:       }
 281: 
 282:       public void setValue(int value)
 283:       {
 284:         Dimension d = component.getSize();
 285:         component.setSize(value, d.height);
 286:       }
 287:     };
 288:   }
 289: 
 290:   /**
 291:    * Return a new Spring which takes its values from the specified
 292:    * Component.  In particular, the maximum value is taken from
 293:    * the maximumSize, the minimum value is taken from the minimumSize,
 294:    * the preferred value is taken from the preferredSize, and the
 295:    * value is taken from the component's current size.  These values
 296:    * change as the component changes size.
 297:    * @param component the component
 298:    * @return a new Spring which tracks the component's height
 299:    * @since 1.5
 300:    */
 301:   public static Spring height(final Component component)
 302:   {
 303:     return new Spring()
 304:     {
 305:       public int getMaximumValue()
 306:       {
 307:         return component.getMaximumSize().height;
 308:       }
 309: 
 310:       public int getMinimumValue()
 311:       {
 312:         return component.getMinimumSize().height;
 313:       }
 314: 
 315:       public int getPreferredValue()
 316:       {
 317:         return component.getPreferredSize().height;
 318:       }
 319: 
 320:       public int getValue()
 321:       {
 322:         return component.getSize().height;
 323:       }
 324: 
 325:       public void setValue(int value)
 326:       {
 327:         Dimension d = component.getSize();
 328:         component.setSize(d.width, value);
 329:       }
 330:     };
 331:   }
 332: 
 333:   /**
 334:    * A simple Spring, that holds constant values for min, pref and max.
 335:    *
 336:    * @author Roman Kennke (roman@ontographics.com)
 337:    */
 338:   private static final class SimpleSpring extends Spring
 339:   {
 340: 
 341:     /** The constant value for min. */
 342:     private final int min;
 343: 
 344:     /** The constant value for pref. */
 345:     private final int pref;
 346: 
 347:     /** The constant value for max. */
 348:     private final int max;
 349: 
 350:     /** The actual value of the spring. */
 351:     private int value;
 352: 
 353:     public String toString()
 354:     {
 355:       return "SimpleSpring of " + value;
 356:     }
 357: 
 358:     /**
 359:      * Creates a new SimpleSpring object.
 360:      *
 361:      * @param newMin the constant minimum value.
 362:      * @param newPref the constant preferred value.
 363:      * @param newMax the constant maximum value.
 364:      */
 365:     public SimpleSpring(int newMin, int newPref, int newMax)
 366:     {
 367:       min = newMin;
 368:       pref = newPref;
 369:       max = newMax;
 370:       value = newPref;
 371:     }
 372: 
 373:     /**
 374:      * Returns the maximum value of this Spring.
 375:      *
 376:      * @return the maximum value.
 377:      */
 378:     public int getMaximumValue()
 379:     {
 380:       return max;
 381:     }
 382: 
 383:     /**
 384:      * Returns the minimum value of this Spring.
 385:      *
 386:      * @return the minimum value.
 387:      */
 388:     public int getMinimumValue()
 389:     {
 390:       return min;
 391:     }
 392: 
 393:     /**
 394:      * Returns the preferred value of this Spring.
 395:      *
 396:      * @return the preferred value.
 397:      */
 398:     public int getPreferredValue()
 399:     {
 400:       return pref;
 401:     }
 402: 
 403:     /**
 404:      * Return the actual current value of this Spring.
 405:      *
 406:      * @return the current value.
 407:      */
 408:     public int getValue()
 409:     {
 410:       if (value == Spring.UNSET)
 411:           return pref;
 412:       return value;
 413:     }
 414: 
 415:     /**
 416:      * Sets the current value.
 417:      *
 418:      * @param val the value to be set.
 419:      */
 420:     public void setValue(int val)
 421:     {
 422:       value = val;
 423:     }
 424:   }
 425: 
 426: 
 427:   /**
 428:    * A Spring, that is the sum of two other Springs.
 429:    *
 430:    * @author Roman Kennke (roman@ontographics.com)
 431:    */
 432:   private static final class AddSpring extends Spring
 433:   {
 434: 
 435:     /** The springs, that are the 'operands' of this Spring. */
 436:     private final Spring s1;
 437:     private final Spring s2;
 438: 
 439:     /** The current value for this Spring. */
 440:     private int value;
 441: 
 442:     public String toString()
 443:     {
 444:       return "AddSpring of " + s1 + " and " + s2;
 445:     }
 446: 
 447:     /**
 448:      * Creates a new AddSpring object.
 449:      *
 450:      * @param s1 the first operand.
 451:      * @param s2 the second operand.
 452:      */
 453:     protected AddSpring(Spring s1, Spring s2)
 454:     {
 455:       super();
 456:       this.s1 = s1;
 457:       this.s2 = s2;
 458:       value = Spring.UNSET;
 459:     }
 460: 
 461:     /**
 462:      * Returns the maximum value of this Spring.
 463:      *
 464:      * @return the maximum value.
 465:      */
 466:     public int getMaximumValue()
 467:     {
 468:       int max1 = s1.getMaximumValue();
 469:       int max2 = s2.getMaximumValue();
 470:       return max1 + max2;
 471:     }
 472: 
 473:     /**
 474:      * Return the minimum value of this Spring.
 475:      *
 476:      * @return the minimum value.
 477:      */
 478:     public int getMinimumValue()
 479:     {
 480:       int min1 = s1.getMinimumValue();
 481:       int min2 = s2.getMinimumValue();
 482:       return min1 + min2;
 483:     }
 484: 
 485:     /**
 486:      * Returns the preferred value of this Spring.
 487:      *
 488:      * @return the preferred value.
 489:      */
 490:     public int getPreferredValue()
 491:     {
 492:       int pref1 = s1.getPreferredValue();
 493:       int pref2 = s2.getPreferredValue();
 494:       return pref1 + pref2;
 495:     }
 496: 
 497:     /**
 498:      * Returns the actual current value of this Spring.
 499:      *
 500:      * @return the current value of this Spring.
 501:      */
 502:     public int getValue()
 503:     {
 504:       if (value == Spring.UNSET)
 505:         {
 506:           int val1 = s1.getValue();
 507:           int val2 = s2.getValue();
 508:           value = val1 + val2;
 509:         }
 510:       return value;
 511:     }
 512: 
 513:     /**
 514:      * Sets the current value.
 515:      *
 516:      * @param val the value to be set.
 517:      */
 518:     public void setValue(int val)
 519:     {
 520:       if (val == Spring.UNSET)
 521:       {
 522:         if (value != Spring.UNSET)
 523:         {
 524:           s1.setValue(Spring.UNSET);
 525:           s2.setValue(Spring.UNSET);
 526:         }
 527:         value = Spring.UNSET;
 528:         return;
 529:       }
 530: 
 531:       value = val;
 532: 
 533:       //Spead the value over the two components
 534:       double fStrain = getStrain();
 535:       s1.setStrain(fStrain);
 536:       int remainder = val - s1.getValue();
 537:       s2.setValue(remainder);
 538:     }
 539: 
 540:   }
 541: 
 542: 
 543:   /**
 544:    * A Spring that is calculated as the negation of another Spring.
 545:    *
 546:    * @author Roman Kennke (roman@ontographics.com)
 547:    */
 548:   private static final class MinusSpring extends Spring
 549:   {
 550: 
 551:     /** The Spring from which to calculate the negation. */
 552:     private final Spring s;
 553: 
 554:     public String toString()
 555:     {
 556:       return "MinusSpring of " + s;
 557:     }
 558: 
 559:     /**
 560:      * Creates a new MinusSpring object.
 561:      * @param s the Spring from which to calculate the negation.
 562:      */
 563:     protected MinusSpring(Spring s)
 564:     {
 565:       super();
 566:       this.s = s;
 567:     }
 568: 
 569:     /** Returns the maximum value of this Spring.
 570:      *
 571:      * @return the maximum value.
 572:      */
 573:     public int getMaximumValue()
 574:     {
 575:       return -s.getMinimumValue();
 576:     }
 577: 
 578:     /**
 579:      * Returns the minimum value of this Spring.
 580:      *
 581:      * @return the minimum value.
 582:      */
 583:     public int getMinimumValue()
 584:     {
 585:       return -s.getMaximumValue();
 586:     }
 587: 
 588:     /**
 589:      * Returns the preferred value of this Spring.
 590:      *
 591:      * @return the preferred value.
 592:      */
 593:     public int getPreferredValue()
 594:     {
 595:       return -s.getPreferredValue();
 596:     }
 597: 
 598:     /**
 599:      * Returns the current value of this Spring.
 600:      *
 601:      * @return the current value.
 602:      */
 603:     public int getValue()
 604:     {
 605:       return -s.getValue();
 606:     }
 607: 
 608:     /**
 609:      * Sets the current value.
 610:      *
 611:      * @param val the value to be set.
 612:      */
 613:     public void setValue(int val)
 614:     {
 615:       if (val == Spring.UNSET)
 616:         s.setValue(Spring.UNSET);
 617:       else
 618:         s.setValue(-val);
 619:     }
 620:   }
 621: 
 622: 
 623:   /**
 624:    * A Spring, that is calculated as the maximum of two Springs.
 625:    *
 626:    * @author Roman Kennke (roman@ontographics.com)
 627:    */
 628:   private static final class MaxSpring extends Spring
 629:   {
 630: 
 631:     /** The two other Springs from which to calculate the maximum. */
 632:     private final Spring s1;
 633:     private final Spring s2;
 634: 
 635:     public String toString()
 636:     {
 637:       return "MaxSpring of " + s1 + " and " + s2;
 638:     }
 639: 
 640:     /** The current value of this Spring. */
 641:     private int value;
 642: 
 643:     /**
 644:      * Creates a new MaxSpring object.
 645:      *
 646:      * @param s1 the 1st operand.
 647:      * @param s2 the 2nd operand.
 648:      */
 649:     protected MaxSpring(Spring s1, Spring s2)
 650:     {
 651:       super();
 652:       this.s1 = s1;
 653:       this.s2 = s2;
 654:       value = Spring.UNSET;
 655:     }
 656: 
 657: 
 658:     /**
 659:      * Returns the maximum value of this Spring.
 660:      *
 661:      * @return the maximum value.
 662:      */
 663:     public int getMaximumValue()
 664:     {
 665:       int max1 = s1.getMaximumValue();
 666:       int max2 = s2.getMaximumValue();
 667:       return Math.max(max1, max2);
 668:     }
 669: 
 670:     /**
 671:      * Returns the minimum value of this Spring.
 672:      *
 673:      * @return the minimum value.
 674:      */
 675:     public int getMinimumValue()
 676:     {
 677:       int min1 = s1.getMinimumValue();
 678:       int min2 = s2.getMinimumValue();
 679:       return Math.max(min1, min2);
 680:     }
 681: 
 682:     /**
 683:      * Returns the preferred value of this Spring.
 684:      *
 685:      * @return the preferred value.
 686:      */
 687:     public int getPreferredValue()
 688:     {
 689:       int pref1 = s1.getPreferredValue();
 690:       int pref2 = s2.getPreferredValue();
 691:       return Math.max(pref1, pref2);
 692:     }
 693: 
 694:     /**
 695:      * Returns the actual value of this Spring.
 696:      *
 697:      * @return the current value.
 698:      */
 699:     public int getValue()
 700:     {
 701:       if (value == Spring.UNSET)
 702:       {
 703:           int val1 = s1.getValue();
 704:           int val2 = s2.getValue();
 705:           value = Math.max(val1, val2);
 706:       }
 707:       return value;
 708:     }
 709: 
 710:     /**
 711:      * Sets the current value.
 712:      *
 713:      * @param val the value to be set.
 714:      */
 715:     public void setValue(int val)
 716:     {
 717:       if (val == Spring.UNSET)
 718:       {
 719:         if (value != Spring.UNSET)
 720:         {
 721:           s1.setValue(Spring.UNSET);
 722:           s2.setValue(Spring.UNSET);
 723:         }
 724:         value = Spring.UNSET;
 725:         return;
 726:       }
 727: 
 728:       value = val;
 729: 
 730:       int p1 = s1.getPreferredValue();
 731:       int p2 = s2.getPreferredValue();
 732: 
 733:       if (p1 < p2)
 734:       {
 735:         s1.setValue(Math.min(val, p1));
 736:         s2.setValue(val);
 737:       }
 738:       else
 739:       {
 740:         s1.setValue(val);
 741:         s2.setValue(Math.min(val, p2));
 742:       }
 743:     }
 744:   }
 745: }