Frames | No Frames |
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: }