1 /* 2 * Copyright (c) 2010, 2016, 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 26 package javafx.beans.binding; 27 28 import java.lang.ref.WeakReference; 29 30 import javafx.beans.InvalidationListener; 31 import javafx.beans.NamedArg; 32 import javafx.beans.Observable; 33 import javafx.beans.value.ObservableBooleanValue; 34 import javafx.beans.value.ObservableDoubleValue; 35 import javafx.beans.value.ObservableFloatValue; 36 import javafx.beans.value.ObservableLongValue; 37 import javafx.beans.value.ObservableNumberValue; 38 import javafx.beans.value.ObservableObjectValue; 39 import javafx.beans.value.ObservableStringValue; 40 import javafx.beans.value.ObservableValue; 41 import javafx.collections.FXCollections; 42 import javafx.collections.ObservableList; 43 44 import com.sun.javafx.binding.DoubleConstant; 45 import com.sun.javafx.binding.FloatConstant; 46 import com.sun.javafx.binding.IntegerConstant; 47 import com.sun.javafx.binding.Logging; 48 import com.sun.javafx.binding.LongConstant; 49 50 /** 51 * Starting point for a binding that calculates a ternary expression. 52 * <p> 53 * A ternary expression has the basic form 54 * {@code new When(cond).then(value1).otherwise(value2);}. The expression 55 * {@code cond} needs to be a {@link javafx.beans.value.ObservableBooleanValue}. 56 * Based on the value of {@code cond}, the binding contains the value of 57 * {@code value1} (if {@code cond.getValue() == true}) or {@code value2} (if 58 * {@code cond.getValue() == false}). The values {@code value1} and 59 * {@code value2} have to be of the same type. They can be constant values or 60 * implementations of {@link javafx.beans.value.ObservableValue}. 61 * @since JavaFX 2.0 62 */ 63 public class When { 64 private final ObservableBooleanValue condition; 65 66 /** 67 * The constructor of {@code When}. 68 * 69 * @param condition 70 * the condition of the ternary expression 71 */ 72 public When(final @NamedArg("condition") ObservableBooleanValue condition) { 73 if (condition == null) { 74 throw new NullPointerException("Condition must be specified."); 75 } 76 this.condition = condition; 77 } 78 79 private static class WhenListener implements InvalidationListener { 80 81 private final ObservableBooleanValue condition; 82 private final ObservableValue<?> thenValue; 83 private final ObservableValue<?> otherwiseValue; 84 private final WeakReference<Binding<?>> ref; 85 86 private WhenListener(Binding<?> binding, ObservableBooleanValue condition, ObservableValue<?> thenValue, ObservableValue<?> otherwiseValue) { 87 this.ref = new WeakReference<Binding<?>>(binding); 88 this.condition = condition; 89 this.thenValue = thenValue; 90 this.otherwiseValue = otherwiseValue; 91 } 92 93 @Override 94 public void invalidated(Observable observable) { 95 final Binding<?> binding = ref.get(); 96 if (binding == null) { 97 condition.removeListener(this); 98 if (thenValue != null) { 99 thenValue.removeListener(this); 100 } 101 if (otherwiseValue != null) { 102 otherwiseValue.removeListener(this); 103 } 104 } else { 105 // short-circuit invalidation. This Binding becomes 106 // only invalid if the condition changes or the 107 // active branch. 108 if (condition.equals(observable) || (binding.isValid() && (condition.get() == observable.equals(thenValue)))) { 109 binding.invalidate(); 110 } 111 } 112 } 113 114 } 115 116 private static NumberBinding createNumberCondition( 117 final ObservableBooleanValue condition, 118 final ObservableNumberValue thenValue, 119 final ObservableNumberValue otherwiseValue) { 120 if ((thenValue instanceof ObservableDoubleValue) || (otherwiseValue instanceof ObservableDoubleValue)) { 121 return new DoubleBinding() { 122 final InvalidationListener observer = new WhenListener(this, condition, thenValue, otherwiseValue); 123 { 124 condition.addListener(observer); 125 thenValue.addListener(observer); 126 otherwiseValue.addListener(observer); 127 } 128 129 @Override 130 public void dispose() { 131 condition.removeListener(observer); 132 thenValue.removeListener(observer); 133 otherwiseValue.removeListener(observer); 134 } 135 136 @Override 137 protected double computeValue() { 138 final boolean conditionValue = condition.get(); 139 Logging.getLogger().finest("Condition of ternary binding expression was evaluated: {0}", conditionValue); 140 return conditionValue ? thenValue.doubleValue() : otherwiseValue.doubleValue(); 141 } 142 143 @Override 144 public ObservableList<ObservableValue<?>> getDependencies() { 145 return FXCollections.unmodifiableObservableList( 146 FXCollections.<ObservableValue<?>> observableArrayList(condition, thenValue, otherwiseValue)); 147 } 148 }; 149 } else if ((thenValue instanceof ObservableFloatValue) || (otherwiseValue instanceof ObservableFloatValue)) { 150 return new FloatBinding() { 151 final InvalidationListener observer = new WhenListener(this, condition, thenValue, otherwiseValue); 152 { 153 condition.addListener(observer); 154 thenValue.addListener(observer); 155 otherwiseValue.addListener(observer); 156 } 157 158 @Override 159 public void dispose() { 160 condition.removeListener(observer); 161 thenValue.removeListener(observer); 162 otherwiseValue.removeListener(observer); 163 } 164 165 @Override 166 protected float computeValue() { 167 final boolean conditionValue = condition.get(); 168 Logging.getLogger().finest("Condition of ternary binding expression was evaluated: {0}", conditionValue); 169 return conditionValue ? thenValue.floatValue() : otherwiseValue.floatValue(); 170 } 171 172 @Override 173 public ObservableList<ObservableValue<?>> getDependencies() { 174 return FXCollections.unmodifiableObservableList( 175 FXCollections.<ObservableValue<?>> observableArrayList(condition, thenValue, otherwiseValue)); 176 } 177 }; 178 } else if ((thenValue instanceof ObservableLongValue) || (otherwiseValue instanceof ObservableLongValue)) { 179 return new LongBinding() { 180 final InvalidationListener observer = new WhenListener(this, condition, thenValue, otherwiseValue); 181 { 182 condition.addListener(observer); 183 thenValue.addListener(observer); 184 otherwiseValue.addListener(observer); 185 } 186 187 @Override 188 public void dispose() { 189 condition.removeListener(observer); 190 thenValue.removeListener(observer); 191 otherwiseValue.removeListener(observer); 192 } 193 194 @Override 195 protected long computeValue() { 196 final boolean conditionValue = condition.get(); 197 Logging.getLogger().finest("Condition of ternary binding expression was evaluated: {0}", conditionValue); 198 return conditionValue ? thenValue.longValue() : otherwiseValue.longValue(); 199 } 200 201 @Override 202 public ObservableList<ObservableValue<?>> getDependencies() { 203 return FXCollections.unmodifiableObservableList( 204 FXCollections.<ObservableValue<?>> observableArrayList(condition, thenValue, otherwiseValue)); 205 } 206 }; 207 } else { 208 return new IntegerBinding() { 209 final InvalidationListener observer = new WhenListener(this, condition, thenValue, otherwiseValue); 210 { 211 condition.addListener(observer); 212 thenValue.addListener(observer); 213 otherwiseValue.addListener(observer); 214 } 215 216 @Override 217 public void dispose() { 218 condition.removeListener(observer); 219 thenValue.removeListener(observer); 220 otherwiseValue.removeListener(observer); 221 } 222 223 @Override 224 protected int computeValue() { 225 final boolean conditionValue = condition.get(); 226 Logging.getLogger().finest("Condition of ternary binding expression was evaluated: {0}", conditionValue); 227 return conditionValue ? thenValue.intValue(): otherwiseValue.intValue(); 228 } 229 230 @Override 231 public ObservableList<ObservableValue<?>> getDependencies() { 232 return FXCollections.unmodifiableObservableList( 233 FXCollections.<ObservableValue<?>> observableArrayList(condition, thenValue, otherwiseValue)); 234 } 235 }; 236 } 237 } 238 239 /** 240 * If-then-else expression returning a number. 241 * @since JavaFX 2.0 242 */ 243 public class NumberConditionBuilder { 244 245 private ObservableNumberValue thenValue; 246 247 private NumberConditionBuilder(final ObservableNumberValue thenValue) { 248 this.thenValue = thenValue; 249 } 250 251 /** 252 * Defines the {@link javafx.beans.value.ObservableNumberValue} which 253 * value is returned by the ternary expression if the condition is 254 * {@code false}. 255 * 256 * @param otherwiseValue 257 * the value 258 * @return the complete {@link DoubleBinding} 259 */ 260 public NumberBinding otherwise(ObservableNumberValue otherwiseValue) { 261 if (otherwiseValue == null) { 262 throw new NullPointerException("Value needs to be specified"); 263 } 264 return When.createNumberCondition(condition, thenValue, otherwiseValue); 265 } 266 267 /** 268 * Defines a constant value of the ternary expression, that is returned 269 * if the condition is {@code false}. 270 * 271 * @param otherwiseValue 272 * the value 273 * @return the complete {@link DoubleBinding} 274 */ 275 public DoubleBinding otherwise(double otherwiseValue) { 276 return (DoubleBinding) otherwise(DoubleConstant.valueOf(otherwiseValue)); 277 } 278 279 /** 280 * Defines a constant value of the ternary expression, that is returned 281 * if the condition is {@code false}. 282 * 283 * @param otherwiseValue 284 * the value 285 * @return the complete {@link NumberBinding} 286 */ 287 public NumberBinding otherwise(float otherwiseValue) { 288 return otherwise(FloatConstant.valueOf(otherwiseValue)); 289 } 290 291 /** 292 * Defines a constant value of the ternary expression, that is returned 293 * if the condition is {@code false}. 294 * 295 * @param otherwiseValue 296 * the value 297 * @return the complete {@link NumberBinding} 298 */ 299 public NumberBinding otherwise(long otherwiseValue) { 300 return otherwise(LongConstant.valueOf(otherwiseValue)); 301 } 302 303 /** 304 * Defines a constant value of the ternary expression, that is returned 305 * if the condition is {@code false}. 306 * 307 * @param otherwiseValue 308 * the value 309 * @return the complete {@link NumberBinding} 310 */ 311 public NumberBinding otherwise(int otherwiseValue) { 312 return otherwise(IntegerConstant.valueOf(otherwiseValue)); 313 } 314 } 315 316 /** 317 * Defines the {@link javafx.beans.value.ObservableNumberValue} which value 318 * is returned by the ternary expression if the condition is {@code true}. 319 * 320 * @param thenValue 321 * the value 322 * @return the intermediate result which still requires the otherwise-branch 323 */ 324 public NumberConditionBuilder then(final ObservableNumberValue thenValue) { 325 if (thenValue == null) { 326 throw new NullPointerException("Value needs to be specified"); 327 } 328 return new NumberConditionBuilder(thenValue); 329 } 330 331 /** 332 * Defines a constant value of the ternary expression, that is returned if 333 * the condition is {@code true}. 334 * 335 * @param thenValue 336 * the value 337 * @return the intermediate result which still requires the otherwise-branch 338 */ 339 public NumberConditionBuilder then(double thenValue) { 340 return new NumberConditionBuilder(DoubleConstant.valueOf(thenValue)); 341 } 342 343 /** 344 * Defines a constant value of the ternary expression, that is returned if 345 * the condition is {@code true}. 346 * 347 * @param thenValue 348 * the value 349 * @return the intermediate result which still requires the otherwise-branch 350 */ 351 public NumberConditionBuilder then(float thenValue) { 352 return new NumberConditionBuilder(FloatConstant.valueOf(thenValue)); 353 } 354 355 /** 356 * Defines a constant value of the ternary expression, that is returned if 357 * the condition is {@code true}. 358 * 359 * @param thenValue 360 * the value 361 * @return the intermediate result which still requires the otherwise-branch 362 */ 363 public NumberConditionBuilder then(long thenValue) { 364 return new NumberConditionBuilder(LongConstant.valueOf(thenValue)); 365 } 366 367 /** 368 * Defines a constant value of the ternary expression, that is returned if 369 * the condition is {@code true}. 370 * 371 * @param thenValue 372 * the value 373 * @return the intermediate result which still requires the otherwise-branch 374 */ 375 public NumberConditionBuilder then(int thenValue) { 376 return new NumberConditionBuilder(IntegerConstant.valueOf(thenValue)); 377 } 378 379 /** 380 * If-then-else expression returning Boolean. 381 */ 382 private class BooleanCondition extends BooleanBinding { 383 private final ObservableBooleanValue trueResult; 384 private final boolean trueResultValue; 385 386 private final ObservableBooleanValue falseResult; 387 private final boolean falseResultValue; 388 389 private final InvalidationListener observer; 390 391 private BooleanCondition(final ObservableBooleanValue then, final ObservableBooleanValue otherwise) { 392 this.trueResult = then; 393 this.trueResultValue = false; 394 this.falseResult = otherwise; 395 this.falseResultValue = false; 396 this.observer = new WhenListener(this, condition, then, otherwise); 397 condition.addListener(observer); 398 then.addListener(observer); 399 otherwise.addListener(observer); 400 } 401 402 private BooleanCondition(final boolean then, final ObservableBooleanValue otherwise) { 403 this.trueResult = null; 404 this.trueResultValue = then; 405 this.falseResult = otherwise; 406 this.falseResultValue = false; 407 this.observer = new WhenListener(this, condition, null, otherwise); 408 condition.addListener(observer); 409 otherwise.addListener(observer); 410 } 411 412 private BooleanCondition(final ObservableBooleanValue then, final boolean otherwise) { 413 this.trueResult = then; 414 this.trueResultValue = false; 415 this.falseResult = null; 416 this.falseResultValue = otherwise; 417 this.observer = new WhenListener(this, condition, then, null); 418 condition.addListener(observer); 419 then.addListener(observer); 420 } 421 422 private BooleanCondition(final boolean then, final boolean otherwise) { 423 this.trueResult = null; 424 this.trueResultValue = then; 425 this.falseResult = null; 426 this.falseResultValue = otherwise; 427 this.observer = null; 428 super.bind(condition); 429 } 430 431 @Override 432 protected boolean computeValue() { 433 final boolean conditionValue = condition.get(); 434 Logging.getLogger().finest("Condition of ternary binding expression was evaluated: {0}", conditionValue); 435 return conditionValue ? (trueResult != null ? trueResult.get() : trueResultValue) 436 : (falseResult != null ? falseResult.get() : falseResultValue); 437 } 438 439 @Override 440 public void dispose() { 441 if (observer == null) { 442 super.unbind(condition); 443 } else { 444 condition.removeListener(observer); 445 if (trueResult != null) { 446 trueResult.removeListener(observer); 447 } 448 if (falseResult != null) { 449 falseResult.removeListener(observer); 450 } 451 } 452 } 453 454 @Override 455 public ObservableList<ObservableValue<?>> getDependencies() { 456 assert condition != null; 457 final ObservableList<ObservableValue<?>> seq = FXCollections.<ObservableValue<?>> observableArrayList(condition); 458 if (trueResult != null) { 459 seq.add(trueResult); 460 } 461 if (falseResult != null) { 462 seq.add(falseResult); 463 } 464 return FXCollections.unmodifiableObservableList(seq); 465 } 466 } 467 468 /** 469 * An intermediate class needed while assembling the ternary expression. It 470 * should not be used in another context. 471 * @since JavaFX 2.0 472 */ 473 public class BooleanConditionBuilder { 474 475 private ObservableBooleanValue trueResult; 476 private boolean trueResultValue; 477 478 private BooleanConditionBuilder(final ObservableBooleanValue thenValue) { 479 this.trueResult = thenValue; 480 } 481 482 private BooleanConditionBuilder(final boolean thenValue) { 483 this.trueResultValue = thenValue; 484 } 485 486 /** 487 * Defines the {@link javafx.beans.value.ObservableBooleanValue} which 488 * value is returned by the ternary expression if the condition is 489 * {@code false}. 490 * 491 * @param otherwiseValue 492 * the value 493 * @return the complete {@link BooleanBinding} 494 */ 495 public BooleanBinding otherwise(final ObservableBooleanValue otherwiseValue) { 496 if (otherwiseValue == null) { 497 throw new NullPointerException("Value needs to be specified"); 498 } 499 if (trueResult != null) 500 return new BooleanCondition(trueResult, otherwiseValue); 501 else 502 return new BooleanCondition(trueResultValue, otherwiseValue); 503 } 504 505 /** 506 * Defines a constant value of the ternary expression, that is returned 507 * if the condition is {@code false}. 508 * 509 * @param otherwiseValue 510 * the value 511 * @return the complete {@link BooleanBinding} 512 */ 513 public BooleanBinding otherwise(final boolean otherwiseValue) { 514 if (trueResult != null) 515 return new BooleanCondition(trueResult, otherwiseValue); 516 else 517 return new BooleanCondition(trueResultValue, otherwiseValue); 518 } 519 } 520 521 /** 522 * Defines the {@link javafx.beans.value.ObservableBooleanValue} which value 523 * is returned by the ternary expression if the condition is {@code true}. 524 * 525 * @param thenValue 526 * the value 527 * @return the intermediate result which still requires the otherwise-branch 528 */ 529 public BooleanConditionBuilder then(final ObservableBooleanValue thenValue) { 530 if (thenValue == null) { 531 throw new NullPointerException("Value needs to be specified"); 532 } 533 return new BooleanConditionBuilder(thenValue); 534 } 535 536 /** 537 * Defines a constant value of the ternary expression, that is returned if 538 * the condition is {@code true}. 539 * 540 * @param thenValue 541 * the value 542 * @return the intermediate result which still requires the otherwise-branch 543 */ 544 public BooleanConditionBuilder then(final boolean thenValue) { 545 return new BooleanConditionBuilder(thenValue); 546 } 547 548 /** 549 * If-then-else expression returning String. 550 */ 551 private class StringCondition extends StringBinding { 552 553 private final ObservableStringValue trueResult; 554 private final String trueResultValue; 555 556 private final ObservableStringValue falseResult; 557 private final String falseResultValue; 558 559 private final InvalidationListener observer; 560 561 private StringCondition(final ObservableStringValue then, final ObservableStringValue otherwise) { 562 this.trueResult = then; 563 this.trueResultValue = ""; 564 this.falseResult = otherwise; 565 this.falseResultValue = ""; 566 this.observer = new WhenListener(this, condition, then, otherwise); 567 condition.addListener(observer); 568 then.addListener(observer); 569 otherwise.addListener(observer); 570 } 571 572 private StringCondition(final String then, final ObservableStringValue otherwise) { 573 this.trueResult = null; 574 this.trueResultValue = then; 575 this.falseResult = otherwise; 576 this.falseResultValue = ""; 577 this.observer = new WhenListener(this, condition, null, otherwise); 578 condition.addListener(observer); 579 otherwise.addListener(observer); 580 } 581 582 private StringCondition(final ObservableStringValue then, final String otherwise) { 583 this.trueResult = then; 584 this.trueResultValue = ""; 585 this.falseResult = null; 586 this.falseResultValue = otherwise; 587 this.observer = new WhenListener(this, condition, then, null); 588 condition.addListener(observer); 589 then.addListener(observer); 590 } 591 592 private StringCondition(final String then, final String otherwise) { 593 this.trueResult = null; 594 this.trueResultValue = then; 595 this.falseResult = null; 596 this.falseResultValue = otherwise; 597 this.observer = null; 598 super.bind(condition); 599 } 600 601 @Override 602 protected String computeValue() { 603 final boolean conditionValue = condition.get(); 604 Logging.getLogger().finest("Condition of ternary binding expression was evaluated: {0}", conditionValue); 605 return conditionValue ? (trueResult != null ? trueResult.get() : trueResultValue) 606 : (falseResult != null ? falseResult.get() : falseResultValue); 607 } 608 609 @Override 610 public void dispose() { 611 if (observer == null) { 612 super.unbind(condition); 613 } else { 614 condition.removeListener(observer); 615 if (trueResult != null) { 616 trueResult.removeListener(observer); 617 } 618 if (falseResult != null) { 619 falseResult.removeListener(observer); 620 } 621 } 622 } 623 624 625 @Override 626 public ObservableList<ObservableValue<?>> getDependencies() { 627 assert condition != null; 628 final ObservableList<ObservableValue<?>> seq = FXCollections.<ObservableValue<?>> observableArrayList(condition); 629 if (trueResult != null) { 630 seq.add(trueResult); 631 } 632 if (falseResult != null) { 633 seq.add(falseResult); 634 } 635 return FXCollections.unmodifiableObservableList(seq); 636 } 637 } 638 639 /** 640 * An intermediate class needed while assembling the ternary expression. It 641 * should not be used in another context. 642 * @since JavaFX 2.0 643 */ 644 public class StringConditionBuilder { 645 646 private ObservableStringValue trueResult; 647 private String trueResultValue; 648 649 private StringConditionBuilder(final ObservableStringValue thenValue) { 650 this.trueResult = thenValue; 651 } 652 653 private StringConditionBuilder(final String thenValue) { 654 this.trueResultValue = thenValue; 655 } 656 657 /** 658 * Defines the {@link javafx.beans.value.ObservableStringValue} which 659 * value is returned by the ternary expression if the condition is 660 * {@code false}. 661 * 662 * @param otherwiseValue 663 * the value 664 * @return the complete {@link StringBinding} 665 */ 666 public StringBinding otherwise(final ObservableStringValue otherwiseValue) { 667 if (trueResult != null) 668 return new StringCondition(trueResult, otherwiseValue); 669 else 670 return new StringCondition(trueResultValue, otherwiseValue); 671 } 672 673 /** 674 * Defines a constant value of the ternary expression, that is returned 675 * if the condition is {@code false}. 676 * 677 * @param otherwiseValue 678 * the value 679 * @return the complete {@link StringBinding} 680 */ 681 public StringBinding otherwise(final String otherwiseValue) { 682 if (trueResult != null) 683 return new StringCondition(trueResult, otherwiseValue); 684 else 685 return new StringCondition(trueResultValue, otherwiseValue); 686 } 687 } 688 689 /** 690 * Defines the {@link javafx.beans.value.ObservableStringValue} which value 691 * is returned by the ternary expression if the condition is {@code true}. 692 * 693 * @param thenValue 694 * the value 695 * @return the intermediate result which still requires the otherwise-branch 696 */ 697 public StringConditionBuilder then(final ObservableStringValue thenValue) { 698 if (thenValue == null) { 699 throw new NullPointerException("Value needs to be specified"); 700 } 701 return new StringConditionBuilder(thenValue); 702 } 703 704 /** 705 * Defines a constant value of the ternary expression, that is returned if 706 * the condition is {@code true}. 707 * 708 * @param thenValue 709 * the value 710 * @return the intermediate result which still requires the otherwise-branch 711 */ 712 public StringConditionBuilder then(final String thenValue) { 713 return new StringConditionBuilder(thenValue); 714 } 715 716 /** 717 * If-then-else expression returning general objects. 718 */ 719 private class ObjectCondition<T> extends ObjectBinding<T> { 720 721 private final ObservableObjectValue<T> trueResult; 722 private final T trueResultValue; 723 724 private final ObservableObjectValue<T> falseResult; 725 private final T falseResultValue; 726 727 private final InvalidationListener observer; 728 729 private ObjectCondition(final ObservableObjectValue<T> then, final ObservableObjectValue<T> otherwise) { 730 this.trueResult = then; 731 this.trueResultValue = null; 732 this.falseResult = otherwise; 733 this.falseResultValue = null; 734 this.observer = new WhenListener(this, condition, then, otherwise); 735 condition.addListener(observer); 736 then.addListener(observer); 737 otherwise.addListener(observer); 738 } 739 740 private ObjectCondition(final T then, final ObservableObjectValue<T> otherwise) { 741 this.trueResult = null; 742 this.trueResultValue = then; 743 this.falseResult = otherwise; 744 this.falseResultValue = null; 745 this.observer = new WhenListener(this, condition, null, otherwise); 746 condition.addListener(observer); 747 otherwise.addListener(observer); 748 } 749 750 private ObjectCondition(final ObservableObjectValue<T> then, final T otherwise) { 751 this.trueResult = then; 752 this.trueResultValue = null; 753 this.falseResult = null; 754 this.falseResultValue = otherwise; 755 this.observer = new WhenListener(this, condition, then, null); 756 condition.addListener(observer); 757 then.addListener(observer); 758 } 759 760 private ObjectCondition(final T then, final T otherwise) { 761 this.trueResult = null; 762 this.trueResultValue = then; 763 this.falseResult = null; 764 this.falseResultValue = otherwise; 765 this.observer = null; 766 super.bind(condition); 767 } 768 769 @Override 770 protected T computeValue() { 771 final boolean conditionValue = condition.get(); 772 Logging.getLogger().finest("Condition of ternary binding expression was evaluated: {0}", conditionValue); 773 return conditionValue ? (trueResult != null ? trueResult.get() : trueResultValue) 774 : (falseResult != null ? falseResult.get() : falseResultValue); 775 } 776 777 @Override 778 public void dispose() { 779 if (observer == null) { 780 super.unbind(condition); 781 } else { 782 condition.removeListener(observer); 783 if (trueResult != null) { 784 trueResult.removeListener(observer); 785 } 786 if (falseResult != null) { 787 falseResult.removeListener(observer); 788 } 789 } 790 } 791 792 793 @Override 794 public ObservableList<ObservableValue<?>> getDependencies() { 795 assert condition != null; 796 final ObservableList<ObservableValue<?>> seq = FXCollections.<ObservableValue<?>> observableArrayList(condition); 797 if (trueResult != null) { 798 seq.add(trueResult); 799 } 800 if (falseResult != null) { 801 seq.add(falseResult); 802 } 803 return FXCollections.unmodifiableObservableList(seq); 804 } 805 } 806 807 /** 808 * An intermediate class needed while assembling the ternary expression. It 809 * should not be used in another context. 810 * @since JavaFX 2.0 811 */ 812 public class ObjectConditionBuilder<T> { 813 814 private ObservableObjectValue<T> trueResult; 815 private T trueResultValue; 816 817 private ObjectConditionBuilder(final ObservableObjectValue<T> thenValue) { 818 this.trueResult = thenValue; 819 } 820 821 private ObjectConditionBuilder(final T thenValue) { 822 this.trueResultValue = thenValue; 823 } 824 825 /** 826 * Defines the {@link javafx.beans.value.ObservableObjectValue} which 827 * value is returned by the ternary expression if the condition is 828 * {@code false}. 829 * 830 * @param otherwiseValue 831 * the value 832 * @return the complete {@link ObjectBinding} 833 */ 834 public ObjectBinding<T> otherwise(final ObservableObjectValue<T> otherwiseValue) { 835 if (otherwiseValue == null) { 836 throw new NullPointerException("Value needs to be specified"); 837 } 838 if (trueResult != null) 839 return new ObjectCondition<T>(trueResult, otherwiseValue); 840 else 841 return new ObjectCondition<T>(trueResultValue, otherwiseValue); 842 } 843 844 /** 845 * Defines a constant value of the ternary expression, that is returned 846 * if the condition is {@code false}. 847 * 848 * @param otherwiseValue 849 * the value 850 * @return the complete {@link ObjectBinding} 851 */ 852 public ObjectBinding<T> otherwise(final T otherwiseValue) { 853 if (trueResult != null) 854 return new ObjectCondition<T>(trueResult, otherwiseValue); 855 else 856 return new ObjectCondition<T>(trueResultValue, otherwiseValue); 857 } 858 } 859 860 /** 861 * Defines the {@link javafx.beans.value.ObservableObjectValue} which value 862 * is returned by the ternary expression if the condition is {@code true}. 863 * 864 * @param <T> the type of the intermediate result 865 * @param thenValue 866 * the value 867 * @return the intermediate result which still requires the otherwise-branch 868 */ 869 public <T> ObjectConditionBuilder<T> then(final ObservableObjectValue<T> thenValue) { 870 if (thenValue == null) { 871 throw new NullPointerException("Value needs to be specified"); 872 } 873 return new ObjectConditionBuilder<T>(thenValue); 874 } 875 876 /** 877 * Defines a constant value of the ternary expression, that is returned if 878 * the condition is {@code true}. 879 * 880 * @param <T> the type of the intermediate result 881 * @param thenValue 882 * the value 883 * @return the intermediate result which still requires the otherwise-branch 884 */ 885 public <T> ObjectConditionBuilder<T> then(final T thenValue) { 886 return new ObjectConditionBuilder<T>(thenValue); 887 } 888 889 }