1 /*
   2  * Copyright (c) 2010, 2017, 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 import java.text.Format;
  30 import java.util.List;
  31 import java.util.Locale;
  32 import java.util.Map;
  33 import java.util.Set;
  34 import java.util.concurrent.Callable;
  35 import javafx.beans.InvalidationListener;
  36 import javafx.beans.Observable;
  37 import javafx.beans.property.Property;
  38 import javafx.beans.value.ObservableBooleanValue;
  39 import javafx.beans.value.ObservableDoubleValue;
  40 import javafx.beans.value.ObservableFloatValue;
  41 import javafx.beans.value.ObservableIntegerValue;
  42 import javafx.beans.value.ObservableLongValue;
  43 import javafx.beans.value.ObservableNumberValue;
  44 import javafx.beans.value.ObservableObjectValue;
  45 import javafx.beans.value.ObservableStringValue;
  46 import javafx.beans.value.ObservableValue;
  47 import javafx.collections.FXCollections;
  48 import javafx.collections.ObservableList;
  49 import javafx.collections.ObservableMap;
  50 import javafx.collections.ObservableSet;
  51 import javafx.util.StringConverter;
  52 import com.sun.javafx.binding.BidirectionalBinding;
  53 import com.sun.javafx.binding.BidirectionalContentBinding;
  54 import com.sun.javafx.binding.ContentBinding;
  55 import com.sun.javafx.binding.DoubleConstant;
  56 import com.sun.javafx.binding.FloatConstant;
  57 import com.sun.javafx.binding.IntegerConstant;
  58 import com.sun.javafx.binding.Logging;
  59 import com.sun.javafx.binding.LongConstant;
  60 import com.sun.javafx.binding.ObjectConstant;
  61 import com.sun.javafx.binding.SelectBinding;
  62 import com.sun.javafx.binding.StringConstant;
  63 import com.sun.javafx.binding.StringFormatter;
  64 import com.sun.javafx.collections.ImmutableObservableList;
  65 import javafx.collections.ObservableArray;
  66 import javafx.collections.ObservableFloatArray;
  67 import javafx.collections.ObservableIntegerArray;
  68 
  69 /**
  70  * Bindings is a helper class with a lot of utility functions to create simple
  71  * bindings.
  72  * <p>
  73  * Usually there are two possibilities to define the same operation: the Fluent
  74  * API and the the factory methods in this class. This allows a developer to
  75  * define complex expression in a way that is most easy to understand. For
  76  * instance the expression {@code result = a*b + c*d} can be defined using only
  77  * the Fluent API:
  78  * <p>
  79  * {@code DoubleBinding result = a.multiply(b).add(c.multiply(d));}
  80  * <p>
  81  * Or using only factory methods in Bindings:
  82  * <p>
  83  * {@code NumberBinding result = add (multiply(a, b), multiply(c,d));}
  84  * <p>
  85  * Or mixing both possibilities:
  86  * <p>
  87  * {@code NumberBinding result = add (a.multiply(b), c.multiply(d));}
  88  * <p>
  89  * The main difference between using the Fluent API and using the factory
  90  * methods in this class is that the Fluent API requires that at least one of
  91  * the operands is an Expression (see {@link javafx.beans.binding}). (Every
  92  * Expression contains a static method that generates an Expression from an
  93  * {@link javafx.beans.value.ObservableValue}.)
  94  * <p>
  95  * Also if you watched closely, you might have noticed that the return type of
  96  * the Fluent API is different in the examples above. In a lot of cases the
  97  * Fluent API allows to be more specific about the returned type (see
  98  * {@link javafx.beans.binding.NumberExpression} for more details about implicit
  99  * casting.
 100  * </p>
 101  * <p><a id="DeployAppAsModule"></a><b>Deploying an Application as a Module</b></p>
 102  * <p>
 103  * If any class used in a select-binding (see the various {@code select*}
 104  * methods) is in a named module, then it must be reflectively accessible to the
 105  * {@code javafx.base} module.
 106  * A class is reflectively accessible if the module
 107  * {@link Module#isOpen(String,Module) opens} the containing package to at
 108  * least the {@code javafx.base} module.
 109  * </p>
 110  * <p>
 111  * For example, if {@code com.foo.MyClass} is in the {@code foo.app} module,
 112  * the {@code module-info.java} might
 113  * look like this:
 114  * </p>
 115  *
 116 <pre>{@code module foo.app {
 117     opens com.foo to javafx.base;
 118 }}</pre>
 119  *
 120  * <p>
 121  * Alternatively, a class is reflectively accessible if the module
 122  * {@link Module#isExported(String) exports} the containing package
 123  * unconditionally.
 124  * </p>
 125  *
 126  * @see Binding
 127  * @see NumberBinding
 128  *
 129  *
 130  * @since JavaFX 2.0
 131  */
 132 public final class Bindings {
 133 
 134     private Bindings() {
 135     }
 136 
 137     // =================================================================================================================
 138     // Helper functions to create custom bindings
 139 
 140     /**
 141      * Helper function to create a custom {@link BooleanBinding}.
 142      *
 143      * @param func The function that calculates the value of this binding
 144      * @param dependencies The dependencies of this binding
 145      * @return The generated binding
 146      * @since JavaFX 2.1
 147      */
 148     public static BooleanBinding createBooleanBinding(final Callable<Boolean> func, final Observable... dependencies) {
 149         return new BooleanBinding() {
 150             {
 151                 bind(dependencies);
 152             }
 153 
 154             @Override
 155             protected boolean computeValue() {
 156                 try {
 157                     return func.call();
 158                 } catch (Exception e) {
 159                     Logging.getLogger().warning("Exception while evaluating binding", e);
 160                     return false;
 161                 }
 162             }
 163 
 164             @Override
 165             public void dispose() {
 166                 super.unbind(dependencies);
 167             }
 168 
 169             @Override
 170             public ObservableList<?> getDependencies() {
 171                 return  ((dependencies == null) || (dependencies.length == 0))?
 172                             FXCollections.emptyObservableList()
 173                         : (dependencies.length == 1)?
 174                             FXCollections.singletonObservableList(dependencies[0])
 175                         : new ImmutableObservableList<Observable>(dependencies);
 176             }
 177         };
 178     }
 179 
 180     /**
 181      * Helper function to create a custom {@link DoubleBinding}.
 182      *
 183      * @param func The function that calculates the value of this binding
 184      * @param dependencies The dependencies of this binding
 185      * @return The generated binding
 186      * @since JavaFX 2.1
 187      */
 188     public static DoubleBinding createDoubleBinding(final Callable<Double> func, final Observable... dependencies) {
 189         return new DoubleBinding() {
 190             {
 191                 bind(dependencies);
 192             }
 193 
 194             @Override
 195             protected double computeValue() {
 196                 try {
 197                     return func.call();
 198                 } catch (Exception e) {
 199                     Logging.getLogger().warning("Exception while evaluating binding", e);
 200                     return 0.0;
 201                 }
 202             }
 203 
 204             @Override
 205             public void dispose() {
 206                 super.unbind(dependencies);
 207             }
 208 
 209             @Override
 210             public ObservableList<?> getDependencies() {
 211                 return  ((dependencies == null) || (dependencies.length == 0))?
 212                             FXCollections.emptyObservableList()
 213                         : (dependencies.length == 1)?
 214                             FXCollections.singletonObservableList(dependencies[0])
 215                         : new ImmutableObservableList<Observable>(dependencies);
 216             }
 217         };
 218     }
 219 
 220     /**
 221      * Helper function to create a custom {@link FloatBinding}.
 222      *
 223      * @param func The function that calculates the value of this binding
 224      * @param dependencies The dependencies of this binding
 225      * @return The generated binding
 226      * @since JavaFX 2.1
 227      */
 228     public static FloatBinding createFloatBinding(final Callable<Float> func, final Observable... dependencies) {
 229         return new FloatBinding() {
 230             {
 231                 bind(dependencies);
 232             }
 233 
 234             @Override
 235             protected float computeValue() {
 236                 try {
 237                     return func.call();
 238                 } catch (Exception e) {
 239                     Logging.getLogger().warning("Exception while evaluating binding", e);
 240                     return 0.0f;
 241                 }
 242             }
 243 
 244             @Override
 245             public void dispose() {
 246                 super.unbind(dependencies);
 247             }
 248 
 249             @Override
 250             public ObservableList<?> getDependencies() {
 251                 return  ((dependencies == null) || (dependencies.length == 0))?
 252                             FXCollections.emptyObservableList()
 253                         : (dependencies.length == 1)?
 254                             FXCollections.singletonObservableList(dependencies[0])
 255                         : new ImmutableObservableList<Observable>(dependencies);
 256             }
 257         };
 258     }
 259 
 260     /**
 261      * Helper function to create a custom {@link IntegerBinding}.
 262      *
 263      * @param func The function that calculates the value of this binding
 264      * @param dependencies The dependencies of this binding
 265      * @return The generated binding
 266      * @since JavaFX 2.1
 267      */
 268     public static IntegerBinding createIntegerBinding(final Callable<Integer> func, final Observable... dependencies) {
 269         return new IntegerBinding() {
 270             {
 271                 bind(dependencies);
 272             }
 273 
 274             @Override
 275             protected int computeValue() {
 276                 try {
 277                     return func.call();
 278                 } catch (Exception e) {
 279                     Logging.getLogger().warning("Exception while evaluating binding", e);
 280                     return 0;
 281                 }
 282             }
 283 
 284             @Override
 285             public void dispose() {
 286                 super.unbind(dependencies);
 287             }
 288 
 289             @Override
 290             public ObservableList<?> getDependencies() {
 291                 return  ((dependencies == null) || (dependencies.length == 0))?
 292                             FXCollections.emptyObservableList()
 293                         : (dependencies.length == 1)?
 294                             FXCollections.singletonObservableList(dependencies[0])
 295                         : new ImmutableObservableList<Observable>(dependencies);
 296             }
 297         };
 298     }
 299 
 300     /**
 301      * Helper function to create a custom {@link LongBinding}.
 302      *
 303      * @param func The function that calculates the value of this binding
 304      * @param dependencies The dependencies of this binding
 305      * @return The generated binding
 306      * @since JavaFX 2.1
 307      */
 308     public static LongBinding createLongBinding(final Callable<Long> func, final Observable... dependencies) {
 309         return new LongBinding() {
 310             {
 311                 bind(dependencies);
 312             }
 313 
 314             @Override
 315             protected long computeValue() {
 316                 try {
 317                     return func.call();
 318                 } catch (Exception e) {
 319                     Logging.getLogger().warning("Exception while evaluating binding", e);
 320                     return 0L;
 321                 }
 322             }
 323 
 324             @Override
 325             public void dispose() {
 326                 super.unbind(dependencies);
 327             }
 328 
 329             @Override
 330             public ObservableList<?> getDependencies() {
 331                 return  ((dependencies == null) || (dependencies.length == 0))?
 332                             FXCollections.emptyObservableList()
 333                         : (dependencies.length == 1)?
 334                             FXCollections.singletonObservableList(dependencies[0])
 335                         : new ImmutableObservableList<Observable>(dependencies);
 336             }
 337         };
 338     }
 339 
 340     /**
 341      * Helper function to create a custom {@link ObjectBinding}.
 342      *
 343      * @param <T> the type of the bound {@code Object}
 344      * @param func The function that calculates the value of this binding
 345      * @param dependencies The dependencies of this binding
 346      * @return The generated binding
 347      * @since JavaFX 2.1
 348      */
 349     public static <T> ObjectBinding<T> createObjectBinding(final Callable<T> func, final Observable... dependencies) {
 350         return new ObjectBinding<T>() {
 351             {
 352                 bind(dependencies);
 353             }
 354 
 355             @Override
 356             protected T computeValue() {
 357                 try {
 358                     return func.call();
 359                 } catch (Exception e) {
 360                     Logging.getLogger().warning("Exception while evaluating binding", e);
 361                     return null;
 362                 }
 363             }
 364 
 365             @Override
 366             public void dispose() {
 367                 super.unbind(dependencies);
 368             }
 369 
 370             @Override
 371             public ObservableList<?> getDependencies() {
 372                 return  ((dependencies == null) || (dependencies.length == 0))?
 373                             FXCollections.emptyObservableList()
 374                         : (dependencies.length == 1)?
 375                             FXCollections.singletonObservableList(dependencies[0])
 376                         : new ImmutableObservableList<Observable>(dependencies);
 377             }
 378         };
 379     }
 380 
 381     /**
 382      * Helper function to create a custom {@link StringBinding}.
 383      *
 384      * @param func The function that calculates the value of this binding
 385      * @param dependencies The dependencies of this binding
 386      * @return The generated binding
 387      * @since JavaFX 2.1
 388      */
 389     public static StringBinding createStringBinding(final Callable<String> func, final Observable... dependencies) {
 390         return new StringBinding() {
 391             {
 392                 bind(dependencies);
 393             }
 394 
 395             @Override
 396             protected String computeValue() {
 397                 try {
 398                     return func.call();
 399                 } catch (Exception e) {
 400                     Logging.getLogger().warning("Exception while evaluating binding", e);
 401                     return "";
 402                 }
 403             }
 404 
 405             @Override
 406             public void dispose() {
 407                 super.unbind(dependencies);
 408             }
 409 
 410             @Override
 411             public ObservableList<?> getDependencies() {
 412                 return  ((dependencies == null) || (dependencies.length == 0))?
 413                             FXCollections.emptyObservableList()
 414                         : (dependencies.length == 1)?
 415                             FXCollections.singletonObservableList(dependencies[0])
 416                         : new ImmutableObservableList<Observable>(dependencies);
 417             }
 418         };
 419     }
 420 
 421 
 422     // =================================================================================================================
 423     // Select Bindings
 424 
 425     /**
 426      * Creates a binding used to get a member, such as {@code a.b.c}. The value
 427      * of the binding will be {@code c}, or {@code null} if {@code c} could not
 428      * be reached (due to {@code b} not having a {@code c} property,
 429      * {@code b} being {@code null}, or {@code c} not being the right type etc.).
 430      * <p>
 431      * All classes and properties used in a select-binding have to be
 432      * declared public.
 433      * Additionally, if any class is in a named module, then it must be
 434      * reflectively accessible to the {@code javafx.base} module (see
 435      * <a href="#DeployAppAsModule">Deploying an Application as a Module</a>).
 436      * </p>
 437      * <p>
 438      * Note: since 8.0, JavaBeans properties are supported and might be in the chain.
 439      * </p>
 440      *
 441      * @param <T> the type of the wrapped {@code Object}
 442      * @param root
 443      *            The root {@link javafx.beans.value.ObservableValue}
 444      * @param steps
 445      *            The property names to reach the final property
 446      * @return the created {@link ObjectBinding}
 447      */
 448     public static <T> ObjectBinding<T> select(ObservableValue<?> root, String... steps) {
 449         return new SelectBinding.AsObject<T>(root, steps);
 450     }
 451 
 452     /**
 453      * Creates a binding used to get a member, such as {@code a.b.c}. The value
 454      * of the binding will be {@code c}, or {@code 0.0} if {@code c} could not
 455      * be reached (due to {@code b} not having a {@code c} property,
 456      * {@code b} being {@code null}, or {@code c} not being a {@code Number} etc.).
 457      * <p>
 458      * All classes and properties used in a select-binding have to be
 459      * declared public.
 460      * Additionally, if any class is in a named module, then it must be
 461      * reflectively accessible to the {@code javafx.base} module (see
 462      * <a href="#DeployAppAsModule">Deploying an Application as a Module</a>).
 463      * </p>
 464      * <p>
 465      * Note: since 8.0, JavaBeans properties are supported and might be in the chain.
 466      * </p>
 467      *
 468      * @param root
 469      *            The root {@link javafx.beans.value.ObservableValue}
 470      * @param steps
 471      *            The property names to reach the final property
 472      * @return the created {@link DoubleBinding}
 473      */
 474     public static DoubleBinding selectDouble(ObservableValue<?> root, String... steps) {
 475         return new SelectBinding.AsDouble(root, steps);
 476     }
 477 
 478     /**
 479      * Creates a binding used to get a member, such as {@code a.b.c}. The value
 480      * of the binding will be {@code c}, or {@code 0.0f} if {@code c} could not
 481      * be reached (due to {@code b} not having a {@code c} property,
 482      * {@code b} being {@code null}, or {@code c} not being a {@code Number} etc.).
 483      * <p>
 484      * All classes and properties used in a select-binding have to be
 485      * declared public.
 486      * Additionally, if any class is in a named module, then it must be
 487      * reflectively accessible to the {@code javafx.base} module (see
 488      * <a href="#DeployAppAsModule">Deploying an Application as a Module</a>).
 489      * </p>
 490      * <p>
 491      * Note: since 8.0, JavaBeans properties are supported and might be in the chain.
 492      * </p>
 493      *
 494      * @param root
 495      *            The root {@link javafx.beans.value.ObservableValue}
 496      * @param steps
 497      *            The property names to reach the final property
 498      * @return the created {@link FloatBinding}
 499      */
 500     public static FloatBinding selectFloat(ObservableValue<?> root, String... steps) {
 501         return new SelectBinding.AsFloat(root, steps);
 502     }
 503 
 504     /**
 505      * Creates a binding used to get a member, such as {@code a.b.c}. The value
 506      * of the binding will be {@code c}, or {@code 0} if {@code c} could not
 507      * be reached (due to {@code b} not having a {@code c} property,
 508      * {@code b} being {@code null}, or {@code c} not being a {@code Number} etc.).
 509      * <p>
 510      * All classes and properties used in a select-binding have to be
 511      * declared public.
 512      * Additionally, if any class is in a named module, then it must be
 513      * reflectively accessible to the {@code javafx.base} module (see
 514      * <a href="#DeployAppAsModule">Deploying an Application as a Module</a>).
 515      * </p>
 516      * <p>
 517      * Note: since 8.0, JavaBeans properties are supported and might be in the chain.
 518      * </p>
 519      *
 520      * @param root
 521      *            The root {@link javafx.beans.value.ObservableValue}
 522      * @param steps
 523      *            The property names to reach the final property
 524      * @return the created {@link IntegerBinding}
 525      */
 526     public static IntegerBinding selectInteger(ObservableValue<?> root, String... steps) {
 527         return new SelectBinding.AsInteger(root, steps);
 528     }
 529 
 530     /**
 531      * Creates a binding used to get a member, such as {@code a.b.c}. The value
 532      * of the binding will be {@code c}, or {@code 0L} if {@code c} could not
 533      * be reached (due to {@code b} not having a {@code c} property,
 534      * {@code b} being {@code null}, or {@code c} not being a {@code Number} etc.).
 535      * <p>
 536      * All classes and properties used in a select-binding have to be
 537      * declared public.
 538      * Additionally, if any class is in a named module, then it must be
 539      * reflectively accessible to the {@code javafx.base} module (see
 540      * <a href="#DeployAppAsModule">Deploying an Application as a Module</a>).
 541      * </p>
 542      * <p>
 543      * Note: since 8.0, JavaBeans properties are supported and might be in the chain.
 544      * </p>
 545      *
 546      * @param root
 547      *            The root {@link javafx.beans.value.ObservableValue}
 548      * @param steps
 549      *            The property names to reach the final property
 550      * @return the created {@link LongBinding}
 551      */
 552     public static LongBinding selectLong(ObservableValue<?> root, String... steps) {
 553         return new SelectBinding.AsLong(root, steps);
 554     }
 555 
 556     /**
 557      * Creates a binding used to get a member, such as {@code a.b.c}. The value
 558      * of the binding will be {@code c}, or {@code false} if {@code c} could not
 559      * be reached (due to {@code b} not having a {@code c} property,
 560      * {@code b} being {@code null}, or {@code c} not being a {@code boolean} etc.).
 561      * <p>
 562      * All classes and properties used in a select-binding have to be
 563      * declared public.
 564      * Additionally, if any class is in a named module, then it must be
 565      * reflectively accessible to the {@code javafx.base} module (see
 566      * <a href="#DeployAppAsModule">Deploying an Application as a Module</a>).
 567      * </p>
 568      * <p>
 569      * Note: since 8.0, JavaBeans properties are supported and might be in the chain.
 570      * </p>
 571      *
 572      * @param root
 573      *            The root {@link javafx.beans.value.ObservableValue}
 574      * @param steps
 575      *            The property names to reach the final property
 576      * @return the created {@link ObjectBinding}
 577      */
 578     public static BooleanBinding selectBoolean(ObservableValue<?> root, String... steps) {
 579         return new SelectBinding.AsBoolean(root, steps);
 580     }
 581 
 582     /**
 583      * Creates a binding used to get a member, such as {@code a.b.c}. The value
 584      * of the binding will be {@code c}, or {@code ""} if {@code c} could not
 585      * be reached (due to {@code b} not having a {@code c} property,
 586      * {@code b} being {@code null}, or {@code c} not being a {@code String} etc.).
 587      * <p>
 588      * All classes and properties used in a select-binding have to be
 589      * declared public.
 590      * Additionally, if any class is in a named module, then it must be
 591      * reflectively accessible to the {@code javafx.base} module (see
 592      * <a href="#DeployAppAsModule">Deploying an Application as a Module</a>).
 593      * </p>
 594      * <p>
 595      * Note: since 8.0, JavaBeans properties are supported and might be in the chain.
 596      * </p>
 597      *
 598      * @param root
 599      *            The root {@link javafx.beans.value.ObservableValue}
 600      * @param steps
 601      *            The property names to reach the final property
 602      * @return the created {@link ObjectBinding}
 603      */
 604     public static StringBinding selectString(ObservableValue<?> root, String... steps) {
 605         return new SelectBinding.AsString(root, steps);
 606     }
 607 
 608     /**
 609      * Creates a binding used to get a member, such as {@code a.b.c}. The value
 610      * of the binding will be {@code c}, or {@code null} if {@code c} could not
 611      * be reached (due to {@code b} not having a {@code c} property,
 612      * {@code b} being {@code null}, or {@code c} not being the right type etc.).
 613      * <p>
 614      * All classes and properties used in a select-binding have to be
 615      * declared public.
 616      * Additionally, if any class is in a named module, then it must be
 617      * reflectively accessible to the {@code javafx.base} module (see
 618      * <a href="#DeployAppAsModule">Deploying an Application as a Module</a>).
 619      * </p>
 620      *
 621      * <p>
 622      * If root has JavaFX properties, this call is equivalent to {@link #select(javafx.beans.value.ObservableValue, java.lang.String[])},
 623      * with the {@code root} and {@code step[0]} being substituted with the relevant property object.
 624      * </p>
 625      *
 626      * @param <T> the type of the wrapped {@code Object}
 627      * @param root
 628      *            The root bean.
 629      * @param steps
 630      *            The property names to reach the final property. The first step
 631      *            must be specified as it marks the property of the root bean.
 632      * @return the created {@link ObjectBinding}
 633      * @since JavaFX 8.0
 634      */
 635     public static <T> ObjectBinding<T> select(Object root, String... steps) {
 636         return new SelectBinding.AsObject<T>(root, steps);
 637     }
 638 
 639     /**
 640      * Creates a binding used to get a member, such as {@code a.b.c}. The value
 641      * of the binding will be {@code c}, or {@code 0.0} if {@code c} could not
 642      * be reached (due to {@code b} not having a {@code c} property,
 643      * {@code b} being {@code null}, or {@code c} not being a {@code Number} etc.).
 644      * <p>
 645      * All classes and properties used in a select-binding have to be
 646      * declared public.
 647      * Additionally, if any class is in a named module, then it must be
 648      * reflectively accessible to the {@code javafx.base} module (see
 649      * <a href="#DeployAppAsModule">Deploying an Application as a Module</a>).
 650      * </p>
 651      *
 652      * <p>
 653      * If root has JavaFX properties, this call is equivalent to {@link #selectDouble(javafx.beans.value.ObservableValue, java.lang.String[])},
 654      * with the {@code root} and {@code step[0]} being substituted with the relevant property object.
 655      * </p>
 656      *
 657      * @param root
 658      *            The root bean.
 659      * @param steps
 660      *            The property names to reach the final property. The first step
 661      *            must be specified as it marks the property of the root bean.
 662      * @return the created {@link DoubleBinding}
 663      * @since JavaFX 8.0
 664      */
 665     public static DoubleBinding selectDouble(Object root, String... steps) {
 666         return new SelectBinding.AsDouble(root, steps);
 667     }
 668 
 669     /**
 670      * Creates a binding used to get a member, such as {@code a.b.c}. The value
 671      * of the binding will be {@code c}, or {@code 0.0f} if {@code c} could not
 672      * be reached (due to {@code b} not having a {@code c} property,
 673      * {@code b} being {@code null}, or {@code c} not being a {@code Number} etc.).
 674      * <p>
 675      * All classes and properties used in a select-binding have to be
 676      * declared public.
 677      * Additionally, if any class is in a named module, then it must be
 678      * reflectively accessible to the {@code javafx.base} module (see
 679      * <a href="#DeployAppAsModule">Deploying an Application as a Module</a>).
 680      * </p>
 681      *
 682      * <p>
 683      * If root has JavaFX properties, this call is equivalent to {@link #selectFloat(javafx.beans.value.ObservableValue, java.lang.String[])},
 684      * with the {@code root} and {@code step[0]} being substituted with the relevant property object.
 685      * </p>
 686      *
 687      * @param root
 688      *            The root bean.
 689      * @param steps
 690      *            The property names to reach the final property. The first step
 691      *            must be specified as it marks the property of the root bean.
 692      * @return the created {@link FloatBinding}
 693      * @since JavaFX 8.0
 694      */
 695     public static FloatBinding selectFloat(Object root, String... steps) {
 696         return new SelectBinding.AsFloat(root, steps);
 697     }
 698 
 699     /**
 700      * Creates a binding used to get a member, such as {@code a.b.c}. The value
 701      * of the binding will be {@code c}, or {@code 0} if {@code c} could not
 702      * be reached (due to {@code b} not having a {@code c} property,
 703      * {@code b} being {@code null}, or {@code c} not being a {@code Number} etc.).
 704      * <p>
 705      * All classes and properties used in a select-binding have to be
 706      * declared public.
 707      * Additionally, if any class is in a named module, then it must be
 708      * reflectively accessible to the {@code javafx.base} module (see
 709      * <a href="#DeployAppAsModule">Deploying an Application as a Module</a>).
 710      * </p>
 711      *
 712      * <p>
 713      * If root has JavaFX properties, this call is equivalent to {@link #selectInteger(javafx.beans.value.ObservableValue, java.lang.String[])},
 714      * with the {@code root} and {@code step[0]} being substituted with the relevant property object.
 715      * </p>
 716      *
 717      * @param root
 718      *            The root bean.
 719      * @param steps
 720      *            The property names to reach the final property. The first step
 721      *            must be specified as it marks the property of the root bean.
 722      * @return the created {@link IntegerBinding}
 723      * @since JavaFX 8.0
 724      */
 725     public static IntegerBinding selectInteger(Object root, String... steps) {
 726         return new SelectBinding.AsInteger(root, steps);
 727     }
 728 
 729     /**
 730      * Creates a binding used to get a member, such as {@code a.b.c}. The value
 731      * of the binding will be {@code c}, or {@code 0L} if {@code c} could not
 732      * be reached (due to {@code b} not having a {@code c} property,
 733      * {@code b} being {@code null}, or {@code c} not being a {@code Number} etc.).
 734      * <p>
 735      * All classes and properties used in a select-binding have to be
 736      * declared public.
 737      * Additionally, if any class is in a named module, then it must be
 738      * reflectively accessible to the {@code javafx.base} module (see
 739      * <a href="#DeployAppAsModule">Deploying an Application as a Module</a>).
 740      * </p>
 741      *
 742      * <p>
 743      * If root has JavaFX properties, this call is equivalent to {@link #selectLong(javafx.beans.value.ObservableValue, java.lang.String[])},
 744      * with the {@code root} and {@code step[0]} being substituted with the relevant property object.
 745      * </p>
 746      *
 747      * @param root
 748      *            The root bean.
 749      * @param steps
 750      *            The property names to reach the final property. The first step
 751      *            must be specified as it marks the property of the root bean.
 752      * @return the created {@link LongBinding}
 753      * @since JavaFX 8.0
 754      */
 755     public static LongBinding selectLong(Object root, String... steps) {
 756         return new SelectBinding.AsLong(root, steps);
 757     }
 758 
 759     /**
 760      * Creates a binding used to get a member, such as {@code a.b.c}. The value
 761      * of the binding will be {@code c}, or {@code false} if {@code c} could not
 762      * be reached (due to {@code b} not having a {@code c} property,
 763      * {@code b} being {@code null}, or {@code c} not being a {@code boolean} etc.).
 764      * <p>
 765      * All classes and properties used in a select-binding have to be
 766      * declared public.
 767      * Additionally, if any class is in a named module, then it must be
 768      * reflectively accessible to the {@code javafx.base} module (see
 769      * <a href="#DeployAppAsModule">Deploying an Application as a Module</a>).
 770      * </p>
 771      *
 772      * <p>
 773      * If root has JavaFX properties, this call is equivalent to {@link #selectBoolean(javafx.beans.value.ObservableValue, java.lang.String[])},
 774      * with the {@code root} and {@code step[0]} being substituted with the relevant property object.
 775      * </p>
 776      *
 777      * @param root
 778      *            The root bean.
 779      * @param steps
 780      *            The property names to reach the final property. The first step
 781      *            must be specified as it marks the property of the root bean.
 782      * @return the created {@link ObjectBinding}
 783      * @since JavaFX 8.0
 784      */
 785     public static BooleanBinding selectBoolean(Object root, String... steps) {
 786         return new SelectBinding.AsBoolean(root, steps);
 787     }
 788 
 789     /**
 790      * Creates a binding used to get a member, such as {@code a.b.c}. The value
 791      * of the binding will be {@code c}, or {@code ""} if {@code c} could not
 792      * be reached (due to {@code b} not having a {@code c} property,
 793      * {@code b} being {@code null}, or {@code c} not being a {@code String} etc.).
 794      * <p>
 795      * All classes and properties used in a select-binding have to be
 796      * declared public.
 797      * Additionally, if any class is in a named module, then it must be
 798      * reflectively accessible to the {@code javafx.base} module (see
 799      * <a href="#DeployAppAsModule">Deploying an Application as a Module</a>).
 800      * </p>
 801      *
 802      * <p>
 803      * If root has JavaFX properties, this call is equivalent to {@link #selectString(javafx.beans.value.ObservableValue, java.lang.String[])},
 804      * with the {@code root} and {@code step[0]} being substituted with the relevant property object.
 805      * </p>
 806      *
 807      * @param root
 808      *            The root bean.
 809      * @param steps
 810      *            The property names to reach the final property. The first step
 811      *            must be specified as it marks the property of the root bean.
 812      * @return the created {@link ObjectBinding}
 813      * @since JavaFX 8.0
 814      */
 815     public static StringBinding selectString(Object root, String... steps) {
 816         return new SelectBinding.AsString(root, steps);
 817     }
 818 
 819     /**
 820      * Creates a binding that calculates the result of a ternary expression. See
 821      * the description of class {@link When} for details.
 822      *
 823      * @see When
 824      *
 825      * @param condition
 826      *            the condition of the ternary expression
 827      * @return an intermediate class to build the complete binding
 828      */
 829     public static When when(final ObservableBooleanValue condition) {
 830         return new When(condition);
 831     }
 832 
 833     // =================================================================================================================
 834     // Bidirectional Bindings
 835 
 836     /**
 837      * Generates a bidirectional binding (or "bind with inverse") between two
 838      * instances of {@link javafx.beans.property.Property}.
 839      * <p>
 840      * A bidirectional binding is a binding that works in both directions. If
 841      * two properties {@code a} and {@code b} are linked with a bidirectional
 842      * binding and the value of {@code a} changes, {@code b} is set to the same
 843      * value automatically. And vice versa, if {@code b} changes, {@code a} is
 844      * set to the same value.
 845      * <p>
 846      * A bidirectional binding can be removed with
 847      * {@link #unbindBidirectional(Property, Property)}.
 848      * <p>
 849      * Note: this implementation of a bidirectional binding behaves differently
 850      * from all other bindings here in two important aspects. A property that is
 851      * linked to another property with a bidirectional binding can still be set
 852      * (usually bindings would throw an exception). Secondly bidirectional
 853      * bindings are calculated eagerly, i.e. a bound property is updated
 854      * immediately.
 855      *
 856      * @param <T>
 857      *            the types of the properties
 858      * @param property1
 859      *            the first {@code Property<T>}
 860      * @param property2
 861      *            the second {@code Property<T>}
 862      * @throws NullPointerException
 863      *            if one of the properties is {@code null}
 864      * @throws IllegalArgumentException
 865      *            if both properties are equal
 866      */
 867     public static <T> void bindBidirectional(Property<T> property1, Property<T> property2) {
 868         BidirectionalBinding.bind(property1, property2);
 869     }
 870 
 871     /**
 872      * Delete a bidirectional binding that was previously defined with
 873      * {@link #bindBidirectional(Property, Property)}.
 874      *
 875      * @param <T>
 876      *            the types of the properties
 877      * @param property1
 878      *            the first {@code Property<T>}
 879      * @param property2
 880      *            the second {@code Property<T>}
 881      * @throws NullPointerException
 882      *            if one of the properties is {@code null}
 883      * @throws IllegalArgumentException
 884      *            if both properties are equal
 885      */
 886     public static <T> void unbindBidirectional(Property<T> property1, Property<T> property2) {
 887         BidirectionalBinding.unbind(property1, property2);
 888     }
 889 
 890     /**
 891      * Delete a bidirectional binding that was previously defined with
 892      * {@link #bindBidirectional(Property, Property)} or
 893      * {@link #bindBidirectional(javafx.beans.property.Property, javafx.beans.property.Property, java.text.Format)}.
 894      *
 895      * @param property1
 896      *            the first {@code Property<T>}
 897      * @param property2
 898      *            the second {@code Property<T>}
 899      * @throws NullPointerException
 900      *            if one of the properties is {@code null}
 901      * @throws IllegalArgumentException
 902      *            if both properties are equal
 903      * @since JavaFX 2.1
 904      */
 905     public static void unbindBidirectional(Object property1, Object property2) {
 906         BidirectionalBinding.unbind(property1, property2);
 907     }
 908 
 909     /**
 910      * Generates a bidirectional binding (or "bind with inverse") between a
 911      * {@code String}-{@link javafx.beans.property.Property} and another {@code Property}
 912      * using the specified {@code Format} for conversion.
 913      * <p>
 914      * A bidirectional binding is a binding that works in both directions. If
 915      * two properties {@code a} and {@code b} are linked with a bidirectional
 916      * binding and the value of {@code a} changes, {@code b} is set to the same
 917      * value automatically. And vice versa, if {@code b} changes, {@code a} is
 918      * set to the same value.
 919      * <p>
 920      * A bidirectional binding can be removed with
 921      * {@link #unbindBidirectional(Object, Object)}.
 922      * <p>
 923      * Note: this implementation of a bidirectional binding behaves differently
 924      * from all other bindings here in two important aspects. A property that is
 925      * linked to another property with a bidirectional binding can still be set
 926      * (usually bindings would throw an exception). Secondly bidirectional
 927      * bindings are calculated eagerly, i.e. a bound property is updated
 928      * immediately.
 929      *
 930      * @param stringProperty
 931      *            the {@code String} {@code Property}
 932      * @param otherProperty
 933      *            the other (non-{@code String}) {@code Property}
 934      * @param format
 935      *            the {@code Format} used to convert between the properties
 936      * @throws NullPointerException
 937      *            if one of the properties or the {@code format} is {@code null}
 938      * @throws IllegalArgumentException
 939      *            if both properties are equal
 940      * @since JavaFX 2.1
 941      */
 942     public  static void bindBidirectional(Property<String> stringProperty, Property<?> otherProperty, Format format) {
 943         BidirectionalBinding.bind(stringProperty, otherProperty, format);
 944     }
 945 
 946     /**
 947      * Generates a bidirectional binding (or "bind with inverse") between a
 948      * {@code String}-{@link javafx.beans.property.Property} and another {@code Property}
 949      * using the specified {@link javafx.util.StringConverter} for conversion.
 950      * <p>
 951      * A bidirectional binding is a binding that works in both directions. If
 952      * two properties {@code a} and {@code b} are linked with a bidirectional
 953      * binding and the value of {@code a} changes, {@code b} is set to the same
 954      * value automatically. And vice versa, if {@code b} changes, {@code a} is
 955      * set to the same value.
 956      * <p>
 957      * A bidirectional binding can be removed with
 958      * {@link #unbindBidirectional(Object, Object)}.
 959      * <p>
 960      * Note: this implementation of a bidirectional binding behaves differently
 961      * from all other bindings here in two important aspects. A property that is
 962      * linked to another property with a bidirectional binding can still be set
 963      * (usually bindings would throw an exception). Secondly bidirectional
 964      * bindings are calculated eagerly, i.e. a bound property is updated
 965      * immediately.
 966      *
 967      * @param <T> the type of the wrapped {@code Object}
 968      * @param stringProperty
 969      *            the {@code String} {@code Property}
 970      * @param otherProperty
 971      *            the other (non-{@code String}) {@code Property}
 972      * @param converter
 973      *            the {@code StringConverter} used to convert between the properties
 974      * @throws NullPointerException
 975      *            if one of the properties or the {@code converter} is {@code null}
 976      * @throws IllegalArgumentException
 977      *            if both properties are equal
 978      * @since JavaFX 2.1
 979      */
 980     public static <T> void bindBidirectional(Property<String> stringProperty, Property<T> otherProperty, StringConverter<T> converter) {
 981         BidirectionalBinding.bind(stringProperty, otherProperty, converter);
 982     }
 983 
 984     /**
 985      * Generates a bidirectional binding (or "bind with inverse") between two
 986      * instances of {@link javafx.collections.ObservableList}.
 987      * <p>
 988      * A bidirectional binding is a binding that works in both directions. If
 989      * two properties {@code a} and {@code b} are linked with a bidirectional
 990      * binding and the value of {@code a} changes, {@code b} is set to the same
 991      * value automatically. And vice versa, if {@code b} changes, {@code a} is
 992      * set to the same value.
 993      * <p>
 994      * Only the content of the two lists is synchronized, which means that
 995      * both lists are different, but they contain the same elements.
 996      * <p>
 997      * A bidirectional content-binding can be removed with
 998      * {@link #unbindContentBidirectional(Object, Object)}.
 999      * <p>
1000      * Note: this implementation of a bidirectional binding behaves differently
1001      * from all other bindings here in two important aspects. A property that is
1002      * linked to another property with a bidirectional binding can still be set
1003      * (usually bindings would throw an exception). Secondly bidirectional
1004      * bindings are calculated eagerly, i.e. a bound property is updated
1005      * immediately.
1006      *
1007      * @param <E>
1008      *            the type of the list elements
1009      * @param list1
1010      *            the first {@code ObservableList<E>}
1011      * @param list2
1012      *            the second {@code ObservableList<E>}
1013      * @throws NullPointerException
1014      *            if one of the lists is {@code null}
1015      * @throws IllegalArgumentException
1016      *            if {@code list1} == {@code list2}
1017      * @since JavaFX 2.1
1018      */
1019     public static <E> void bindContentBidirectional(ObservableList<E> list1, ObservableList<E> list2) {
1020         BidirectionalContentBinding.bind(list1, list2);
1021     }
1022 
1023     /**
1024      * Generates a bidirectional binding (or "bind with inverse") between two
1025      * instances of {@link javafx.collections.ObservableSet}.
1026      * <p>
1027      * A bidirectional binding is a binding that works in both directions. If
1028      * two properties {@code a} and {@code b} are linked with a bidirectional
1029      * binding and the value of {@code a} changes, {@code b} is set to the same
1030      * value automatically. And vice versa, if {@code b} changes, {@code a} is
1031      * set to the same value.
1032      * <p>
1033      * Only the content of the two sets is synchronized, which means that
1034      * both sets are different, but they contain the same elements.
1035      * <p>
1036      * A bidirectional content-binding can be removed with
1037      * {@link #unbindContentBidirectional(Object, Object)}.
1038      * <p>
1039      * Note: this implementation of a bidirectional binding behaves differently
1040      * from all other bindings here in two important aspects. A property that is
1041      * linked to another property with a bidirectional binding can still be set
1042      * (usually bindings would throw an exception). Secondly bidirectional
1043      * bindings are calculated eagerly, i.e. a bound property is updated
1044      * immediately.
1045      *
1046      * @param <E>
1047      *            the type of the set elements
1048      * @param set1
1049      *            the first {@code ObservableSet<E>}
1050      * @param set2
1051      *            the second {@code ObservableSet<E>}
1052      * @throws NullPointerException
1053      *            if one of the sets is {@code null}
1054      * @throws IllegalArgumentException
1055      *            if {@code set1} == {@code set2}
1056      * @since JavaFX 2.1
1057      */
1058     public static <E> void bindContentBidirectional(ObservableSet<E> set1, ObservableSet<E> set2) {
1059         BidirectionalContentBinding.bind(set1, set2);
1060     }
1061 
1062     /**
1063      * Generates a bidirectional binding (or "bind with inverse") between two
1064      * instances of {@link javafx.collections.ObservableMap}.
1065      * <p>
1066      * A bidirectional binding is a binding that works in both directions. If
1067      * two properties {@code a} and {@code b} are linked with a bidirectional
1068      * binding and the value of {@code a} changes, {@code b} is set to the same
1069      * value automatically. And vice versa, if {@code b} changes, {@code a} is
1070      * set to the same value.
1071      * <p>
1072      * Only the content of the two maps is synchronized, which means that
1073      * both maps are different, but they contain the same elements.
1074      * <p>
1075      * A bidirectional content-binding can be removed with
1076      * {@link #unbindContentBidirectional(Object, Object)}.
1077      * <p>
1078      * Note: this implementation of a bidirectional binding behaves differently
1079      * from all other bindings here in two important aspects. A property that is
1080      * linked to another property with a bidirectional binding can still be set
1081      * (usually bindings would throw an exception). Secondly bidirectional
1082      * bindings are calculated eagerly, i.e. a bound property is updated
1083      * immediately.
1084      *
1085      * @param <K>
1086      *            the type of the key elements
1087      * @param <V>
1088      *            the type of the value elements
1089      * @param map1
1090      *            the first {@code ObservableMap<K, V>}
1091      * @param map2
1092      *            the second {@code ObservableMap<K, V>}
1093      * @since JavaFX 2.1
1094      */
1095     public static <K, V> void bindContentBidirectional(ObservableMap<K, V> map1, ObservableMap<K, V> map2) {
1096         BidirectionalContentBinding.bind(map1, map2);
1097     }
1098 
1099     /**
1100      * Remove a bidirectional content binding.
1101      *
1102      * @param obj1
1103      *            the first {@code Object}
1104      * @param obj2
1105      *            the second {@code Object}
1106      * @since JavaFX 2.1
1107      */
1108     public static void unbindContentBidirectional(Object obj1, Object obj2) {
1109         BidirectionalContentBinding.unbind(obj1, obj2);
1110     }
1111 
1112     /**
1113      * Generates a content binding between an {@link javafx.collections.ObservableList} and a {@link java.util.List}.
1114      * <p>
1115      * A content binding ensures that the {@code List} contains the same elements as the {@code ObservableList}.
1116      * If the content of the {@code ObservableList} changes, the {@code List} will be updated automatically.
1117      * <p>
1118      * Once a {@code List} is bound to an {@code ObservableList}, the {@code List} must not be changed directly
1119      * anymore. Doing so would lead to unexpected results.
1120      * <p>
1121      * A content-binding can be removed with {@link #unbindContent(Object, Object)}.
1122      *
1123      * @param <E>
1124      *            the type of the {@code List} elements
1125      * @param list1
1126      *            the {@code List}
1127      * @param list2
1128      *            the {@code ObservableList}
1129      * @since JavaFX 2.1
1130      */
1131     public static <E> void bindContent(List<E> list1, ObservableList<? extends E> list2) {
1132         ContentBinding.bind(list1, list2);
1133     }
1134 
1135     /**
1136      * Generates a content binding between an {@link javafx.collections.ObservableSet} and a {@link java.util.Set}.
1137      * <p>
1138      * A content binding ensures that the {@code Set} contains the same elements as the {@code ObservableSet}.
1139      * If the content of the {@code ObservableSet} changes, the {@code Set} will be updated automatically.
1140      * <p>
1141      * Once a {@code Set} is bound to an {@code ObservableSet}, the {@code Set} must not be changed directly
1142      * anymore. Doing so would lead to unexpected results.
1143      * <p>
1144      * A content-binding can be removed with {@link #unbindContent(Object, Object)}.
1145      *
1146      * @param <E>
1147      *            the type of the {@code Set} elements
1148      * @param set1
1149      *            the {@code Set}
1150      * @param set2
1151      *            the {@code ObservableSet}
1152      * @throws NullPointerException
1153      *            if one of the sets is {@code null}
1154      * @throws IllegalArgumentException
1155      *            if {@code set1} == {@code set2}
1156      * @since JavaFX 2.1
1157      */
1158     public static <E> void bindContent(Set<E> set1, ObservableSet<? extends E> set2) {
1159         ContentBinding.bind(set1, set2);
1160     }
1161 
1162     /**
1163      * Generates a content binding between an {@link javafx.collections.ObservableMap} and a {@link java.util.Map}.
1164      * <p>
1165      * A content binding ensures that the {@code Map} contains the same elements as the {@code ObservableMap}.
1166      * If the content of the {@code ObservableMap} changes, the {@code Map} will be updated automatically.
1167      * <p>
1168      * Once a {@code Map} is bound to an {@code ObservableMap}, the {@code Map} must not be changed directly
1169      * anymore. Doing so would lead to unexpected results.
1170      * <p>
1171      * A content-binding can be removed with {@link #unbindContent(Object, Object)}.
1172      *
1173      * @param <K>
1174      *            the type of the key elements of the {@code Map}
1175      * @param <V>
1176      *            the type of the value elements of the {@code Map}
1177      * @param map1
1178      *            the {@code Map}
1179      * @param map2
1180      *            the {@code ObservableMap}
1181      * @throws NullPointerException
1182      *            if one of the maps is {@code null}
1183      * @throws IllegalArgumentException
1184      *            if {@code map1} == {@code map2}
1185      * @since JavaFX 2.1
1186      */
1187     public static <K, V> void bindContent(Map<K, V> map1, ObservableMap<? extends K, ? extends V> map2) {
1188         ContentBinding.bind(map1, map2);
1189     }
1190 
1191     /**
1192      * Remove a content binding.
1193      *
1194      * @param obj1
1195      *            the first {@code Object}
1196      * @param obj2
1197      *            the second {@code Object}
1198      * @throws NullPointerException
1199      *            if one of the {@code Objects} is {@code null}
1200      * @throws IllegalArgumentException
1201      *            if {@code obj1} == {@code obj2}
1202      * @since JavaFX 2.1
1203      */
1204     public static void unbindContent(Object obj1, Object obj2) {
1205         ContentBinding.unbind(obj1, obj2);
1206     }
1207 
1208 
1209 
1210     // =================================================================================================================
1211     // Negation
1212 
1213     /**
1214      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
1215      * the negation of a {@link javafx.beans.value.ObservableNumberValue}.
1216      *
1217      * @param value
1218      *            the operand
1219      * @return the new {@code NumberBinding}
1220      * @throws NullPointerException
1221      *             if the value is {@code null}
1222      */
1223     public static NumberBinding negate(final ObservableNumberValue value) {
1224         if (value == null) {
1225             throw new NullPointerException("Operand cannot be null.");
1226         }
1227 
1228         if (value instanceof ObservableDoubleValue) {
1229             return new DoubleBinding() {
1230                 {
1231                     super.bind(value);
1232                 }
1233 
1234                 @Override
1235                 public void dispose() {
1236                     super.unbind(value);
1237                 }
1238 
1239                 @Override
1240                 protected double computeValue() {
1241                     return -value.doubleValue();
1242                 }
1243 
1244                 @Override
1245                 public ObservableList<?> getDependencies() {
1246                     return FXCollections.singletonObservableList(value);
1247                 }
1248             };
1249         } else if (value instanceof ObservableFloatValue) {
1250             return new FloatBinding() {
1251                 {
1252                     super.bind(value);
1253                 }
1254 
1255                 @Override
1256                 public void dispose() {
1257                     super.unbind(value);
1258                 }
1259 
1260                 @Override
1261                 protected float computeValue() {
1262                     return -value.floatValue();
1263                 }
1264 
1265                 @Override
1266                 public ObservableList<?> getDependencies() {
1267                     return FXCollections.singletonObservableList(value);
1268                 }
1269             };
1270         } else if (value instanceof ObservableLongValue) {
1271             return new LongBinding() {
1272                 {
1273                     super.bind(value);
1274                 }
1275 
1276                 @Override
1277                 public void dispose() {
1278                     super.unbind(value);
1279                 }
1280 
1281                 @Override
1282                 protected long computeValue() {
1283                     return -value.longValue();
1284                 }
1285 
1286                 @Override
1287                 public ObservableList<?> getDependencies() {
1288                     return FXCollections.singletonObservableList(value);
1289                 }
1290             };
1291         } else {
1292             return new IntegerBinding() {
1293                 {
1294                     super.bind(value);
1295                 }
1296 
1297                 @Override
1298                 public void dispose() {
1299                     super.unbind(value);
1300                 }
1301 
1302                 @Override
1303                 protected int computeValue() {
1304                     return -value.intValue();
1305                 }
1306 
1307                 @Override
1308                 public ObservableList<?> getDependencies() {
1309                     return FXCollections.singletonObservableList(value);
1310                 }
1311             };
1312         }
1313     }
1314 
1315     // =================================================================================================================
1316     // Sum
1317 
1318     private static NumberBinding add(final ObservableNumberValue op1, final ObservableNumberValue op2, final Observable... dependencies) {
1319         if ((op1 == null) || (op2 == null)) {
1320             throw new NullPointerException("Operands cannot be null.");
1321         }
1322         assert (dependencies != null) && (dependencies.length > 0);
1323 
1324         if ((op1 instanceof ObservableDoubleValue) || (op2 instanceof ObservableDoubleValue)) {
1325             return new DoubleBinding() {
1326                 {
1327                     super.bind(dependencies);
1328                 }
1329 
1330                 @Override
1331                 public void dispose() {
1332                     super.unbind(dependencies);
1333                 }
1334 
1335                 @Override
1336                 protected double computeValue() {
1337                     return op1.doubleValue() + op2.doubleValue();
1338                 }
1339 
1340                 @Override
1341                 public ObservableList<?> getDependencies() {
1342                     return (dependencies.length == 1)?
1343                             FXCollections.singletonObservableList(dependencies[0])
1344                             : new ImmutableObservableList<Observable>(dependencies);
1345                 }
1346             };
1347         } else if ((op1 instanceof ObservableFloatValue) || (op2 instanceof ObservableFloatValue)) {
1348             return new FloatBinding() {
1349                 {
1350                     super.bind(dependencies);
1351                 }
1352 
1353                 @Override
1354                 public void dispose() {
1355                     super.unbind(dependencies);
1356                 }
1357 
1358                 @Override
1359                 protected float computeValue() {
1360                     return op1.floatValue() + op2.floatValue();
1361                 }
1362 
1363                 @Override
1364                 public ObservableList<?> getDependencies() {
1365                     return (dependencies.length == 1)?
1366                             FXCollections.singletonObservableList(dependencies[0])
1367                             : new ImmutableObservableList<Observable>(dependencies);
1368                 }
1369             };
1370         } else if ((op1 instanceof ObservableLongValue) || (op2 instanceof ObservableLongValue)) {
1371             return new LongBinding() {
1372                 {
1373                     super.bind(dependencies);
1374                 }
1375 
1376                 @Override
1377                 public void dispose() {
1378                     super.unbind(dependencies);
1379                 }
1380 
1381                 @Override
1382                 protected long computeValue() {
1383                     return op1.longValue() + op2.longValue();
1384                 }
1385 
1386                 @Override
1387                 public ObservableList<?> getDependencies() {
1388                     return (dependencies.length == 1)?
1389                             FXCollections.singletonObservableList(dependencies[0])
1390                             : new ImmutableObservableList<Observable>(dependencies);
1391                 }
1392             };
1393         } else {
1394             return new IntegerBinding() {
1395                 {
1396                     super.bind(dependencies);
1397                 }
1398 
1399                 @Override
1400                 public void dispose() {
1401                     super.unbind(dependencies);
1402                 }
1403 
1404                 @Override
1405                 protected int computeValue() {
1406                     return op1.intValue() + op2.intValue();
1407                 }
1408 
1409                 @Override
1410                 public ObservableList<?> getDependencies() {
1411                     return (dependencies.length == 1)?
1412                             FXCollections.singletonObservableList(dependencies[0])
1413                             : new ImmutableObservableList<Observable>(dependencies);
1414                 }
1415             };
1416         }
1417     }
1418 
1419     /**
1420      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
1421      * the sum of the values of two instances of
1422      * {@link javafx.beans.value.ObservableNumberValue}.
1423      *
1424      * @param op1
1425      *            the first operand
1426      * @param op2
1427      *            the second operand
1428      * @return the new {@code NumberBinding}
1429      * @throws NullPointerException
1430      *             if one of the operands is {@code null}
1431      */
1432     public static NumberBinding add(final ObservableNumberValue op1, final ObservableNumberValue op2) {
1433         return Bindings.add(op1, op2, op1, op2);
1434     }
1435 
1436     /**
1437      * Creates a new {@link javafx.beans.binding.DoubleBinding} that calculates
1438      * the sum of the value of a
1439      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
1440      *
1441      * @param op1
1442      *            the {@code ObservableNumberValue}
1443      * @param op2
1444      *            the constant value
1445      * @return the new {@code DoubleBinding}
1446      * @throws NullPointerException
1447      *             if the {@code ObservableNumberValue} is {@code null}
1448      */
1449     public static DoubleBinding add(final ObservableNumberValue op1, double op2) {
1450         return (DoubleBinding) Bindings.add(op1, DoubleConstant.valueOf(op2), op1);
1451     }
1452 
1453     /**
1454      * Creates a new {@link javafx.beans.binding.DoubleBinding} that calculates
1455      * the sum of the value of a
1456      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
1457      *
1458      * @param op1
1459      *            the constant value
1460      * @param op2
1461      *            the {@code ObservableNumberValue}
1462      * @return the new {@code DoubleBinding}
1463      * @throws NullPointerException
1464      *             if the {@code ObservableNumberValue} is {@code null}
1465      */
1466     public static DoubleBinding add(double op1, final ObservableNumberValue op2) {
1467         return (DoubleBinding) Bindings.add(DoubleConstant.valueOf(op1), op2, op2);
1468     }
1469 
1470     /**
1471      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
1472      * the sum of the value of a
1473      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
1474      *
1475      * @param op1
1476      *            the {@code ObservableNumberValue}
1477      * @param op2
1478      *            the constant value
1479      * @return the new {@code NumberBinding}
1480      * @throws NullPointerException
1481      *             if the {@code ObservableNumberValue} is {@code null}
1482      */
1483     public static NumberBinding add(final ObservableNumberValue op1, float op2) {
1484         return Bindings.add(op1, FloatConstant.valueOf(op2), op1);
1485     }
1486 
1487     /**
1488      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
1489      * the sum of the value of a
1490      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
1491      *
1492      * @param op1
1493      *            the constant value
1494      * @param op2
1495      *            the {@code ObservableNumberValue}
1496      * @return the new {@code NumberBinding}
1497      * @throws NullPointerException
1498      *             if the {@code ObservableNumberValue} is {@code null}
1499      */
1500     public static NumberBinding add(float op1, final ObservableNumberValue op2) {
1501         return Bindings.add(FloatConstant.valueOf(op1), op2, op2);
1502     }
1503 
1504     /**
1505      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
1506      * the sum of the value of a
1507      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
1508      *
1509      * @param op1
1510      *            the {@code ObservableNumberValue}
1511      * @param op2
1512      *            the constant value
1513      * @return the new {@code NumberBinding}
1514      * @throws NullPointerException
1515      *             if the {@code ObservableNumberValue} is {@code null}
1516      */
1517     public static NumberBinding add(final ObservableNumberValue op1, long op2) {
1518         return Bindings.add(op1, LongConstant.valueOf(op2), op1);
1519     }
1520 
1521     /**
1522      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
1523      * the sum of the value of a
1524      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
1525      *
1526      * @param op1
1527      *            the constant value
1528      * @param op2
1529      *            the {@code ObservableNumberValue}
1530      * @return the new {@code NumberBinding}
1531      * @throws NullPointerException
1532      *             if the {@code ObservableNumberValue} is {@code null}
1533      */
1534     public static NumberBinding add(long op1, final ObservableNumberValue op2) {
1535         return Bindings.add(LongConstant.valueOf(op1), op2, op2);
1536     }
1537 
1538     /**
1539      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
1540      * the sum of the value of a
1541      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
1542      *
1543      * @param op1
1544      *            the {@code ObservableNumberValue}
1545      * @param op2
1546      *            the constant value
1547      * @return the new {@code NumberBinding}
1548      * @throws NullPointerException
1549      *             if the {@code ObservableNumberValue} is {@code null}
1550      */
1551     public static NumberBinding add(final ObservableNumberValue op1, int op2) {
1552         return Bindings.add(op1, IntegerConstant.valueOf(op2), op1);
1553     }
1554 
1555     /**
1556      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
1557      * the sum of the value of a
1558      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
1559      *
1560      * @param op1
1561      *            the constant value
1562      * @param op2
1563      *            the {@code ObservableNumberValue}
1564      * @return the new {@code NumberBinding}
1565      * @throws NullPointerException
1566      *             if the {@code ObservableNumberValue} is {@code null}
1567      */
1568     public static NumberBinding add(int op1, final ObservableNumberValue op2) {
1569         return Bindings.add(IntegerConstant.valueOf(op1), op2, op2);
1570     }
1571 
1572     // =================================================================================================================
1573     // Diff
1574 
1575     private static NumberBinding subtract(final ObservableNumberValue op1, final ObservableNumberValue op2, final Observable... dependencies) {
1576         if ((op1 == null) || (op2 == null)) {
1577             throw new NullPointerException("Operands cannot be null.");
1578         }
1579         assert (dependencies != null) && (dependencies.length > 0);
1580 
1581         if ((op1 instanceof ObservableDoubleValue) || (op2 instanceof ObservableDoubleValue)) {
1582             return new DoubleBinding() {
1583                 {
1584                     super.bind(dependencies);
1585                 }
1586 
1587                 @Override
1588                 public void dispose() {
1589                     super.unbind(dependencies);
1590                 }
1591 
1592                 @Override
1593                 protected double computeValue() {
1594                     return op1.doubleValue() - op2.doubleValue();
1595                 }
1596 
1597                 @Override
1598                 public ObservableList<?> getDependencies() {
1599                     return (dependencies.length == 1)?
1600                             FXCollections.singletonObservableList(dependencies[0])
1601                             : new ImmutableObservableList<Observable>(dependencies);
1602                 }
1603             };
1604         } else if ((op1 instanceof ObservableFloatValue) || (op2 instanceof ObservableFloatValue)) {
1605             return new FloatBinding() {
1606                 {
1607                     super.bind(dependencies);
1608                 }
1609 
1610                 @Override
1611                 public void dispose() {
1612                     super.unbind(dependencies);
1613                 }
1614 
1615                 @Override
1616                 protected float computeValue() {
1617                     return op1.floatValue() - op2.floatValue();
1618                 }
1619 
1620                 @Override
1621                 public ObservableList<?> getDependencies() {
1622                     return (dependencies.length == 1)?
1623                             FXCollections.singletonObservableList(dependencies[0])
1624                             : new ImmutableObservableList<Observable>(dependencies);
1625                 }
1626             };
1627         } else if ((op1 instanceof ObservableLongValue) || (op2 instanceof ObservableLongValue)) {
1628             return new LongBinding() {
1629                 {
1630                     super.bind(dependencies);
1631                 }
1632 
1633                 @Override
1634                 public void dispose() {
1635                     super.unbind(dependencies);
1636                 }
1637 
1638                 @Override
1639                 protected long computeValue() {
1640                     return op1.longValue() - op2.longValue();
1641                 }
1642 
1643                 @Override
1644                 public ObservableList<?> getDependencies() {
1645                     return (dependencies.length == 1)?
1646                             FXCollections.singletonObservableList(dependencies[0])
1647                             : new ImmutableObservableList<Observable>(dependencies);
1648                 }
1649             };
1650         } else {
1651             return new IntegerBinding() {
1652                 {
1653                     super.bind(dependencies);
1654                 }
1655 
1656                 @Override
1657                 public void dispose() {
1658                     super.unbind(dependencies);
1659                 }
1660 
1661                 @Override
1662                 protected int computeValue() {
1663                     return op1.intValue() - op2.intValue();
1664                 }
1665 
1666                 @Override
1667                 public ObservableList<?> getDependencies() {
1668                     return (dependencies.length == 1)?
1669                             FXCollections.singletonObservableList(dependencies[0])
1670                             : new ImmutableObservableList<Observable>(dependencies);
1671                 }
1672             };
1673         }
1674     }
1675 
1676     /**
1677      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
1678      * the difference of the values of two instances of
1679      * {@link javafx.beans.value.ObservableNumberValue}.
1680      *
1681      * @param op1
1682      *            the first operand
1683      * @param op2
1684      *            the second operand
1685      * @return the new {@code NumberBinding}
1686      * @throws NullPointerException
1687      *             if one of the operands is {@code null}
1688      */
1689     public static NumberBinding subtract(final ObservableNumberValue op1, final ObservableNumberValue op2) {
1690         return Bindings.subtract(op1, op2, op1, op2);
1691     }
1692 
1693     /**
1694      * Creates a new {@link javafx.beans.binding.DoubleBinding} that calculates
1695      * the difference of the value of a
1696      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
1697      *
1698      * @param op1
1699      *            the {@code ObservableNumberValue}
1700      * @param op2
1701      *            the constant value
1702      * @return the new {@code DoubleBinding}
1703      * @throws NullPointerException
1704      *             if the {@code ObservableNumberValue} is {@code null}
1705      */
1706     public static DoubleBinding subtract(final ObservableNumberValue op1, double op2) {
1707         return (DoubleBinding) Bindings.subtract(op1, DoubleConstant.valueOf(op2), op1);
1708     }
1709 
1710     /**
1711      * Creates a new {@link javafx.beans.binding.DoubleBinding} that calculates
1712      * the difference of a constant value and the value of a
1713      * {@link javafx.beans.value.ObservableNumberValue}.
1714      *
1715      * @param op1
1716      *            the constant value
1717      * @param op2
1718      *            the {@code ObservableNumberValue}
1719      * @return the new {@code DoubleBinding}
1720      * @throws NullPointerException
1721      *             if the {@code ObservableNumberValue} is {@code null}
1722      */
1723     public static DoubleBinding subtract(double op1, final ObservableNumberValue op2) {
1724         return (DoubleBinding) Bindings.subtract(DoubleConstant.valueOf(op1), op2, op2);
1725     }
1726 
1727     /**
1728      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
1729      * the difference of the value of a
1730      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
1731      *
1732      * @param op1
1733      *            the constant value
1734      * @param op2
1735      *            the {@code ObservableNumberValue}
1736      * @return the new {@code NumberBinding}
1737      * @throws NullPointerException
1738      *             if the {@code ObservableNumberValue} is {@code null}
1739      */
1740     public static NumberBinding subtract(final ObservableNumberValue op1, float op2) {
1741         return Bindings.subtract(op1, FloatConstant.valueOf(op2), op1);
1742     }
1743 
1744     /**
1745      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
1746      * the difference of a constant value and the value of a
1747      * {@link javafx.beans.value.ObservableNumberValue}.
1748      *
1749      * @param op1
1750      *            the {@code ObservableNumberValue}
1751      * @param op2
1752      *            the constant value
1753      * @return the new {@code NumberBinding}
1754      * @throws NullPointerException
1755      *             if the {@code ObservableNumberValue} is {@code null}
1756      */
1757     public static NumberBinding subtract(float op1, final ObservableNumberValue op2) {
1758         return Bindings.subtract(FloatConstant.valueOf(op1), op2, op2);
1759     }
1760 
1761     /**
1762      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
1763      * the difference of the value of a
1764      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
1765      *
1766      * @param op1
1767      *            the constant value
1768      * @param op2
1769      *            the {@code ObservableNumberValue}
1770      * @return the new {@code NumberBinding}
1771      * @throws NullPointerException
1772      *             if the {@code ObservableNumberValue} is {@code null}
1773      */
1774     public static NumberBinding subtract(final ObservableNumberValue op1, long op2) {
1775         return Bindings.subtract(op1, LongConstant.valueOf(op2), op1);
1776     }
1777 
1778     /**
1779      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
1780      * the difference of a constant value and the value of a
1781      * {@link javafx.beans.value.ObservableNumberValue}.
1782      *
1783      * @param op1
1784      *            the {@code ObservableNumberValue}
1785      * @param op2
1786      *            the constant value
1787      * @return the new {@code NumberBinding}
1788      * @throws NullPointerException
1789      *             if the {@code ObservableNumberValue} is {@code null}
1790      */
1791     public static NumberBinding subtract(long op1, final ObservableNumberValue op2) {
1792         return Bindings.subtract(LongConstant.valueOf(op1), op2, op2);
1793     }
1794 
1795     /**
1796      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
1797      * the difference of the value of a
1798      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
1799      *
1800      * @param op1
1801      *            the constant value
1802      * @param op2
1803      *            the {@code ObservableNumberValue}
1804      * @return the new {@code NumberBinding}
1805      * @throws NullPointerException
1806      *             if the {@code ObservableNumberValue} is {@code null}
1807      */
1808     public static NumberBinding subtract(final ObservableNumberValue op1, int op2) {
1809         return Bindings.subtract(op1, IntegerConstant.valueOf(op2), op1);
1810     }
1811 
1812     /**
1813      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
1814      * the difference of a constant value and the value of a
1815      * {@link javafx.beans.value.ObservableNumberValue}.
1816      *
1817      * @param op1
1818      *            the {@code ObservableNumberValue}
1819      * @param op2
1820      *            the constant value
1821      * @return the new {@code NumberBinding}
1822      * @throws NullPointerException
1823      *             if the {@code ObservableNumberValue} is {@code null}
1824      */
1825     public static NumberBinding subtract(int op1, final ObservableNumberValue op2) {
1826         return Bindings.subtract(IntegerConstant.valueOf(op1), op2, op2);
1827     }
1828 
1829     // =================================================================================================================
1830     // Multiply
1831 
1832     private static NumberBinding multiply(final ObservableNumberValue op1, final ObservableNumberValue op2, final Observable... dependencies) {
1833         if ((op1 == null) || (op2 == null)) {
1834             throw new NullPointerException("Operands cannot be null.");
1835         }
1836         assert (dependencies != null) && (dependencies.length > 0);
1837 
1838         if ((op1 instanceof ObservableDoubleValue) || (op2 instanceof ObservableDoubleValue)) {
1839             return new DoubleBinding() {
1840                 {
1841                     super.bind(dependencies);
1842                 }
1843 
1844                 @Override
1845                 public void dispose() {
1846                     super.unbind(dependencies);
1847                 }
1848 
1849                 @Override
1850                 protected double computeValue() {
1851                     return op1.doubleValue() * op2.doubleValue();
1852                 }
1853 
1854                 @Override
1855                 public ObservableList<?> getDependencies() {
1856                     return (dependencies.length == 1)?
1857                             FXCollections.singletonObservableList(dependencies[0])
1858                             : new ImmutableObservableList<Observable>(dependencies);
1859                 }
1860             };
1861         } else if ((op1 instanceof ObservableFloatValue) || (op2 instanceof ObservableFloatValue)) {
1862             return new FloatBinding() {
1863                 {
1864                     super.bind(dependencies);
1865                 }
1866 
1867                 @Override
1868                 public void dispose() {
1869                     super.unbind(dependencies);
1870                 }
1871 
1872                 @Override
1873                 protected float computeValue() {
1874                     return op1.floatValue() * op2.floatValue();
1875                 }
1876 
1877                 @Override
1878                 public ObservableList<?> getDependencies() {
1879                     return (dependencies.length == 1)?
1880                             FXCollections.singletonObservableList(dependencies[0])
1881                             : new ImmutableObservableList<Observable>(dependencies);
1882                 }
1883             };
1884         } else if ((op1 instanceof ObservableLongValue) || (op2 instanceof ObservableLongValue)) {
1885             return new LongBinding() {
1886                 {
1887                     super.bind(dependencies);
1888                 }
1889 
1890                 @Override
1891                 public void dispose() {
1892                     super.unbind(dependencies);
1893                 }
1894 
1895                 @Override
1896                 protected long computeValue() {
1897                     return op1.longValue() * op2.longValue();
1898                 }
1899 
1900                 @Override
1901                 public ObservableList<?> getDependencies() {
1902                     return (dependencies.length == 1)?
1903                             FXCollections.singletonObservableList(dependencies[0])
1904                             : new ImmutableObservableList<Observable>(dependencies);
1905                 }
1906             };
1907         } else {
1908             return new IntegerBinding() {
1909                 {
1910                     super.bind(dependencies);
1911                 }
1912 
1913                 @Override
1914                 public void dispose() {
1915                     super.unbind(dependencies);
1916                 }
1917 
1918                 @Override
1919                 protected int computeValue() {
1920                     return op1.intValue() * op2.intValue();
1921                 }
1922 
1923                 @Override
1924                 public ObservableList<?> getDependencies() {
1925                     return (dependencies.length == 1)?
1926                             FXCollections.singletonObservableList(dependencies[0])
1927                             : new ImmutableObservableList<Observable>(dependencies);
1928                 }
1929             };
1930         }
1931     }
1932 
1933     /**
1934      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
1935      * the product of the values of two instances of
1936      * {@link javafx.beans.value.ObservableNumberValue}.
1937      *
1938      * @param op1
1939      *            the first operand
1940      * @param op2
1941      *            the second operand
1942      * @return the new {@code NumberBinding}
1943      * @throws NullPointerException
1944      *             if one of the operands is {@code null}
1945      */
1946     public static NumberBinding multiply(final ObservableNumberValue op1, final ObservableNumberValue op2) {
1947         return Bindings.multiply(op1, op2, op1, op2);
1948     }
1949 
1950     /**
1951      * Creates a new {@link javafx.beans.binding.DoubleBinding} that calculates
1952      * the product of the value of a
1953      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
1954      *
1955      * @param op1
1956      *            the {@code ObservableNumberValue}
1957      * @param op2
1958      *            the constant value
1959      * @return the new {@code DoubleBinding}
1960      * @throws NullPointerException
1961      *             if the {@code ObservableNumberValue} is {@code null}
1962      */
1963     public static DoubleBinding multiply(final ObservableNumberValue op1, double op2) {
1964         return (DoubleBinding) Bindings.multiply(op1, DoubleConstant.valueOf(op2), op1);
1965     }
1966 
1967     /**
1968      * Creates a new {@link javafx.beans.binding.DoubleBinding} that calculates
1969      * the product of the value of a
1970      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
1971      *
1972      * @param op1
1973      *            the constant value
1974      * @param op2
1975      *            the {@code ObservableNumberValue}
1976      * @return the new {@code DoubleBinding}
1977      * @throws NullPointerException
1978      *             if the {@code ObservableNumberValue} is {@code null}
1979      */
1980     public static DoubleBinding multiply(double op1, final ObservableNumberValue op2) {
1981         return (DoubleBinding) Bindings.multiply(DoubleConstant.valueOf(op1), op2, op2);
1982     }
1983 
1984     /**
1985      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
1986      * the product of the value of a
1987      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
1988      *
1989      * @param op1
1990      *            the constant value
1991      * @param op2
1992      *            the {@code ObservableNumberValue}
1993      * @return the new {@code NumberBinding}
1994      * @throws NullPointerException
1995      *             if the {@code ObservableNumberValue} is {@code null}
1996      */
1997     public static NumberBinding multiply(final ObservableNumberValue op1, float op2) {
1998         return Bindings.multiply(op1, FloatConstant.valueOf(op2), op1);
1999     }
2000 
2001     /**
2002      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
2003      * the product of the value of a
2004      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
2005      *
2006      * @param op1
2007      *            the constant value
2008      * @param op2
2009      *            the {@code ObservableNumberValue}
2010      * @return the new {@code NumberBinding}
2011      * @throws NullPointerException
2012      *             if the {@code ObservableNumberValue} is {@code null}
2013      */
2014     public static NumberBinding multiply(float op1, final ObservableNumberValue op2) {
2015         return Bindings.multiply(FloatConstant.valueOf(op1), op2, op2);
2016     }
2017 
2018     /**
2019      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
2020      * the product of the value of a
2021      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
2022      *
2023      * @param op1
2024      *            the constant value
2025      * @param op2
2026      *            the {@code ObservableNumberValue}
2027      * @return the new {@code NumberBinding}
2028      * @throws NullPointerException
2029      *             if the {@code ObservableNumberValue} is {@code null}
2030      */
2031     public static NumberBinding multiply(final ObservableNumberValue op1, long op2) {
2032         return Bindings.multiply(op1, LongConstant.valueOf(op2), op1);
2033     }
2034 
2035     /**
2036      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
2037      * the product of the value of a
2038      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
2039      *
2040      * @param op1
2041      *            the constant value
2042      * @param op2
2043      *            the {@code ObservableNumberValue}
2044      * @return the new {@code NumberBinding}
2045      * @throws NullPointerException
2046      *             if the {@code ObservableNumberValue} is {@code null}
2047      */
2048     public static NumberBinding multiply(long op1, final ObservableNumberValue op2) {
2049         return Bindings.multiply(LongConstant.valueOf(op1), op2, op2);
2050     }
2051 
2052     /**
2053      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
2054      * the product of the value of a
2055      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
2056      *
2057      * @param op1
2058      *            the constant value
2059      * @param op2
2060      *            the {@code ObservableNumberValue}
2061      * @return the new {@code NumberBinding}
2062      * @throws NullPointerException
2063      *             if the {@code ObservableNumberValue} is {@code null}
2064      */
2065     public static NumberBinding multiply(final ObservableNumberValue op1, int op2) {
2066         return Bindings.multiply(op1, IntegerConstant.valueOf(op2), op1);
2067     }
2068 
2069     /**
2070      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
2071      * the product of the value of a
2072      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
2073      *
2074      * @param op1
2075      *            the constant value
2076      * @param op2
2077      *            the {@code ObservableNumberValue}
2078      * @return the new {@code NumberBinding}
2079      * @throws NullPointerException
2080      *             if the {@code ObservableNumberValue} is {@code null}
2081      */
2082     public static NumberBinding multiply(int op1, final ObservableNumberValue op2) {
2083         return Bindings.multiply(IntegerConstant.valueOf(op1), op2, op2);
2084     }
2085 
2086     // =================================================================================================================
2087     // Divide
2088 
2089     private static NumberBinding divide(final ObservableNumberValue op1, final ObservableNumberValue op2, final Observable... dependencies) {
2090         if ((op1 == null) || (op2 == null)) {
2091             throw new NullPointerException("Operands cannot be null.");
2092         }
2093         assert (dependencies != null) && (dependencies.length > 0);
2094 
2095         if ((op1 instanceof ObservableDoubleValue) || (op2 instanceof ObservableDoubleValue)) {
2096             return new DoubleBinding() {
2097                 {
2098                     super.bind(dependencies);
2099                 }
2100 
2101                 @Override
2102                 public void dispose() {
2103                     super.unbind(dependencies);
2104                 }
2105 
2106                 @Override
2107                 protected double computeValue() {
2108                     return op1.doubleValue() / op2.doubleValue();
2109                 }
2110 
2111                 @Override
2112                 public ObservableList<?> getDependencies() {
2113                     return (dependencies.length == 1)?
2114                             FXCollections.singletonObservableList(dependencies[0])
2115                             : new ImmutableObservableList<Observable>(dependencies);
2116                 }
2117             };
2118         } else if ((op1 instanceof ObservableFloatValue) || (op2 instanceof ObservableFloatValue)) {
2119             return new FloatBinding() {
2120                 {
2121                     super.bind(dependencies);
2122                 }
2123 
2124                 @Override
2125                 public void dispose() {
2126                     super.unbind(dependencies);
2127                 }
2128 
2129                 @Override
2130                 protected float computeValue() {
2131                     return op1.floatValue() / op2.floatValue();
2132                 }
2133 
2134                 @Override
2135                 public ObservableList<?> getDependencies() {
2136                     return (dependencies.length == 1)?
2137                             FXCollections.singletonObservableList(dependencies[0])
2138                             : new ImmutableObservableList<Observable>(dependencies);
2139                 }
2140             };
2141         } else if ((op1 instanceof ObservableLongValue) || (op2 instanceof ObservableLongValue)) {
2142             return new LongBinding() {
2143                 {
2144                     super.bind(dependencies);
2145                 }
2146 
2147                 @Override
2148                 public void dispose() {
2149                     super.unbind(dependencies);
2150                 }
2151 
2152                 @Override
2153                 protected long computeValue() {
2154                     return op1.longValue() / op2.longValue();
2155                 }
2156 
2157                 @Override
2158                 public ObservableList<?> getDependencies() {
2159                     return (dependencies.length == 1)?
2160                             FXCollections.singletonObservableList(dependencies[0])
2161                             : new ImmutableObservableList<Observable>(dependencies);
2162                 }
2163             };
2164         } else {
2165             return new IntegerBinding() {
2166                 {
2167                     super.bind(dependencies);
2168                 }
2169 
2170                 @Override
2171                 public void dispose() {
2172                     super.unbind(dependencies);
2173                 }
2174 
2175                 @Override
2176                 protected int computeValue() {
2177                     return op1.intValue() / op2.intValue();
2178                 }
2179 
2180                 @Override
2181                 public ObservableList<?> getDependencies() {
2182                     return (dependencies.length == 1)?
2183                             FXCollections.singletonObservableList(dependencies[0])
2184                             : new ImmutableObservableList<Observable>(dependencies);
2185                 }
2186             };
2187         }
2188     }
2189 
2190     /**
2191      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
2192      * the division of the values of two instances of
2193      * {@link javafx.beans.value.ObservableNumberValue}.
2194      *
2195      * @param op1
2196      *            the first operand
2197      * @param op2
2198      *            the second operand
2199      * @return the new {@code NumberBinding}
2200      * @throws NullPointerException
2201      *             if one of the operands is {@code null}
2202      */
2203     public static NumberBinding divide(final ObservableNumberValue op1, final ObservableNumberValue op2) {
2204         return Bindings.divide(op1, op2, op1, op2);
2205     }
2206 
2207     /**
2208      * Creates a new {@link javafx.beans.binding.DoubleBinding} that calculates
2209      * the division of the value of a
2210      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
2211      *
2212      * @param op1
2213      *            the {@code ObservableNumberValue}
2214      * @param op2
2215      *            the constant value
2216      * @return the new {@code DoubleBinding}
2217      * @throws NullPointerException
2218      *             if the {@code ObservableNumberValue} is {@code null}
2219      */
2220     public static DoubleBinding divide(final ObservableNumberValue op1, double op2) {
2221         return (DoubleBinding) Bindings.divide(op1, DoubleConstant.valueOf(op2), op1);
2222     }
2223 
2224     /**
2225      * Creates a new {@link javafx.beans.binding.DoubleBinding} that calculates
2226      * the division of a constant value and the value of a
2227      * {@link javafx.beans.value.ObservableNumberValue}.
2228      *
2229      * @param op1
2230      *            the constant value
2231      * @param op2
2232      *            the {@code ObservableNumberValue}
2233      * @return the new {@code DoubleBinding}
2234      * @throws NullPointerException
2235      *             if the {@code ObservableNumberValue} is {@code null}
2236      */
2237     public static DoubleBinding divide(double op1, final ObservableNumberValue op2) {
2238         return (DoubleBinding) Bindings.divide(DoubleConstant.valueOf(op1), op2, op2);
2239     }
2240 
2241     /**
2242      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
2243      * the division of the value of a
2244      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
2245      *
2246      * @param op1
2247      *            the constant value
2248      * @param op2
2249      *            the {@code ObservableNumberValue}
2250      * @return the new {@code NumberBinding}
2251      * @throws NullPointerException
2252      *             if the {@code ObservableNumberValue} is {@code null}
2253      */
2254     public static NumberBinding divide(final ObservableNumberValue op1, float op2) {
2255         return Bindings.divide(op1, FloatConstant.valueOf(op2), op1);
2256     }
2257 
2258     /**
2259      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
2260      * the division of a constant value and the value of a
2261      * {@link javafx.beans.value.ObservableNumberValue}.
2262      *
2263      * @param op1
2264      *            the {@code ObservableNumberValue}
2265      * @param op2
2266      *            the constant value
2267      * @return the new {@code NumberBinding}
2268      * @throws NullPointerException
2269      *             if the {@code ObservableNumberValue} is {@code null}
2270      */
2271     public static NumberBinding divide(float op1, final ObservableNumberValue op2) {
2272         return Bindings.divide(FloatConstant.valueOf(op1), op2, op2);
2273     }
2274 
2275     /**
2276      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
2277      * the division of the value of a
2278      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
2279      *
2280      * @param op1
2281      *            the constant value
2282      * @param op2
2283      *            the {@code ObservableNumberValue}
2284      * @return the new {@code NumberBinding}
2285      * @throws NullPointerException
2286      *             if the {@code ObservableNumberValue} is {@code null}
2287      */
2288     public static NumberBinding divide(final ObservableNumberValue op1, long op2) {
2289         return Bindings.divide(op1, LongConstant.valueOf(op2), op1);
2290     }
2291 
2292     /**
2293      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
2294      * the division of a constant value and the value of a
2295      * {@link javafx.beans.value.ObservableNumberValue}.
2296      *
2297      * @param op1
2298      *            the {@code ObservableNumberValue}
2299      * @param op2
2300      *            the constant value
2301      * @return the new {@code NumberBinding}
2302      * @throws NullPointerException
2303      *             if the {@code ObservableNumberValue} is {@code null}
2304      */
2305     public static NumberBinding divide(long op1, final ObservableNumberValue op2) {
2306         return Bindings.divide(LongConstant.valueOf(op1), op2, op2);
2307     }
2308 
2309     /**
2310      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
2311      * the division of the value of a
2312      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
2313      *
2314      * @param op1
2315      *            the constant value
2316      * @param op2
2317      *            the {@code ObservableNumberValue}
2318      * @return the new {@code NumberBinding}
2319      * @throws NullPointerException
2320      *             if the {@code ObservableNumberValue} is {@code null}
2321      */
2322     public static NumberBinding divide(final ObservableNumberValue op1, int op2) {
2323         return Bindings.divide(op1, IntegerConstant.valueOf(op2), op1);
2324     }
2325 
2326     /**
2327      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
2328      * the division of a constant value and the value of a
2329      * {@link javafx.beans.value.ObservableNumberValue}.
2330      *
2331      * @param op1
2332      *            the {@code ObservableNumberValue}
2333      * @param op2
2334      *            the constant value
2335      * @return the new {@code NumberBinding}
2336      * @throws NullPointerException
2337      *             if the {@code ObservableNumberValue} is {@code null}
2338      */
2339     public static NumberBinding divide(int op1, final ObservableNumberValue op2) {
2340         return Bindings.divide(IntegerConstant.valueOf(op1), op2, op2);
2341     }
2342 
2343     // =================================================================================================================
2344     // Equals
2345 
2346     private static BooleanBinding equal(final ObservableNumberValue op1, final ObservableNumberValue op2, final double epsilon, final Observable... dependencies) {
2347         if ((op1 == null) || (op2 == null)) {
2348             throw new NullPointerException("Operands cannot be null.");
2349         }
2350         assert (dependencies != null) && (dependencies.length > 0);
2351 
2352         if ((op1 instanceof ObservableDoubleValue) || (op2 instanceof ObservableDoubleValue)) {
2353             return new BooleanBinding() {
2354                 {
2355                     super.bind(dependencies);
2356                 }
2357 
2358                 @Override
2359                 public void dispose() {
2360                     super.unbind(dependencies);
2361                 }
2362 
2363                 @Override
2364                 protected boolean computeValue() {
2365                     return Math.abs(op1.doubleValue() - op2.doubleValue()) <= epsilon;
2366                 }
2367 
2368                 @Override
2369                 public ObservableList<?> getDependencies() {
2370                     return (dependencies.length == 1)?
2371                             FXCollections.singletonObservableList(dependencies[0])
2372                             : new ImmutableObservableList<Observable>(dependencies);
2373                 }
2374             };
2375         } else if ((op1 instanceof ObservableFloatValue) || (op2 instanceof ObservableFloatValue)) {
2376             return new BooleanBinding() {
2377                 {
2378                     super.bind(dependencies);
2379                 }
2380 
2381                 @Override
2382                 public void dispose() {
2383                     super.unbind(dependencies);
2384                 }
2385 
2386                 @Override
2387                 protected boolean computeValue() {
2388                     return Math.abs(op1.floatValue() - op2.floatValue()) <= epsilon;
2389                 }
2390 
2391                 @Override
2392                 public ObservableList<?> getDependencies() {
2393                     return (dependencies.length == 1)?
2394                             FXCollections.singletonObservableList(dependencies[0])
2395                             : new ImmutableObservableList<Observable>(dependencies);
2396                 }
2397             };
2398         } else if ((op1 instanceof ObservableLongValue) || (op2 instanceof ObservableLongValue)) {
2399             return new BooleanBinding() {
2400                 {
2401                     super.bind(dependencies);
2402                 }
2403 
2404                 @Override
2405                 public void dispose() {
2406                     super.unbind(dependencies);
2407                 }
2408 
2409                 @Override
2410                 protected boolean computeValue() {
2411                     return Math.abs(op1.longValue() - op2.longValue()) <= epsilon;
2412                 }
2413 
2414                 @Override
2415                 public ObservableList<?> getDependencies() {
2416                     return (dependencies.length == 1)?
2417                             FXCollections.singletonObservableList(dependencies[0])
2418                             : new ImmutableObservableList<Observable>(dependencies);
2419                 }
2420             };
2421         } else {
2422             return new BooleanBinding() {
2423                 {
2424                     super.bind(dependencies);
2425                 }
2426 
2427                 @Override
2428                 public void dispose() {
2429                     super.unbind(dependencies);
2430                 }
2431 
2432                 @Override
2433                 protected boolean computeValue() {
2434                     return Math.abs(op1.intValue() - op2.intValue()) <= epsilon;
2435                 }
2436 
2437                 @Override
2438                 public ObservableList<?> getDependencies() {
2439                     return (dependencies.length == 1)?
2440                             FXCollections.singletonObservableList(dependencies[0])
2441                             : new ImmutableObservableList<Observable>(dependencies);
2442                 }
2443             };
2444         }
2445     }
2446 
2447     /**
2448      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
2449      * if the values of two instances of
2450      * {@link javafx.beans.value.ObservableNumberValue} are equal (with a
2451      * tolerance).
2452      * <p>
2453      * Two operands {@code a} and {@code b} are considered equal if
2454      * {@code Math.abs(a-b) <= epsilon}.
2455      * <p>
2456      * Allowing a small tolerance is recommended when comparing floating-point
2457      * numbers because of rounding-errors.
2458      *
2459      * @param op1
2460      *            the first operand
2461      * @param op2
2462      *            the second operand
2463      * @param epsilon
2464      *            the permitted tolerance
2465      * @return the new {@code BooleanBinding}
2466      * @throws NullPointerException
2467      *             if one of the operands is {@code null}
2468      */
2469     public static BooleanBinding equal(final ObservableNumberValue op1, final ObservableNumberValue op2, final double epsilon) {
2470         return Bindings.equal(op1, op2, epsilon, op1, op2);
2471     }
2472 
2473     /**
2474      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
2475      * if the values of two instances of
2476      * {@link javafx.beans.value.ObservableNumberValue} are equal.
2477      * <p>
2478      * When comparing floating-point numbers it is recommended to use the
2479      * {@link #equal(ObservableNumberValue, ObservableNumberValue, double)
2480      * equal()} method that allows a small tolerance.
2481      *
2482      * @param op1
2483      *            the first operand
2484      * @param op2
2485      *            the second operand
2486      * @return the new {@code BooleanBinding}
2487      * @throws NullPointerException
2488      *             if one of the operands is {@code null}
2489      */
2490     public static BooleanBinding equal(final ObservableNumberValue op1, final ObservableNumberValue op2) {
2491         return equal(op1, op2, 0.0, op1, op2);
2492     }
2493 
2494     /**
2495      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
2496      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
2497      * equal to a constant value (with a tolerance).
2498      * <p>
2499      * Two operands {@code a} and {@code b} are considered equal if
2500      * {@code Math.abs(a-b) <= epsilon}.
2501      * <p>
2502      * Allowing a small tolerance is recommended when comparing floating-point
2503      * numbers because of rounding-errors.
2504      *
2505      * @param op1
2506      *            the {@code ObservableNumberValue}
2507      * @param op2
2508      *            the constant value
2509      * @param epsilon
2510      *            the permitted tolerance
2511      * @return the new {@code BooleanBinding}
2512      * @throws NullPointerException
2513      *             if the {@code ObservableNumberValue} is {@code null}
2514      */
2515     public static BooleanBinding equal(final ObservableNumberValue op1, final double op2, final double epsilon) {
2516         return equal(op1, DoubleConstant.valueOf(op2), epsilon,  op1);
2517     }
2518 
2519     /**
2520      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
2521      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
2522      * equal to a constant value (with a tolerance).
2523      * <p>
2524      * Two operands {@code a} and {@code b} are considered equal if
2525      * {@code Math.abs(a-b) <= epsilon}.
2526      * <p>
2527      * Allowing a small tolerance is recommended when comparing floating-point
2528      * numbers because of rounding-errors.
2529      *
2530      * @param op1
2531      *            the constant value
2532      * @param op2
2533      *            the {@code ObservableNumberValue}
2534      * @param epsilon
2535      *            the permitted tolerance
2536      * @return the new {@code BooleanBinding}
2537      * @throws NullPointerException
2538      *             if the {@code ObservableNumberValue} is {@code null}
2539      */
2540     public static BooleanBinding equal(final double op1, final ObservableNumberValue op2, final double epsilon) {
2541         return equal(DoubleConstant.valueOf(op1), op2, epsilon, op2);
2542     }
2543 
2544     /**
2545      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
2546      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
2547      * equal to a constant value (with a tolerance).
2548      * <p>
2549      * Two operands {@code a} and {@code b} are considered equal if
2550      * {@code Math.abs(a-b) <= epsilon}.
2551      * <p>
2552      * Allowing a small tolerance is recommended when comparing floating-point
2553      * numbers because of rounding-errors.
2554      *
2555      * @param op1
2556      *            the {@code ObservableNumberValue}
2557      * @param op2
2558      *            the constant value
2559      * @param epsilon
2560      *            the permitted tolerance
2561      * @return the new {@code BooleanBinding}
2562      * @throws NullPointerException
2563      *             if the {@code ObservableNumberValue} is {@code null}
2564      */
2565     public static BooleanBinding equal(final ObservableNumberValue op1, final float op2, final double epsilon) {
2566         return equal(op1, FloatConstant.valueOf(op2), epsilon, op1);
2567     }
2568 
2569     /**
2570      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
2571      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
2572      * equal to a constant value (with a tolerance).
2573      * <p>
2574      * Two operands {@code a} and {@code b} are considered equal if
2575      * {@code Math.abs(a-b) <= epsilon}.
2576      * <p>
2577      * Allowing a small tolerance is recommended when comparing floating-point
2578      * numbers because of rounding-errors.
2579      *
2580      * @param op1
2581      *            the constant value
2582      * @param op2
2583      *            the {@code ObservableNumberValue}
2584      * @param epsilon
2585      *            the permitted tolerance
2586      * @return the new {@code BooleanBinding}
2587      * @throws NullPointerException
2588      *             if the {@code ObservableNumberValue} is {@code null}
2589      */
2590     public static BooleanBinding equal(final float op1, final ObservableNumberValue op2, final double epsilon) {
2591         return equal(FloatConstant.valueOf(op1), op2, epsilon, op2);
2592     }
2593 
2594     /**
2595      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
2596      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
2597      * equal to a constant value (with a tolerance).
2598      * <p>
2599      * Two operands {@code a} and {@code b} are considered equal if
2600      * {@code Math.abs(a-b) <= epsilon}.
2601      * <p>
2602      * Allowing a small tolerance is recommended when comparing floating-point
2603      * numbers because of rounding-errors.
2604      *
2605      * @param op1
2606      *            the {@code ObservableNumberValue}
2607      * @param op2
2608      *            the constant value
2609      * @param epsilon
2610      *            the permitted tolerance
2611      * @return the new {@code BooleanBinding}
2612      * @throws NullPointerException
2613      *             if the {@code ObservableNumberValue} is {@code null}
2614      */
2615     public static BooleanBinding equal(final ObservableNumberValue op1, final long op2, final double epsilon) {
2616         return equal(op1, LongConstant.valueOf(op2), epsilon, op1);
2617     }
2618 
2619     /**
2620      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
2621      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
2622      * equal to a constant value.
2623      * <p>
2624      * When comparing floating-point numbers it is recommended to use the
2625      * {@link #equal(ObservableNumberValue, long, double) equal()} method that
2626      * allows a small tolerance.
2627      *
2628      * @param op1
2629      *            the {@code ObservableNumberValue}
2630      * @param op2
2631      *            the constant value
2632      * @return the new {@code BooleanBinding}
2633      * @throws NullPointerException
2634      *             if the {@code ObservableNumberValue} is {@code null}
2635      */
2636     public static BooleanBinding equal(final ObservableNumberValue op1, final long op2) {
2637         return equal(op1, LongConstant.valueOf(op2), 0.0, op1);
2638     }
2639 
2640     /**
2641      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
2642      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
2643      * equal to a constant value (with a tolerance).
2644      * <p>
2645      * Two operands {@code a} and {@code b} are considered equal if
2646      * {@code Math.abs(a-b) <= epsilon}.
2647      * <p>
2648      * Allowing a small tolerance is recommended when comparing floating-point
2649      * numbers because of rounding-errors.
2650      *
2651      * @param op1
2652      *            the constant value
2653      * @param op2
2654      *            the {@code ObservableNumberValue}
2655      * @param epsilon
2656      *            the permitted tolerance
2657      * @return the new {@code BooleanBinding}
2658      * @throws NullPointerException
2659      *             if the {@code ObservableNumberValue} is {@code null}
2660      */
2661     public static BooleanBinding equal(final long op1, final ObservableNumberValue op2, final double epsilon) {
2662         return equal(LongConstant.valueOf(op1), op2, epsilon, op2);
2663     }
2664 
2665     /**
2666      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
2667      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
2668      * equal to a constant value.
2669      * <p>
2670      * When comparing floating-point numbers it is recommended to use the
2671      * {@link #equal(long, ObservableNumberValue, double) equal()} method that
2672      * allows a small tolerance.
2673      *
2674      * @param op1
2675      *            the constant value
2676      * @param op2
2677      *            the {@code ObservableNumberValue}
2678      * @return the new {@code BooleanBinding}
2679      * @throws NullPointerException
2680      *             if the {@code ObservableNumberValue} is {@code null}
2681      */
2682     public static BooleanBinding equal(final long op1, final ObservableNumberValue op2) {
2683         return equal(LongConstant.valueOf(op1), op2, 0.0, op2);
2684     }
2685 
2686     /**
2687      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
2688      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
2689      * equal to a constant value (with a tolerance).
2690      * <p>
2691      * Two operands {@code a} and {@code b} are considered equal if
2692      * {@code Math.abs(a-b) <= epsilon}.
2693      * <p>
2694      * Allowing a small tolerance is recommended when comparing floating-point
2695      * numbers because of rounding-errors.
2696      *
2697      * @param op1
2698      *            the {@code ObservableNumberValue}
2699      * @param op2
2700      *            the constant value
2701      * @param epsilon
2702      *            the permitted tolerance
2703      * @return the new {@code BooleanBinding}
2704      * @throws NullPointerException
2705      *             if the {@code ObservableNumberValue} is {@code null}
2706      */
2707     public static BooleanBinding equal(final ObservableNumberValue op1, final int op2, final double epsilon) {
2708         return equal(op1, IntegerConstant.valueOf(op2), epsilon, op1);
2709     }
2710 
2711     /**
2712      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
2713      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
2714      * equal to a constant value.
2715      * <p>
2716      * When comparing floating-point numbers it is recommended to use the
2717      * {@link #equal(ObservableNumberValue, int, double) equal()} method that
2718      * allows a small tolerance.
2719      *
2720      * @param op1
2721      *            the {@code ObservableNumberValue}
2722      * @param op2
2723      *            the constant value
2724      * @return the new {@code BooleanBinding}
2725      * @throws NullPointerException
2726      *             if the {@code ObservableNumberValue} is {@code null}
2727      */
2728     public static BooleanBinding equal(final ObservableNumberValue op1, final int op2) {
2729         return equal(op1, IntegerConstant.valueOf(op2), 0.0, op1);
2730     }
2731 
2732     /**
2733      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
2734      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
2735      * equal to a constant value (with a tolerance).
2736      * <p>
2737      * Two operands {@code a} and {@code b} are considered equal if
2738      * {@code Math.abs(a-b) <= epsilon}.
2739      * <p>
2740      * Allowing a small tolerance is recommended when comparing floating-point
2741      * numbers because of rounding-errors.
2742      *
2743      * @param op1
2744      *            the constant value
2745      * @param op2
2746      *            the {@code ObservableNumberValue}
2747      * @param epsilon
2748      *            the permitted tolerance
2749      * @return the new {@code BooleanBinding}
2750      * @throws NullPointerException
2751      *             if the {@code ObservableNumberValue} is {@code null}
2752      */
2753     public static BooleanBinding equal(final int op1, final ObservableNumberValue op2, final double epsilon) {
2754         return equal(IntegerConstant.valueOf(op1), op2, epsilon, op2);
2755     }
2756 
2757     /**
2758      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
2759      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
2760      * equal to a constant value.
2761      * <p>
2762      * When comparing floating-point numbers it is recommended to use the
2763      * {@link #equal(int, ObservableNumberValue, double) equal()} method that
2764      * allows a small tolerance.
2765      *
2766      * @param op1
2767      *            the constant value
2768      * @param op2
2769      *            the {@code ObservableNumberValue}
2770      * @return the new {@code BooleanBinding}
2771      * @throws NullPointerException
2772      *             if the {@code ObservableNumberValue} is {@code null}
2773      */
2774     public static BooleanBinding equal(final int op1, final ObservableNumberValue op2) {
2775         return equal(IntegerConstant.valueOf(op1), op2, 0.0, op2);
2776     }
2777 
2778     // =================================================================================================================
2779     // Not Equal
2780 
2781     private static BooleanBinding notEqual(final ObservableNumberValue op1, final ObservableNumberValue op2, final double epsilon, final Observable... dependencies) {
2782         if ((op1 == null) || (op2 == null)) {
2783             throw new NullPointerException("Operands cannot be null.");
2784         }
2785         assert (dependencies != null) && (dependencies.length > 0);
2786 
2787         if ((op1 instanceof ObservableDoubleValue) || (op2 instanceof ObservableDoubleValue)) {
2788             return new BooleanBinding() {
2789                 {
2790                     super.bind(dependencies);
2791                 }
2792 
2793                 @Override
2794                 public void dispose() {
2795                     super.unbind(dependencies);
2796                 }
2797 
2798                 @Override
2799                 protected boolean computeValue() {
2800                     return Math.abs(op1.doubleValue() - op2.doubleValue()) > epsilon;
2801                 }
2802 
2803                 @Override
2804                 public ObservableList<?> getDependencies() {
2805                     return (dependencies.length == 1)?
2806                             FXCollections.singletonObservableList(dependencies[0])
2807                             : new ImmutableObservableList<Observable>(dependencies);
2808                 }
2809             };
2810         } else if ((op1 instanceof ObservableFloatValue) || (op2 instanceof ObservableFloatValue)) {
2811             return new BooleanBinding() {
2812                 {
2813                     super.bind(dependencies);
2814                 }
2815 
2816                 @Override
2817                 public void dispose() {
2818                     super.unbind(dependencies);
2819                 }
2820 
2821                 @Override
2822                 protected boolean computeValue() {
2823                     return Math.abs(op1.floatValue() - op2.floatValue()) > epsilon;
2824                 }
2825 
2826                 @Override
2827                 public ObservableList<?> getDependencies() {
2828                     return (dependencies.length == 1)?
2829                             FXCollections.singletonObservableList(dependencies[0])
2830                             : new ImmutableObservableList<Observable>(dependencies);
2831                 }
2832             };
2833         } else if ((op1 instanceof ObservableLongValue) || (op2 instanceof ObservableLongValue)) {
2834             return new BooleanBinding() {
2835                 {
2836                     super.bind(dependencies);
2837                 }
2838 
2839                 @Override
2840                 public void dispose() {
2841                     super.unbind(dependencies);
2842                 }
2843 
2844                 @Override
2845                 protected boolean computeValue() {
2846                     return Math.abs(op1.longValue() - op2.longValue()) > epsilon;
2847                 }
2848 
2849                 @Override
2850                 public ObservableList<?> getDependencies() {
2851                     return (dependencies.length == 1)?
2852                             FXCollections.singletonObservableList(dependencies[0])
2853                             : new ImmutableObservableList<Observable>(dependencies);
2854                 }
2855             };
2856         } else {
2857             return new BooleanBinding() {
2858                 {
2859                     super.bind(dependencies);
2860                 }
2861 
2862                 @Override
2863                 public void dispose() {
2864                     super.unbind(dependencies);
2865                 }
2866 
2867                 @Override
2868                 protected boolean computeValue() {
2869                     return Math.abs(op1.intValue() - op2.intValue()) > epsilon;
2870                 }
2871 
2872                 @Override
2873                 public ObservableList<?> getDependencies() {
2874                     return (dependencies.length == 1)?
2875                             FXCollections.singletonObservableList(dependencies[0])
2876                             : new ImmutableObservableList<Observable>(dependencies);
2877                 }
2878             };
2879         }
2880     }
2881 
2882     /**
2883      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
2884      * if the values of two instances of
2885      * {@link javafx.beans.value.ObservableNumberValue} are not equal (with a
2886      * tolerance).
2887      * <p>
2888      * Two operands {@code a} and {@code b} are considered equal if
2889      * {@code Math.abs(a-b) <= epsilon}.
2890      * <p>
2891      * Allowing a small tolerance is recommended when comparing floating-point
2892      * numbers because of rounding-errors.
2893      *
2894      * @param op1
2895      *            the first operand
2896      * @param op2
2897      *            the second operand
2898      * @param epsilon
2899      *            the permitted tolerance
2900      * @return the new {@code BooleanBinding}
2901      * @throws NullPointerException
2902      *             if one of the operands is {@code null}
2903      */
2904     public static BooleanBinding notEqual(final ObservableNumberValue op1, final ObservableNumberValue op2, final double epsilon) {
2905         return Bindings.notEqual(op1, op2, epsilon, op1, op2);
2906     }
2907 
2908     /**
2909      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
2910      * if the values of two instances of
2911      * {@link javafx.beans.value.ObservableNumberValue} are not equal.
2912      * <p>
2913      * When comparing floating-point numbers it is recommended to use the
2914      * {@link #notEqual(ObservableNumberValue, ObservableNumberValue, double)
2915      * notEqual()} method that allows a small tolerance.
2916      *
2917      * @param op1
2918      *            the first operand
2919      * @param op2
2920      *            the second operand
2921      * @return the new {@code BooleanBinding}
2922      * @throws NullPointerException
2923      *             if one of the operands is {@code null}
2924      */
2925     public static BooleanBinding notEqual(final ObservableNumberValue op1, final ObservableNumberValue op2) {
2926         return notEqual(op1, op2, 0.0, op1, op2);
2927     }
2928 
2929     /**
2930      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
2931      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is not
2932      * equal to a constant value (with a tolerance).
2933      * <p>
2934      * Two operands {@code a} and {@code b} are considered equal if
2935      * {@code Math.abs(a-b) <= epsilon}.
2936      * <p>
2937      * Allowing a small tolerance is recommended when comparing floating-point
2938      * numbers because of rounding-errors.
2939      *
2940      * @param op1
2941      *            the {@code ObservableNumberValue}
2942      * @param op2
2943      *            the constant value
2944      * @param epsilon
2945      *            the permitted tolerance
2946      * @return the new {@code BooleanBinding}
2947      * @throws NullPointerException
2948      *             if the {@code ObservableNumberValue} is {@code null}
2949      */
2950     public static BooleanBinding notEqual(final ObservableNumberValue op1, final double op2, final double epsilon) {
2951         return notEqual(op1, DoubleConstant.valueOf(op2), epsilon, op1);
2952     }
2953 
2954     /**
2955      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
2956      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is not
2957      * equal to a constant value (with a tolerance).
2958      * <p>
2959      * Two operands {@code a} and {@code b} are considered equal if
2960      * {@code Math.abs(a-b) <= epsilon}.
2961      * <p>
2962      * Allowing a small tolerance is recommended when comparing floating-point
2963      * numbers because of rounding-errors.
2964      *
2965      * @param op1
2966      *            the constant value
2967      * @param op2
2968      *            the {@code ObservableNumberValue}
2969      * @param epsilon
2970      *            the permitted tolerance
2971      * @return the new {@code BooleanBinding}
2972      * @throws NullPointerException
2973      *             if the {@code ObservableNumberValue} is {@code null}
2974      */
2975     public static BooleanBinding notEqual(final double op1, final ObservableNumberValue op2, final double epsilon) {
2976         return notEqual(DoubleConstant.valueOf(op1), op2, epsilon, op2);
2977     }
2978 
2979     /**
2980      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
2981      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is not
2982      * equal to a constant value (with a tolerance).
2983      * <p>
2984      * Two operands {@code a} and {@code b} are considered equal if
2985      * {@code Math.abs(a-b) <= epsilon}.
2986      * <p>
2987      * Allowing a small tolerance is recommended when comparing floating-point
2988      * numbers because of rounding-errors.
2989      *
2990      * @param op1
2991      *            the {@code ObservableNumberValue}
2992      * @param op2
2993      *            the constant value
2994      * @param epsilon
2995      *            the permitted tolerance
2996      * @return the new {@code BooleanBinding}
2997      * @throws NullPointerException
2998      *             if the {@code ObservableNumberValue} is {@code null}
2999      */
3000     public static BooleanBinding notEqual(final ObservableNumberValue op1, final float op2, final double epsilon) {
3001         return notEqual(op1, FloatConstant.valueOf(op2), epsilon, op1);
3002     }
3003 
3004     /**
3005      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3006      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is not
3007      * equal to a constant value (with a tolerance).
3008      * <p>
3009      * Two operands {@code a} and {@code b} are considered equal if
3010      * {@code Math.abs(a-b) <= epsilon}.
3011      * <p>
3012      * Allowing a small tolerance is recommended when comparing floating-point
3013      * numbers because of rounding-errors.
3014      *
3015      * @param op1
3016      *            the constant value
3017      * @param op2
3018      *            the {@code ObservableNumberValue}
3019      * @param epsilon
3020      *            the permitted tolerance
3021      * @return the new {@code BooleanBinding}
3022      * @throws NullPointerException
3023      *             if the {@code ObservableNumberValue} is {@code null}
3024      */
3025     public static BooleanBinding notEqual(final float op1, final ObservableNumberValue op2, final double epsilon) {
3026         return notEqual(FloatConstant.valueOf(op1), op2, epsilon, op2);
3027     }
3028 
3029     /**
3030      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3031      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is not
3032      * equal to a constant value (with a tolerance).
3033      * <p>
3034      * Two operands {@code a} and {@code b} are considered equal if
3035      * {@code Math.abs(a-b) <= epsilon}.
3036      * <p>
3037      * Allowing a small tolerance is recommended when comparing floating-point
3038      * numbers because of rounding-errors.
3039      *
3040      * @param op1
3041      *            the {@code ObservableNumberValue}
3042      * @param op2
3043      *            the constant value
3044      * @param epsilon
3045      *            the permitted tolerance
3046      * @return the new {@code BooleanBinding}
3047      * @throws NullPointerException
3048      *             if the {@code ObservableNumberValue} is {@code null}
3049      */
3050     public static BooleanBinding notEqual(final ObservableNumberValue op1, final long op2, final double epsilon) {
3051         return notEqual(op1, LongConstant.valueOf(op2), epsilon, op1);
3052     }
3053 
3054     /**
3055      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3056      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is not
3057      * equal to a constant value.
3058      * <p>
3059      * When comparing floating-point numbers it is recommended to use the
3060      * {@link #notEqual(ObservableNumberValue, long, double) notEqual()} method
3061      * that allows a small tolerance.
3062      *
3063      * @param op1
3064      *            the {@code ObservableNumberValue}
3065      * @param op2
3066      *            the constant value
3067      * @return the new {@code BooleanBinding}
3068      * @throws NullPointerException
3069      *             if the {@code ObservableNumberValue} is {@code null}
3070      */
3071     public static BooleanBinding notEqual(final ObservableNumberValue op1, final long op2) {
3072         return notEqual(op1, LongConstant.valueOf(op2), 0.0, op1);
3073     }
3074 
3075     /**
3076      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3077      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is not
3078      * equal to a constant value (with a tolerance).
3079      * <p>
3080      * Two operands {@code a} and {@code b} are considered equal if
3081      * {@code Math.abs(a-b) <= epsilon}.
3082      * <p>
3083      * Allowing a small tolerance is recommended when comparing floating-point
3084      * numbers because of rounding-errors.
3085      *
3086      * @param op1
3087      *            the constant value
3088      * @param op2
3089      *            the {@code ObservableNumberValue}
3090      * @param epsilon
3091      *            the permitted tolerance
3092      * @return the new {@code BooleanBinding}
3093      * @throws NullPointerException
3094      *             if the {@code ObservableNumberValue} is {@code null}
3095      */
3096     public static BooleanBinding notEqual(final long op1, final ObservableNumberValue op2, final double epsilon) {
3097         return notEqual(LongConstant.valueOf(op1), op2, epsilon, op2);
3098     }
3099 
3100     /**
3101      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3102      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is not
3103      * equal to a constant value.
3104      * <p>
3105      * When comparing floating-point numbers it is recommended to use the
3106      * {@link #notEqual(long, ObservableNumberValue, double) notEqual()} method
3107      * that allows a small tolerance.
3108      *
3109      * @param op1
3110      *            the constant value
3111      * @param op2
3112      *            the {@code ObservableNumberValue}
3113      * @return the new {@code BooleanBinding}
3114      * @throws NullPointerException
3115      *             if the {@code ObservableNumberValue} is {@code null}
3116      */
3117     public static BooleanBinding notEqual(final long op1, final ObservableNumberValue op2) {
3118         return notEqual(LongConstant.valueOf(op1), op2, 0.0, op2);
3119     }
3120 
3121     /**
3122      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3123      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is not
3124      * equal to a constant value (with a tolerance).
3125      * <p>
3126      * Two operands {@code a} and {@code b} are considered equal if
3127      * {@code Math.abs(a-b) <= epsilon}.
3128      * <p>
3129      * Allowing a small tolerance is recommended when comparing floating-point
3130      * numbers because of rounding-errors.
3131      *
3132      * @param op1
3133      *            the {@code ObservableNumberValue}
3134      * @param op2
3135      *            the constant value
3136      * @param epsilon
3137      *            the permitted tolerance
3138      * @return the new {@code BooleanBinding}
3139      * @throws NullPointerException
3140      *             if the {@code ObservableNumberValue} is {@code null}
3141      */
3142     public static BooleanBinding notEqual(final ObservableNumberValue op1, final int op2, final double epsilon) {
3143         return notEqual(op1, IntegerConstant.valueOf(op2), epsilon, op1);
3144     }
3145 
3146     /**
3147      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3148      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is not
3149      * equal to a constant value.
3150      * <p>
3151      * When comparing floating-point numbers it is recommended to use the
3152      * {@link #notEqual(ObservableNumberValue, int, double) notEqual()} method
3153      * that allows a small tolerance.
3154      *
3155      * @param op1
3156      *            the {@code ObservableNumberValue}
3157      * @param op2
3158      *            the constant value
3159      * @return the new {@code BooleanBinding}
3160      * @throws NullPointerException
3161      *             if the {@code ObservableNumberValue} is {@code null}
3162      */
3163     public static BooleanBinding notEqual(final ObservableNumberValue op1, final int op2) {
3164         return notEqual(op1, IntegerConstant.valueOf(op2), 0.0, op1);
3165     }
3166 
3167     /**
3168      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3169      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is not
3170      * equal to a constant value (with a tolerance).
3171      * <p>
3172      * Two operands {@code a} and {@code b} are considered equal if
3173      * {@code Math.abs(a-b) <= epsilon}.
3174      * <p>
3175      * Allowing a small tolerance is recommended when comparing floating-point
3176      * numbers because of rounding-errors.
3177      *
3178      * @param op1
3179      *            the constant value
3180      * @param op2
3181      *            the {@code ObservableNumberValue}
3182      * @param epsilon
3183      *            the permitted tolerance
3184      * @return the new {@code BooleanBinding}
3185      * @throws NullPointerException
3186      *             if the {@code ObservableNumberValue} is {@code null}
3187      */
3188     public static BooleanBinding notEqual(final int op1, final ObservableNumberValue op2, final double epsilon) {
3189         return notEqual(IntegerConstant.valueOf(op1), op2, epsilon, op2);
3190     }
3191 
3192     /**
3193      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3194      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is not
3195      * equal to a constant value.
3196      * <p>
3197      * When comparing floating-point numbers it is recommended to use the
3198      * {@link #notEqual(int, ObservableNumberValue, double) notEqual()} method
3199      * that allows a small tolerance.
3200      *
3201      * @param op1
3202      *            the constant value
3203      * @param op2
3204      *            the {@code ObservableNumberValue}
3205      * @return the new {@code BooleanBinding}
3206      * @throws NullPointerException
3207      *             if the {@code ObservableNumberValue} is {@code null}
3208      */
3209     public static BooleanBinding notEqual(final int op1, final ObservableNumberValue op2) {
3210         return notEqual(IntegerConstant.valueOf(op1), op2, 0.0, op2);
3211     }
3212 
3213     // =================================================================================================================
3214     // Greater Than
3215 
3216     private static BooleanBinding greaterThan(final ObservableNumberValue op1, final ObservableNumberValue op2, final Observable... dependencies) {
3217         if ((op1 == null) || (op2 == null)) {
3218             throw new NullPointerException("Operands cannot be null.");
3219         }
3220         assert (dependencies != null) && (dependencies.length > 0);
3221 
3222         if ((op1 instanceof ObservableDoubleValue) || (op2 instanceof ObservableDoubleValue)) {
3223             return new BooleanBinding() {
3224                 {
3225                     super.bind(dependencies);
3226                 }
3227 
3228                 @Override
3229                 public void dispose() {
3230                     super.unbind(dependencies);
3231                 }
3232 
3233                 @Override
3234                 protected boolean computeValue() {
3235                     return op1.doubleValue() > op2.doubleValue();
3236                 }
3237 
3238                 @Override
3239                 public ObservableList<?> getDependencies() {
3240                     return (dependencies.length == 1)?
3241                             FXCollections.singletonObservableList(dependencies[0])
3242                             : new ImmutableObservableList<Observable>(dependencies);
3243                 }
3244             };
3245         } else if ((op1 instanceof ObservableFloatValue) || (op2 instanceof ObservableFloatValue)) {
3246             return new BooleanBinding() {
3247                 {
3248                     super.bind(dependencies);
3249                 }
3250 
3251                 @Override
3252                 public void dispose() {
3253                     super.unbind(dependencies);
3254                 }
3255 
3256                 @Override
3257                 protected boolean computeValue() {
3258                     return op1.floatValue() > op2.floatValue();
3259                 }
3260 
3261                 @Override
3262                 public ObservableList<?> getDependencies() {
3263                     return (dependencies.length == 1)?
3264                             FXCollections.singletonObservableList(dependencies[0])
3265                             : new ImmutableObservableList<Observable>(dependencies);
3266                 }
3267             };
3268         } else if ((op1 instanceof ObservableLongValue) || (op2 instanceof ObservableLongValue)) {
3269             return new BooleanBinding() {
3270                 {
3271                     super.bind(dependencies);
3272                 }
3273 
3274                 @Override
3275                 public void dispose() {
3276                     super.unbind(dependencies);
3277                 }
3278 
3279                 @Override
3280                 protected boolean computeValue() {
3281                     return op1.longValue() > op2.longValue();
3282                 }
3283 
3284                 @Override
3285                 public ObservableList<?> getDependencies() {
3286                     return (dependencies.length == 1)?
3287                             FXCollections.singletonObservableList(dependencies[0])
3288                             : new ImmutableObservableList<Observable>(dependencies);
3289                 }
3290             };
3291         } else {
3292             return new BooleanBinding() {
3293                 {
3294                     super.bind(dependencies);
3295                 }
3296 
3297                 @Override
3298                 public void dispose() {
3299                     super.unbind(dependencies);
3300                 }
3301 
3302                 @Override
3303                 protected boolean computeValue() {
3304                     return op1.intValue() > op2.intValue();
3305                 }
3306 
3307                 @Override
3308                 public ObservableList<?> getDependencies() {
3309                     return (dependencies.length == 1)?
3310                             FXCollections.singletonObservableList(dependencies[0])
3311                             : new ImmutableObservableList<Observable>(dependencies);
3312                 }
3313             };
3314         }
3315     }
3316 
3317     /**
3318      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3319      * if the value of the first
3320      * {@link javafx.beans.value.ObservableNumberValue} is greater than the
3321      * value of the second.
3322      *
3323      * @param op1
3324      *            the first operand
3325      * @param op2
3326      *            the second operand
3327      * @return the new {@code BooleanBinding}
3328      * @throws NullPointerException
3329      *             if one of the operands is {@code null}
3330      */
3331     public static BooleanBinding greaterThan(final ObservableNumberValue op1, final ObservableNumberValue op2) {
3332         return Bindings.greaterThan(op1, op2, op1, op2);
3333     }
3334 
3335     /**
3336      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3337      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
3338      * greater than a constant value.
3339      *
3340      * @param op1
3341      *            the {@code ObservableNumberValue}
3342      * @param op2
3343      *            the constant value
3344      * @return the new {@code BooleanBinding}
3345      * @throws NullPointerException
3346      *             if the {@code ObservableNumberValue} is {@code null}
3347      */
3348     public static BooleanBinding greaterThan(final ObservableNumberValue op1, final double op2) {
3349         return greaterThan(op1, DoubleConstant.valueOf(op2), op1);
3350     }
3351 
3352     /**
3353      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3354      * if a constant value is greater than the value of a
3355      * {@link javafx.beans.value.ObservableNumberValue}.
3356      *
3357      * @param op1
3358      *            the constant value
3359      * @param op2
3360      *            the {@code ObservableNumberValue}
3361      * @return the new {@code BooleanBinding}
3362      * @throws NullPointerException
3363      *             if the {@code ObservableNumberValue} is {@code null}
3364      */
3365     public static BooleanBinding greaterThan(final double op1, final ObservableNumberValue op2) {
3366         return greaterThan(DoubleConstant.valueOf(op1), op2, op2);
3367     }
3368 
3369     /**
3370      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3371      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
3372      * greater than a constant value.
3373      *
3374      * @param op1
3375      *            the {@code ObservableNumberValue}
3376      * @param op2
3377      *            the constant value
3378      * @return the new {@code BooleanBinding}
3379      * @throws NullPointerException
3380      *             if the {@code ObservableNumberValue} is {@code null}
3381      */
3382     public static BooleanBinding greaterThan(final ObservableNumberValue op1, final float op2) {
3383         return greaterThan(op1, FloatConstant.valueOf(op2), op1);
3384     }
3385 
3386     /**
3387      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3388      * if a constant value is greater than the value of a
3389      * {@link javafx.beans.value.ObservableNumberValue}.
3390      *
3391      * @param op1
3392      *            the constant value
3393      * @param op2
3394      *            the {@code ObservableNumberValue}
3395      * @return the new {@code BooleanBinding}
3396      * @throws NullPointerException
3397      *             if the {@code ObservableNumberValue} is {@code null}
3398      */
3399     public static BooleanBinding greaterThan(final float op1, final ObservableNumberValue op2) {
3400         return greaterThan(FloatConstant.valueOf(op1), op2, op2);
3401     }
3402 
3403     /**
3404      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3405      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
3406      * greater than a constant value.
3407      *
3408      * @param op1
3409      *            the {@code ObservableNumberValue}
3410      * @param op2
3411      *            the constant value
3412      * @return the new {@code BooleanBinding}
3413      * @throws NullPointerException
3414      *             if the {@code ObservableNumberValue} is {@code null}
3415      */
3416     public static BooleanBinding greaterThan(final ObservableNumberValue op1, final long op2) {
3417         return greaterThan(op1, LongConstant.valueOf(op2), op1);
3418     }
3419 
3420     /**
3421      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3422      * if a constant value is greater than the value of a
3423      * {@link javafx.beans.value.ObservableNumberValue}.
3424      *
3425      * @param op1
3426      *            the constant value
3427      * @param op2
3428      *            the {@code ObservableNumberValue}
3429      * @return the new {@code BooleanBinding}
3430      * @throws NullPointerException
3431      *             if the {@code ObservableNumberValue} is {@code null}
3432      */
3433     public static BooleanBinding greaterThan(final long op1, final ObservableNumberValue op2) {
3434         return greaterThan(LongConstant.valueOf(op1), op2, op2);
3435     }
3436 
3437     /**
3438      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3439      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
3440      * greater than a constant value.
3441      *
3442      * @param op1
3443      *            the {@code ObservableNumberValue}
3444      * @param op2
3445      *            the constant value
3446      * @return the new {@code BooleanBinding}
3447      * @throws NullPointerException
3448      *             if the {@code ObservableNumberValue} is {@code null}
3449      */
3450     public static BooleanBinding greaterThan(final ObservableNumberValue op1, final int op2) {
3451         return greaterThan(op1, IntegerConstant.valueOf(op2), op1);
3452     }
3453 
3454     /**
3455      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3456      * if a constant value is greater than the value of a
3457      * {@link javafx.beans.value.ObservableNumberValue}.
3458      *
3459      * @param op1
3460      *            the constant value
3461      * @param op2
3462      *            the {@code ObservableNumberValue}
3463      * @return the new {@code BooleanBinding}
3464      * @throws NullPointerException
3465      *             if the {@code ObservableNumberValue} is {@code null}
3466      */
3467     public static BooleanBinding greaterThan(final int op1, final ObservableNumberValue op2) {
3468         return greaterThan(IntegerConstant.valueOf(op1), op2, op2);
3469     }
3470 
3471     // =================================================================================================================
3472     // Less Than
3473 
3474     private static BooleanBinding lessThan(final ObservableNumberValue op1, final ObservableNumberValue op2, final Observable... dependencies) {
3475         return greaterThan(op2, op1, dependencies);
3476     }
3477 
3478     /**
3479      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3480      * if the value of the first
3481      * {@link javafx.beans.value.ObservableNumberValue} is less than the value
3482      * of the second.
3483      *
3484      * @param op1
3485      *            the first operand
3486      * @param op2
3487      *            the second operand
3488      * @return the new {@code BooleanBinding}
3489      * @throws NullPointerException
3490      *             if one of the operands is {@code null}
3491      */
3492     public static BooleanBinding lessThan(final ObservableNumberValue op1, final ObservableNumberValue op2) {
3493         return lessThan(op1, op2, op1, op2);
3494     }
3495 
3496     /**
3497      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3498      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
3499      * less than a constant value.
3500      *
3501      * @param op1
3502      *            the {@code ObservableNumberValue}
3503      * @param op2
3504      *            the constant value
3505      * @return the new {@code BooleanBinding}
3506      * @throws NullPointerException
3507      *             if the {@code ObservableNumberValue} is {@code null}
3508      */
3509     public static BooleanBinding lessThan(final ObservableNumberValue op1, final double op2) {
3510         return lessThan(op1, DoubleConstant.valueOf(op2), op1);
3511     }
3512 
3513     /**
3514      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3515      * if a constant value is less than the value of a
3516      * {@link javafx.beans.value.ObservableNumberValue}.
3517      *
3518      * @param op1
3519      *            the constant value
3520      * @param op2
3521      *            the {@code ObservableNumberValue}
3522      * @return the new {@code BooleanBinding}
3523      * @throws NullPointerException
3524      *             if the {@code ObservableNumberValue} is {@code null}
3525      */
3526     public static BooleanBinding lessThan(final double op1, final ObservableNumberValue op2) {
3527         return lessThan(DoubleConstant.valueOf(op1), op2, op2);
3528     }
3529 
3530     /**
3531      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3532      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
3533      * less than a constant value.
3534      *
3535      * @param op1
3536      *            the {@code ObservableNumberValue}
3537      * @param op2
3538      *            the constant value
3539      * @return the new {@code BooleanBinding}
3540      * @throws NullPointerException
3541      *             if the {@code ObservableNumberValue} is {@code null}
3542      */
3543     public static BooleanBinding lessThan(final ObservableNumberValue op1, final float op2) {
3544         return lessThan(op1, FloatConstant.valueOf(op2), op1);
3545     }
3546 
3547     /**
3548      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3549      * if a constant value is less than the value of a
3550      * {@link javafx.beans.value.ObservableNumberValue}.
3551      *
3552      * @param op1
3553      *            the constant value
3554      * @param op2
3555      *            the {@code ObservableNumberValue}
3556      * @return the new {@code BooleanBinding}
3557      * @throws NullPointerException
3558      *             if the {@code ObservableNumberValue} is {@code null}
3559      */
3560     public static BooleanBinding lessThan(final float op1, final ObservableNumberValue op2) {
3561         return lessThan(FloatConstant.valueOf(op1), op2, op2);
3562     }
3563 
3564     /**
3565      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3566      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
3567      * less than a constant value.
3568      *
3569      * @param op1
3570      *            the {@code ObservableNumberValue}
3571      * @param op2
3572      *            the constant value
3573      * @return the new {@code BooleanBinding}
3574      * @throws NullPointerException
3575      *             if the {@code ObservableNumberValue} is {@code null}
3576      */
3577     public static BooleanBinding lessThan(final ObservableNumberValue op1, final long op2) {
3578         return lessThan(op1, LongConstant.valueOf(op2), op1);
3579     }
3580 
3581     /**
3582      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3583      * if a constant value is less than the value of a
3584      * {@link javafx.beans.value.ObservableNumberValue}.
3585      *
3586      * @param op1
3587      *            the constant value
3588      * @param op2
3589      *            the {@code ObservableNumberValue}
3590      * @return the new {@code BooleanBinding}
3591      * @throws NullPointerException
3592      *             if the {@code ObservableNumberValue} is {@code null}
3593      */
3594     public static BooleanBinding lessThan(final long op1, final ObservableNumberValue op2) {
3595         return lessThan(LongConstant.valueOf(op1), op2, op2);
3596     }
3597 
3598     /**
3599      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3600      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
3601      * less than a constant value.
3602      *
3603      * @param op1
3604      *            the {@code ObservableNumberValue}
3605      * @param op2
3606      *            the constant value
3607      * @return the new {@code BooleanBinding}
3608      * @throws NullPointerException
3609      *             if the {@code ObservableNumberValue} is {@code null}
3610      */
3611     public static BooleanBinding lessThan(final ObservableNumberValue op1, final int op2) {
3612         return lessThan(op1, IntegerConstant.valueOf(op2), op1);
3613     }
3614 
3615     /**
3616      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3617      * if a constant value is less than the value of a
3618      * {@link javafx.beans.value.ObservableNumberValue}.
3619      *
3620      * @param op1
3621      *            the constant value
3622      * @param op2
3623      *            the {@code ObservableNumberValue}
3624      * @return the new {@code BooleanBinding}
3625      * @throws NullPointerException
3626      *             if the {@code ObservableNumberValue} is {@code null}
3627      */
3628     public static BooleanBinding lessThan(final int op1, final ObservableNumberValue op2) {
3629         return lessThan(IntegerConstant.valueOf(op1), op2, op2);
3630     }
3631 
3632     // =================================================================================================================
3633     // Greater Than or Equal
3634 
3635     private static BooleanBinding greaterThanOrEqual(final ObservableNumberValue op1, final ObservableNumberValue op2, final Observable... dependencies) {
3636         if ((op1 == null) || (op2 == null)) {
3637             throw new NullPointerException("Operands cannot be null.");
3638         }
3639         assert (dependencies != null) && (dependencies.length > 0);
3640 
3641         if ((op1 instanceof ObservableDoubleValue) || (op2 instanceof ObservableDoubleValue)) {
3642             return new BooleanBinding() {
3643                 {
3644                     super.bind(dependencies);
3645                 }
3646 
3647                 @Override
3648                 public void dispose() {
3649                     super.unbind(dependencies);
3650                 }
3651 
3652                 @Override
3653                 protected boolean computeValue() {
3654                     return op1.doubleValue() >= op2.doubleValue();
3655                 }
3656 
3657                 @Override
3658                 public ObservableList<?> getDependencies() {
3659                     return (dependencies.length == 1)?
3660                             FXCollections.singletonObservableList(dependencies[0])
3661                             : new ImmutableObservableList<Observable>(dependencies);
3662                 }
3663             };
3664         } else if ((op1 instanceof ObservableFloatValue) || (op2 instanceof ObservableFloatValue)) {
3665             return new BooleanBinding() {
3666                 {
3667                     super.bind(dependencies);
3668                 }
3669 
3670                 @Override
3671                 public void dispose() {
3672                     super.unbind(dependencies);
3673                 }
3674 
3675                 @Override
3676                 protected boolean computeValue() {
3677                     return op1.floatValue() >= op2.floatValue();
3678                 }
3679 
3680                 @Override
3681                 public ObservableList<?> getDependencies() {
3682                     return (dependencies.length == 1)?
3683                             FXCollections.singletonObservableList(dependencies[0])
3684                             : new ImmutableObservableList<Observable>(dependencies);
3685                 }
3686             };
3687         } else if ((op1 instanceof ObservableLongValue) || (op2 instanceof ObservableLongValue)) {
3688             return new BooleanBinding() {
3689                 {
3690                     super.bind(dependencies);
3691                 }
3692 
3693                 @Override
3694                 public void dispose() {
3695                     super.unbind(dependencies);
3696                 }
3697 
3698                 @Override
3699                 protected boolean computeValue() {
3700                     return op1.longValue() >= op2.longValue();
3701                 }
3702 
3703                 @Override
3704                 public ObservableList<?> getDependencies() {
3705                     return (dependencies.length == 1)?
3706                             FXCollections.singletonObservableList(dependencies[0])
3707                             : new ImmutableObservableList<Observable>(dependencies);
3708                 }
3709             };
3710         } else {
3711             return new BooleanBinding() {
3712                 {
3713                     super.bind(dependencies);
3714                 }
3715 
3716                 @Override
3717                 public void dispose() {
3718                     super.unbind(dependencies);
3719                 }
3720 
3721                 @Override
3722                 protected boolean computeValue() {
3723                     return op1.intValue() >= op2.intValue();
3724                 }
3725 
3726                 @Override
3727                 public ObservableList<?> getDependencies() {
3728                     return (dependencies.length == 1)?
3729                             FXCollections.singletonObservableList(dependencies[0])
3730                             : new ImmutableObservableList<Observable>(dependencies);
3731                 }
3732             };
3733         }
3734     }
3735 
3736     /**
3737      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3738      * if the value of the first
3739      * {@link javafx.beans.value.ObservableNumberValue} is greater than or equal
3740      * to the value of the second.
3741      *
3742      * @param op1
3743      *            the first operand
3744      * @param op2
3745      *            the second operand
3746      * @return the new {@code BooleanBinding}
3747      * @throws NullPointerException
3748      *             if one of the operands is {@code null}
3749      */
3750     public static BooleanBinding greaterThanOrEqual(final ObservableNumberValue op1, final ObservableNumberValue op2) {
3751         return greaterThanOrEqual(op1, op2, op1, op2);
3752     }
3753 
3754     /**
3755      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3756      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
3757      * greater than or equal to a constant value.
3758      *
3759      * @param op1
3760      *            the {@code ObservableNumberValue}
3761      * @param op2
3762      *            the constant value
3763      * @return the new {@code BooleanBinding}
3764      * @throws NullPointerException
3765      *             if the {@code ObservableNumberValue} is {@code null}
3766      */
3767     public static BooleanBinding greaterThanOrEqual(final ObservableNumberValue op1, final double op2) {
3768         return greaterThanOrEqual(op1, DoubleConstant.valueOf(op2), op1);
3769     }
3770 
3771     /**
3772      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3773      * if a constant value is greater than or equal to the value of a
3774      * {@link javafx.beans.value.ObservableNumberValue}.
3775      *
3776      * @param op1
3777      *            the constant value
3778      * @param op2
3779      *            the {@code ObservableNumberValue}
3780      * @return the new {@code BooleanBinding}
3781      * @throws NullPointerException
3782      *             if the {@code ObservableNumberValue} is {@code null}
3783      */
3784     public static BooleanBinding greaterThanOrEqual(final double op1, final ObservableNumberValue op2) {
3785         return greaterThanOrEqual(DoubleConstant.valueOf(op1), op2, op2);
3786     }
3787 
3788     /**
3789      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3790      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
3791      * greater than or equal to a constant value.
3792      *
3793      * @param op1
3794      *            the {@code ObservableNumberValue}
3795      * @param op2
3796      *            the constant value
3797      * @return the new {@code BooleanBinding}
3798      * @throws NullPointerException
3799      *             if the {@code ObservableNumberValue} is {@code null}
3800      */
3801     public static BooleanBinding greaterThanOrEqual(final ObservableNumberValue op1, final float op2) {
3802         return greaterThanOrEqual(op1, FloatConstant.valueOf(op2), op1);
3803     }
3804 
3805     /**
3806      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3807      * if a constant value is greater than or equal to the value of a
3808      * {@link javafx.beans.value.ObservableNumberValue}.
3809      *
3810      * @param op1
3811      *            the constant value
3812      * @param op2
3813      *            the {@code ObservableNumberValue}
3814      * @return the new {@code BooleanBinding}
3815      * @throws NullPointerException
3816      *             if the {@code ObservableNumberValue} is {@code null}
3817      */
3818     public static BooleanBinding greaterThanOrEqual(final float op1, final ObservableNumberValue op2) {
3819         return greaterThanOrEqual(FloatConstant.valueOf(op1), op2, op2);
3820     }
3821 
3822     /**
3823      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3824      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
3825      * greater than or equal to a constant value.
3826      *
3827      * @param op1
3828      *            the {@code ObservableNumberValue}
3829      * @param op2
3830      *            the constant value
3831      * @return the new {@code BooleanBinding}
3832      * @throws NullPointerException
3833      *             if the {@code ObservableNumberValue} is {@code null}
3834      */
3835     public static BooleanBinding greaterThanOrEqual(final ObservableNumberValue op1, final long op2) {
3836         return greaterThanOrEqual(op1, LongConstant.valueOf(op2), op1);
3837     }
3838 
3839     /**
3840      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3841      * if a constant value is greater than or equal to the value of a
3842      * {@link javafx.beans.value.ObservableNumberValue}.
3843      *
3844      * @param op1
3845      *            the constant value
3846      * @param op2
3847      *            the {@code ObservableNumberValue}
3848      * @return the new {@code BooleanBinding}
3849      * @throws NullPointerException
3850      *             if the {@code ObservableNumberValue} is {@code null}
3851      */
3852     public static BooleanBinding greaterThanOrEqual(final long op1, final ObservableNumberValue op2) {
3853         return greaterThanOrEqual(LongConstant.valueOf(op1), op2, op2);
3854     }
3855 
3856     /**
3857      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3858      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
3859      * greater than or equal to a constant value.
3860      *
3861      * @param op1
3862      *            the {@code ObservableNumberValue}
3863      * @param op2
3864      *            the constant value
3865      * @return the new {@code BooleanBinding}
3866      * @throws NullPointerException
3867      *             if the {@code ObservableNumberValue} is {@code null}
3868      */
3869     public static BooleanBinding greaterThanOrEqual(final ObservableNumberValue op1, final int op2) {
3870         return greaterThanOrEqual(op1, IntegerConstant.valueOf(op2), op1);
3871     }
3872 
3873     /**
3874      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3875      * if a constant value is greater than or equal to the value of a
3876      * {@link javafx.beans.value.ObservableNumberValue}.
3877      *
3878      * @param op1
3879      *            the constant value
3880      * @param op2
3881      *            the {@code ObservableNumberValue}
3882      * @return the new {@code BooleanBinding}
3883      * @throws NullPointerException
3884      *             if the {@code ObservableNumberValue} is {@code null}
3885      */
3886     public static BooleanBinding greaterThanOrEqual(final int op1, final ObservableNumberValue op2) {
3887         return greaterThanOrEqual(IntegerConstant.valueOf(op1), op2, op2);
3888     }
3889 
3890     // =================================================================================================================
3891     // Less Than or Equal
3892 
3893     private static BooleanBinding lessThanOrEqual(final ObservableNumberValue op1, final ObservableNumberValue op2, Observable... dependencies) {
3894         return greaterThanOrEqual(op2, op1, dependencies);
3895     }
3896 
3897 
3898     /**
3899      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3900      * if the value of the first
3901      * {@link javafx.beans.value.ObservableNumberValue} is less than or equal to
3902      * the value of the second.
3903      *
3904      * @param op1
3905      *            the first operand
3906      * @param op2
3907      *            the second operand
3908      * @return the new {@code BooleanBinding}
3909      * @throws NullPointerException
3910      *             if one of the operands is {@code null}
3911      */
3912     public static BooleanBinding lessThanOrEqual(final ObservableNumberValue op1, final ObservableNumberValue op2) {
3913         return lessThanOrEqual(op1, op2, op1, op2);
3914     }
3915 
3916     /**
3917      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3918      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
3919      * less than or equal to a constant value.
3920      *
3921      * @param op1
3922      *            the {@code ObservableNumberValue}
3923      * @param op2
3924      *            the constant value
3925      * @return the new {@code BooleanBinding}
3926      * @throws NullPointerException
3927      *             if the {@code ObservableNumberValue} is {@code null}
3928      */
3929     public static BooleanBinding lessThanOrEqual(final ObservableNumberValue op1, final double op2) {
3930         return lessThanOrEqual(op1, DoubleConstant.valueOf(op2), op1);
3931     }
3932 
3933     /**
3934      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3935      * if a constant value is less than or equal to the value of a
3936      * {@link javafx.beans.value.ObservableNumberValue}.
3937      *
3938      * @param op1
3939      *            the constant value
3940      * @param op2
3941      *            the {@code ObservableNumberValue}
3942      * @return the new {@code BooleanBinding}
3943      * @throws NullPointerException
3944      *             if the {@code ObservableNumberValue} is {@code null}
3945      */
3946     public static BooleanBinding lessThanOrEqual(final double op1, final ObservableNumberValue op2) {
3947         return lessThanOrEqual(DoubleConstant.valueOf(op1), op2, op2);
3948     }
3949 
3950     /**
3951      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3952      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
3953      * less than or equal to a constant value.
3954      *
3955      * @param op1
3956      *            the {@code ObservableNumberValue}
3957      * @param op2
3958      *            the constant value
3959      * @return the new {@code BooleanBinding}
3960      * @throws NullPointerException
3961      *             if the {@code ObservableNumberValue} is {@code null}
3962      */
3963     public static BooleanBinding lessThanOrEqual(final ObservableNumberValue op1, final float op2) {
3964         return lessThanOrEqual(op1, FloatConstant.valueOf(op2), op1);
3965     }
3966 
3967     /**
3968      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3969      * if a constant value is less than or equal to the value of a
3970      * {@link javafx.beans.value.ObservableNumberValue}.
3971      *
3972      * @param op1
3973      *            the constant value
3974      * @param op2
3975      *            the {@code ObservableNumberValue}
3976      * @return the new {@code BooleanBinding}
3977      * @throws NullPointerException
3978      *             if the {@code ObservableNumberValue} is {@code null}
3979      */
3980     public static BooleanBinding lessThanOrEqual(final float op1, final ObservableNumberValue op2) {
3981         return lessThanOrEqual(FloatConstant.valueOf(op1), op2, op2);
3982     }
3983 
3984     /**
3985      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
3986      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
3987      * less than or equal to a constant value.
3988      *
3989      * @param op1
3990      *            the {@code ObservableNumberValue}
3991      * @param op2
3992      *            the constant value
3993      * @return the new {@code BooleanBinding}
3994      * @throws NullPointerException
3995      *             if the {@code ObservableNumberValue} is {@code null}
3996      */
3997     public static BooleanBinding lessThanOrEqual(final ObservableNumberValue op1, final long op2) {
3998         return lessThanOrEqual(op1, LongConstant.valueOf(op2), op1);
3999     }
4000 
4001     /**
4002      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
4003      * if a constant value is less than or equal to the value of a
4004      * {@link javafx.beans.value.ObservableNumberValue}.
4005      *
4006      * @param op1
4007      *            the constant value
4008      * @param op2
4009      *            the {@code ObservableNumberValue}
4010      * @return the new {@code BooleanBinding}
4011      * @throws NullPointerException
4012      *             if the {@code ObservableNumberValue} is {@code null}
4013      */
4014     public static BooleanBinding lessThanOrEqual(final long op1, final ObservableNumberValue op2) {
4015         return lessThanOrEqual(LongConstant.valueOf(op1), op2, op2);
4016     }
4017 
4018     /**
4019      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
4020      * if the value of a {@link javafx.beans.value.ObservableNumberValue} is
4021      * less than or equal to a constant value.
4022      *
4023      * @param op1
4024      *            the {@code ObservableNumberValue}
4025      * @param op2
4026      *            the constant value
4027      * @return the new {@code BooleanBinding}
4028      * @throws NullPointerException
4029      *             if the {@code ObservableNumberValue} is {@code null}
4030      */
4031     public static BooleanBinding lessThanOrEqual(final ObservableNumberValue op1, final int op2) {
4032         return lessThanOrEqual(op1, IntegerConstant.valueOf(op2), op1);
4033     }
4034 
4035     /**
4036      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
4037      * if a constant value is less than or equal to the value of a
4038      * {@link javafx.beans.value.ObservableNumberValue}.
4039      *
4040      * @param op1
4041      *            the constant value
4042      * @param op2
4043      *            the {@code ObservableNumberValue}
4044      * @return the new {@code BooleanBinding}
4045      * @throws NullPointerException
4046      *             if the {@code ObservableNumberValue} is {@code null}
4047      */
4048     public static BooleanBinding lessThanOrEqual(final int op1, final ObservableNumberValue op2) {
4049         return lessThanOrEqual(IntegerConstant.valueOf(op1), op2, op2);
4050     }
4051 
4052     // =================================================================================================================
4053     // Minimum
4054 
4055     private static NumberBinding min(final ObservableNumberValue op1, final ObservableNumberValue op2, final Observable... dependencies) {
4056         if ((op1 == null) || (op2 == null)) {
4057             throw new NullPointerException("Operands cannot be null.");
4058         }
4059         assert (dependencies != null) && (dependencies.length > 0);
4060 
4061         if ((op1 instanceof ObservableDoubleValue) || (op2 instanceof ObservableDoubleValue)) {
4062             return new DoubleBinding() {
4063                 {
4064                     super.bind(dependencies);
4065                 }
4066 
4067                 @Override
4068                 public void dispose() {
4069                     super.unbind(dependencies);
4070                 }
4071 
4072                 @Override
4073                 protected double computeValue() {
4074                     return Math.min(op1.doubleValue(), op2.doubleValue());
4075                 }
4076 
4077                 @Override
4078                 public ObservableList<?> getDependencies() {
4079                     return (dependencies.length == 1)?
4080                             FXCollections.singletonObservableList(dependencies[0])
4081                             : new ImmutableObservableList<Observable>(dependencies);
4082                 }
4083             };
4084         } else if ((op1 instanceof ObservableFloatValue) || (op2 instanceof ObservableFloatValue)) {
4085             return new FloatBinding() {
4086                 {
4087                     super.bind(dependencies);
4088                 }
4089 
4090                 @Override
4091                 public void dispose() {
4092                     super.unbind(dependencies);
4093                 }
4094 
4095                 @Override
4096                 protected float computeValue() {
4097                     return Math.min(op1.floatValue(), op2.floatValue());
4098                 }
4099 
4100                 @Override
4101                 public ObservableList<?> getDependencies() {
4102                     return (dependencies.length == 1)?
4103                             FXCollections.singletonObservableList(dependencies[0])
4104                             : new ImmutableObservableList<Observable>(dependencies);
4105                 }
4106             };
4107         } else if ((op1 instanceof ObservableLongValue) || (op2 instanceof ObservableLongValue)) {
4108             return new LongBinding() {
4109                 {
4110                     super.bind(dependencies);
4111                 }
4112 
4113                 @Override
4114                 public void dispose() {
4115                     super.unbind(dependencies);
4116                 }
4117 
4118                 @Override
4119                 protected long computeValue() {
4120                     return Math.min(op1.longValue(), op2.longValue());
4121                 }
4122 
4123                 @Override
4124                 public ObservableList<?> getDependencies() {
4125                     return (dependencies.length == 1)?
4126                             FXCollections.singletonObservableList(dependencies[0])
4127                             : new ImmutableObservableList<Observable>(dependencies);
4128                 }
4129             };
4130         } else {
4131             return new IntegerBinding() {
4132                 {
4133                     super.bind(dependencies);
4134                 }
4135 
4136                 @Override
4137                 public void dispose() {
4138                     super.unbind(dependencies);
4139                 }
4140 
4141                 @Override
4142                 protected int computeValue() {
4143                     return Math.min(op1.intValue(), op2.intValue());
4144                 }
4145 
4146                 @Override
4147                 public ObservableList<?> getDependencies() {
4148                     return (dependencies.length == 1)?
4149                             FXCollections.singletonObservableList(dependencies[0])
4150                             : new ImmutableObservableList<Observable>(dependencies);
4151                 }
4152             };
4153         }
4154     }
4155 
4156     /**
4157      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
4158      * the minimum of the values of two instances of
4159      * {@link javafx.beans.value.ObservableNumberValue}.
4160      *
4161      * @param op1
4162      *            the first operand
4163      * @param op2
4164      *            the second operand
4165      * @return the new {@code NumberBinding}
4166      * @throws NullPointerException
4167      *             if one of the operands is {@code null}
4168      */
4169     public static NumberBinding min(final ObservableNumberValue op1, final ObservableNumberValue op2) {
4170         return min(op1, op2, op1, op2);
4171     }
4172 
4173     /**
4174      * Creates a new {@link javafx.beans.binding.DoubleBinding} that calculates
4175      * the minimum of the value of a
4176      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
4177      *
4178      * @param op1
4179      *            the {@code ObservableNumberValue}
4180      * @param op2
4181      *            the constant value
4182      * @return the new {@code DoubleBinding}
4183      * @throws NullPointerException
4184      *             if the {@code ObservableNumberValue} is {@code null}
4185      */
4186     public static DoubleBinding min(final ObservableNumberValue op1, final double op2) {
4187         return (DoubleBinding) min(op1, DoubleConstant.valueOf(op2), op1);
4188     }
4189 
4190     /**
4191      * Creates a new {@link javafx.beans.binding.DoubleBinding} that calculates
4192      * the minimum of the value of a
4193      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
4194      *
4195      * @param op1
4196      *            the constant value
4197      * @param op2
4198      *            the {@code ObservableNumberValue}
4199      * @return the new {@code DoubleBinding}
4200      * @throws NullPointerException
4201      *             if the {@code ObservableNumberValue} is {@code null}
4202      */
4203     public static DoubleBinding min(final double op1, final ObservableNumberValue op2) {
4204         return (DoubleBinding) min(DoubleConstant.valueOf(op1), op2, op2);
4205     }
4206 
4207     /**
4208      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
4209      * the minimum of the value of a
4210      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
4211      *
4212      * @param op1
4213      *            the {@code ObservableNumberValue}
4214      * @param op2
4215      *            the constant value
4216      * @return the new {@code NumberBinding}
4217      * @throws NullPointerException
4218      *             if the {@code ObservableNumberValue} is {@code null}
4219      */
4220     public static NumberBinding min(final ObservableNumberValue op1, final float op2) {
4221         return min(op1, FloatConstant.valueOf(op2), op1);
4222     }
4223 
4224     /**
4225      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
4226      * the minimum of the value of a
4227      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
4228      *
4229      * @param op1
4230      *            the constant value
4231      * @param op2
4232      *            the {@code ObservableNumberValue}
4233      * @return the new {@code NumberBinding}
4234      * @throws NullPointerException
4235      *             if the {@code ObservableNumberValue} is {@code null}
4236      */
4237     public static NumberBinding min(final float op1, final ObservableNumberValue op2) {
4238         return min(FloatConstant.valueOf(op1), op2, op2);
4239     }
4240 
4241     /**
4242      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
4243      * the minimum of the value of a
4244      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
4245      *
4246      * @param op1
4247      *            the {@code ObservableNumberValue}
4248      * @param op2
4249      *            the constant value
4250      * @return the new {@code NumberBinding}
4251      * @throws NullPointerException
4252      *             if the {@code ObservableNumberValue} is {@code null}
4253      */
4254     public static NumberBinding min(final ObservableNumberValue op1, final long op2) {
4255         return min(op1, LongConstant.valueOf(op2), op1);
4256     }
4257 
4258     /**
4259      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
4260      * the minimum of the value of a
4261      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
4262      *
4263      * @param op1
4264      *            the constant value
4265      * @param op2
4266      *            the {@code ObservableNumberValue}
4267      * @return the new {@code NumberBinding}
4268      * @throws NullPointerException
4269      *             if the {@code ObservableNumberValue} is {@code null}
4270      */
4271     public static NumberBinding min(final long op1, final ObservableNumberValue op2) {
4272         return min(LongConstant.valueOf(op1), op2, op2);
4273     }
4274 
4275     /**
4276      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
4277      * the minimum of the value of a
4278      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
4279      *
4280      * @param op1
4281      *            the {@code ObservableNumberValue}
4282      * @param op2
4283      *            the constant value
4284      * @return the new {@code NumberBinding}
4285      * @throws NullPointerException
4286      *             if the {@code ObservableNumberValue} is {@code null}
4287      */
4288     public static NumberBinding min(final ObservableNumberValue op1, final int op2) {
4289         return min(op1, IntegerConstant.valueOf(op2), op1);
4290     }
4291 
4292     /**
4293      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
4294      * the minimum of the value of a
4295      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
4296      *
4297      * @param op1
4298      *            the constant value
4299      * @param op2
4300      *            the {@code ObservableNumberValue}
4301      * @return the new {@code NumberBinding}
4302      * @throws NullPointerException
4303      *             if the {@code ObservableNumberValue} is {@code null}
4304      */
4305     public static NumberBinding min(final int op1, final ObservableNumberValue op2) {
4306         return min(IntegerConstant.valueOf(op1), op2, op2);
4307     }
4308 
4309     // =================================================================================================================
4310     // Maximum
4311 
4312     private static NumberBinding max(final ObservableNumberValue op1, final ObservableNumberValue op2, final Observable... dependencies) {
4313         if ((op1 == null) || (op2 == null)) {
4314             throw new NullPointerException("Operands cannot be null.");
4315         }
4316         assert (dependencies != null) && (dependencies.length > 0);
4317 
4318         if ((op1 instanceof ObservableDoubleValue) || (op2 instanceof ObservableDoubleValue)) {
4319             return new DoubleBinding() {
4320                 {
4321                     super.bind(dependencies);
4322                 }
4323 
4324                 @Override
4325                 public void dispose() {
4326                     super.unbind(dependencies);
4327                 }
4328 
4329                 @Override
4330                 protected double computeValue() {
4331                     return Math.max(op1.doubleValue(), op2.doubleValue());
4332                 }
4333 
4334                 @Override
4335                 public ObservableList<?> getDependencies() {
4336                     return (dependencies.length == 1)?
4337                             FXCollections.singletonObservableList(dependencies[0])
4338                             : new ImmutableObservableList<Observable>(dependencies);
4339                 }
4340             };
4341         } else if ((op1 instanceof ObservableFloatValue) || (op2 instanceof ObservableFloatValue)) {
4342             return new FloatBinding() {
4343                 {
4344                     super.bind(dependencies);
4345                 }
4346 
4347                 @Override
4348                 public void dispose() {
4349                     super.unbind(dependencies);
4350                 }
4351 
4352                 @Override
4353                 protected float computeValue() {
4354                     return Math.max(op1.floatValue(), op2.floatValue());
4355                 }
4356 
4357                 @Override
4358                 public ObservableList<?> getDependencies() {
4359                     return (dependencies.length == 1)?
4360                             FXCollections.singletonObservableList(dependencies[0])
4361                             : new ImmutableObservableList<Observable>(dependencies);
4362                 }
4363             };
4364         } else if ((op1 instanceof ObservableLongValue) || (op2 instanceof ObservableLongValue)) {
4365             return new LongBinding() {
4366                 {
4367                     super.bind(dependencies);
4368                 }
4369 
4370                 @Override
4371                 public void dispose() {
4372                     super.unbind(dependencies);
4373                 }
4374 
4375                 @Override
4376                 protected long computeValue() {
4377                     return Math.max(op1.longValue(), op2.longValue());
4378                 }
4379 
4380                 @Override
4381                 public ObservableList<?> getDependencies() {
4382                     return (dependencies.length == 1)?
4383                             FXCollections.singletonObservableList(dependencies[0])
4384                             : new ImmutableObservableList<Observable>(dependencies);
4385                 }
4386             };
4387         } else {
4388             return new IntegerBinding() {
4389                 {
4390                     super.bind(dependencies);
4391                 }
4392 
4393                 @Override
4394                 public void dispose() {
4395                     super.unbind(dependencies);
4396                 }
4397 
4398                 @Override
4399                 protected int computeValue() {
4400                     return Math.max(op1.intValue(), op2.intValue());
4401                 }
4402 
4403                 @Override
4404                 public ObservableList<?> getDependencies() {
4405                     return (dependencies.length == 1)?
4406                             FXCollections.singletonObservableList(dependencies[0])
4407                             : new ImmutableObservableList<Observable>(dependencies);
4408                 }
4409             };
4410         }
4411     }
4412 
4413     /**
4414      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
4415      * the maximum of the values of two instances of
4416      * {@link javafx.beans.value.ObservableNumberValue}.
4417      *
4418      * @param op1
4419      *            the first operand
4420      * @param op2
4421      *            the second operand
4422      * @return the new {@code NumberBinding}
4423      * @throws NullPointerException
4424      *             if one of the operands is {@code null}
4425      */
4426     public static NumberBinding max(final ObservableNumberValue op1, final ObservableNumberValue op2) {
4427         return max(op1, op2, op1, op2);
4428     }
4429 
4430     /**
4431      * Creates a new {@link javafx.beans.binding.DoubleBinding} that calculates
4432      * the maximum of the value of a
4433      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
4434      *
4435      * @param op1
4436      *            the {@code ObservableNumberValue}
4437      * @param op2
4438      *            the constant value
4439      * @return the new {@code DoubleBinding}
4440      * @throws NullPointerException
4441      *             if the {@code ObservableNumberValue} is {@code null}
4442      */
4443     public static DoubleBinding max(final ObservableNumberValue op1, final double op2) {
4444         return (DoubleBinding) max(op1, DoubleConstant.valueOf(op2), op1);
4445     }
4446 
4447     /**
4448      * Creates a new {@link javafx.beans.binding.DoubleBinding} that calculates
4449      * the maximum of the value of a
4450      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
4451      *
4452      * @param op1
4453      *            the constant value
4454      * @param op2
4455      *            the {@code ObservableNumberValue}
4456      * @return the new {@code DoubleBinding}
4457      * @throws NullPointerException
4458      *             if the {@code ObservableNumberValue} is {@code null}
4459      */
4460     public static DoubleBinding max(final double op1, final ObservableNumberValue op2) {
4461         return (DoubleBinding) max(DoubleConstant.valueOf(op1), op2, op2);
4462     }
4463 
4464     /**
4465      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
4466      * the maximum of the value of a
4467      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
4468      *
4469      * @param op1
4470      *            the {@code ObservableNumberValue}
4471      * @param op2
4472      *            the constant value
4473      * @return the new {@code NumberBinding}
4474      * @throws NullPointerException
4475      *             if the {@code ObservableNumberValue} is {@code null}
4476      */
4477     public static NumberBinding max(final ObservableNumberValue op1, final float op2) {
4478         return max(op1, FloatConstant.valueOf(op2), op1);
4479     }
4480 
4481     /**
4482      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
4483      * the maximum of the value of a
4484      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
4485      *
4486      * @param op1
4487      *            the constant value
4488      * @param op2
4489      *            the {@code ObservableNumberValue}
4490      * @return the new {@code NumberBinding}
4491      * @throws NullPointerException
4492      *             if the {@code ObservableNumberValue} is {@code null}
4493      */
4494     public static NumberBinding max(final float op1, final ObservableNumberValue op2) {
4495         return max(FloatConstant.valueOf(op1), op2, op2);
4496     }
4497 
4498     /**
4499      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
4500      * the maximum of the value of a
4501      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
4502      *
4503      * @param op1
4504      *            the {@code ObservableNumberValue}
4505      * @param op2
4506      *            the constant value
4507      * @return the new {@code NumberBinding}
4508      * @throws NullPointerException
4509      *             if the {@code ObservableNumberValue} is {@code null}
4510      */
4511     public static NumberBinding max(final ObservableNumberValue op1, final long op2) {
4512         return max(op1, LongConstant.valueOf(op2), op1);
4513     }
4514 
4515     /**
4516      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
4517      * the maximum of the value of a
4518      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
4519      *
4520      * @param op1
4521      *            the constant value
4522      * @param op2
4523      *            the {@code ObservableNumberValue}
4524      * @return the new {@code NumberBinding}
4525      * @throws NullPointerException
4526      *             if the {@code ObservableNumberValue} is {@code null}
4527      */
4528     public static NumberBinding max(final long op1, final ObservableNumberValue op2) {
4529         return max(LongConstant.valueOf(op1), op2, op2);
4530     }
4531 
4532     /**
4533      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
4534      * the maximum of the value of a
4535      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
4536      *
4537      * @param op1
4538      *            the {@code ObservableNumberValue}
4539      * @param op2
4540      *            the constant value
4541      * @return the new {@code NumberBinding}
4542      * @throws NullPointerException
4543      *             if the {@code ObservableNumberValue} is {@code null}
4544      */
4545     public static NumberBinding max(final ObservableNumberValue op1, final int op2) {
4546         return max(op1, IntegerConstant.valueOf(op2), op1);
4547     }
4548 
4549     /**
4550      * Creates a new {@link javafx.beans.binding.NumberBinding} that calculates
4551      * the maximum of the value of a
4552      * {@link javafx.beans.value.ObservableNumberValue} and a constant value.
4553      *
4554      * @param op1
4555      *            the constant value
4556      * @param op2
4557      *            the {@code ObservableNumberValue}
4558      * @return the new {@code NumberBinding}
4559      * @throws NullPointerException
4560      *             if the {@code ObservableNumberValue} is {@code null}
4561      */
4562     public static NumberBinding max(final int op1, final ObservableNumberValue op2) {
4563         return max(IntegerConstant.valueOf(op1), op2, op2);
4564     }
4565 
4566     // boolean
4567     // =================================================================================================================
4568 
4569      private static class BooleanAndBinding extends BooleanBinding {
4570 
4571         private final ObservableBooleanValue op1;
4572         private final ObservableBooleanValue op2;
4573         private final InvalidationListener observer;
4574 
4575         public BooleanAndBinding(ObservableBooleanValue op1, ObservableBooleanValue op2) {
4576             this.op1 = op1;
4577             this.op2 = op2;
4578 
4579             observer = new ShortCircuitAndInvalidator(this);
4580 
4581             op1.addListener(observer);
4582             op2.addListener(observer);
4583         }
4584 
4585 
4586         @Override
4587         public void dispose() {
4588             op1.removeListener(observer);
4589             op2.removeListener(observer);
4590         }
4591 
4592         @Override
4593         protected boolean computeValue() {
4594             return op1.get() && op2.get();
4595         }
4596 
4597         @Override
4598         public ObservableList<?> getDependencies() {
4599             return new ImmutableObservableList<>(op1, op2);
4600         }
4601     }
4602 
4603     private static class ShortCircuitAndInvalidator implements InvalidationListener {
4604 
4605         private final WeakReference<BooleanAndBinding> ref;
4606 
4607         private ShortCircuitAndInvalidator(BooleanAndBinding binding) {
4608             assert binding != null;
4609             ref = new WeakReference<>(binding);
4610         }
4611 
4612         @Override
4613         public void invalidated(Observable observable) {
4614             final BooleanAndBinding binding = ref.get();
4615             if (binding == null) {
4616                 observable.removeListener(this);
4617             } else {
4618                 // short-circuit invalidation. This BooleanBinding becomes
4619                 // only invalid if the first operator changes or the
4620                 // first parameter is true.
4621                 if ((binding.op1.equals(observable) || (binding.isValid() && binding.op1.get()))) {
4622                     binding.invalidate();
4623                 }
4624             }
4625         }
4626 
4627     }
4628 
4629     /**
4630      * Creates a {@link BooleanBinding} that calculates the conditional-AND
4631      * operation on the value of two instance of
4632      * {@link javafx.beans.value.ObservableBooleanValue}.
4633      *
4634      * @param op1
4635      *            first {@code ObservableBooleanValue}
4636      * @param op2
4637      *            second {@code ObservableBooleanValue}
4638      * @return the new {@code BooleanBinding}
4639      * @throws NullPointerException
4640      *             if one of the operands is {@code null}
4641      */
4642     public static BooleanBinding and(final ObservableBooleanValue op1, final ObservableBooleanValue op2) {
4643         if ((op1 == null) || (op2 == null)) {
4644             throw new NullPointerException("Operands cannot be null.");
4645         }
4646 
4647         return new BooleanAndBinding(op1, op2);
4648     }
4649 
4650     private static class BooleanOrBinding extends BooleanBinding {
4651 
4652         private final ObservableBooleanValue op1;
4653         private final ObservableBooleanValue op2;
4654         private final InvalidationListener observer;
4655 
4656         public BooleanOrBinding(ObservableBooleanValue op1, ObservableBooleanValue op2) {
4657             this.op1 = op1;
4658             this.op2 = op2;
4659             observer = new ShortCircuitOrInvalidator(this);
4660             op1.addListener(observer);
4661             op2.addListener(observer);
4662         }
4663 
4664 
4665         @Override
4666         public void dispose() {
4667             op1.removeListener(observer);
4668             op2.removeListener(observer);
4669         }
4670 
4671         @Override
4672         protected boolean computeValue() {
4673             return op1.get() || op2.get();
4674         }
4675 
4676         @Override
4677         public ObservableList<?> getDependencies() {
4678             return new ImmutableObservableList<>(op1, op2);
4679         }
4680     }
4681 
4682 
4683     private static class ShortCircuitOrInvalidator implements InvalidationListener {
4684 
4685         private final WeakReference<BooleanOrBinding> ref;
4686 
4687         private ShortCircuitOrInvalidator(BooleanOrBinding binding) {
4688             assert binding != null;
4689             ref = new WeakReference<>(binding);
4690         }
4691 
4692         @Override
4693         public void invalidated(Observable observable) {
4694             final BooleanOrBinding binding = ref.get();
4695             if (binding == null) {
4696                 observable.removeListener(this);
4697             } else {
4698                 // short circuit invalidation. This BooleanBinding becomes
4699                 // only invalid if the first operator changes or the
4700                 // first parameter is false.
4701                 if ((binding.op1.equals(observable) || (binding.isValid() && !binding.op1.get()))) {
4702                     binding.invalidate();
4703                 }
4704             }
4705         }
4706 
4707     }
4708 
4709     /**
4710      * Creates a {@link BooleanBinding} that calculates the conditional-OR
4711      * operation on the value of two instance of
4712      * {@link javafx.beans.value.ObservableBooleanValue}.
4713      *
4714      * @param op1
4715      *            first {@code ObservableBooleanValue}
4716      * @param op2
4717      *            second {@code ObservableBooleanValue}
4718      * @return the new {@code BooleanBinding}
4719      * @throws NullPointerException
4720      *             if one of the operands is {@code null}
4721      */
4722     public static BooleanBinding or(final ObservableBooleanValue op1, final ObservableBooleanValue op2) {
4723         if ((op1 == null) || (op2 == null)) {
4724             throw new NullPointerException("Operands cannot be null.");
4725         }
4726 
4727         return new BooleanOrBinding(op1, op2);
4728     }
4729 
4730     /**
4731      * Creates a {@link BooleanBinding} that calculates the inverse of the value
4732      * of a {@link javafx.beans.value.ObservableBooleanValue}.
4733      *
4734      * @param op
4735      *            the {@code ObservableBooleanValue}
4736      * @return the new {@code BooleanBinding}
4737      * @throws NullPointerException
4738      *             if the operand is {@code null}
4739      */
4740     public static BooleanBinding not(final ObservableBooleanValue op) {
4741         if (op == null) {
4742             throw new NullPointerException("Operand cannot be null.");
4743         }
4744 
4745         return new BooleanBinding() {
4746             {
4747                 super.bind(op);
4748             }
4749 
4750             @Override
4751             public void dispose() {
4752                 super.unbind(op);
4753             }
4754 
4755             @Override
4756             protected boolean computeValue() {
4757                 return !op.get();
4758             }
4759 
4760             @Override
4761             public ObservableList<?> getDependencies() {
4762                 return FXCollections.singletonObservableList(op);
4763             }
4764         };
4765     }
4766 
4767     /**
4768      * Creates a new {@link BooleanBinding} that holds {@code true} if the values of two
4769      * instances of {@link javafx.beans.value.ObservableBooleanValue} are equal.
4770      *
4771      * @param op1
4772      *            the first operand
4773      * @param op2
4774      *            the second operand
4775      * @return the new {@code BooleanBinding}
4776      * @throws NullPointerException
4777      *             if one of the operands is {@code null}
4778      */
4779     public static BooleanBinding equal(final ObservableBooleanValue op1, final ObservableBooleanValue op2) {
4780         if ((op1 == null) || (op2 == null)) {
4781             throw new NullPointerException("Operands cannot be null.");
4782         }
4783 
4784         return new BooleanBinding() {
4785             {
4786                 super.bind(op1, op2);
4787             }
4788 
4789             @Override
4790             public void dispose() {
4791                 super.unbind(op1, op2);
4792             }
4793 
4794             @Override
4795             protected boolean computeValue() {
4796                 return op1.get() == op2.get();
4797             }
4798 
4799             @Override
4800             public ObservableList<?> getDependencies() {
4801                 return new ImmutableObservableList<ObservableBooleanValue>(op1, op2);
4802             }
4803         };
4804     }
4805 
4806     /**
4807      * Creates a new {@link BooleanBinding} that holds {@code true} if the values of two
4808      * instances of {@link javafx.beans.value.ObservableBooleanValue} are not
4809      * equal.
4810      *
4811      * @param op1
4812      *            the first operand
4813      * @param op2
4814      *            the second operand
4815      * @return the new {@code BooleanBinding}
4816      * @throws NullPointerException
4817      *             if one of the operands is {@code null}
4818      */
4819     public static BooleanBinding notEqual(final ObservableBooleanValue op1, final ObservableBooleanValue op2) {
4820         if ((op1 == null) || (op2 == null)) {
4821             throw new NullPointerException("Operands cannot be null.");
4822         }
4823 
4824         return new BooleanBinding() {
4825             {
4826                 super.bind(op1, op2);
4827             }
4828 
4829             @Override
4830             public void dispose() {
4831                 super.unbind(op1, op2);
4832             }
4833 
4834             @Override
4835             protected boolean computeValue() {
4836                 return op1.get() != op2.get();
4837             }
4838 
4839             @Override
4840             public ObservableList<?> getDependencies() {
4841                 return new ImmutableObservableList<ObservableBooleanValue>(op1, op2);
4842             }
4843         };
4844     }
4845 
4846     // String
4847     // =================================================================================================================
4848 
4849     /**
4850      * Returns a {@link javafx.beans.binding.StringExpression} that wraps a
4851      * {@link javafx.beans.value.ObservableValue}. If the
4852      * {@code ObservableValue} is already a {@code StringExpression}, it will be
4853      * returned. Otherwise a new {@link javafx.beans.binding.StringBinding} is
4854      * created that holds the value of the {@code ObservableValue} converted to
4855      * a {@code String}.
4856      *
4857      * @param observableValue
4858      *            The source {@code ObservableValue}
4859      * @return A {@code StringExpression} that wraps the {@code ObservableValue}
4860      *         if necessary
4861      * @throws NullPointerException
4862      *             if {@code observableValue} is {@code null}
4863      */
4864     public static StringExpression convert(ObservableValue<?> observableValue) {
4865         return StringFormatter.convert(observableValue);
4866     }
4867 
4868     /**
4869      * Returns a {@link javafx.beans.binding.StringExpression} that holds the
4870      * value of the concatenation of multiple {@code Objects}.
4871      * <p>
4872      * If one of the arguments implements
4873      * {@link javafx.beans.value.ObservableValue} and the value of this
4874      * {@code ObservableValue} changes, the change is automatically reflected in
4875      * the {@code StringExpression}.
4876      * <p>
4877      * If {@code null} or an empty array is passed to this method, a
4878      * {@code StringExpression} that contains an empty {@code String} is
4879      * returned
4880      *
4881      * @param args
4882      *            the {@code Objects} that should be concatenated
4883      * @return the new {@code StringExpression}
4884      */
4885     public static StringExpression concat(Object... args) {
4886         return StringFormatter.concat(args);
4887     }
4888 
4889     /**
4890      * Creates a {@link javafx.beans.binding.StringExpression} that holds the
4891      * value of multiple {@code Objects} formatted according to a format
4892      * {@code String}.
4893      * <p>
4894      * If one of the arguments implements
4895      * {@link javafx.beans.value.ObservableValue} and the value of this
4896      * {@code ObservableValue} changes, the change is automatically reflected in
4897      * the {@code StringExpression}.
4898      * <p>
4899      * See {@code java.util.Formatter} for formatting rules.
4900      *
4901      * @param format
4902      *            the formatting {@code String}
4903      * @param args
4904      *            the {@code Objects} that should be inserted in the formatting
4905      *            {@code String}
4906      * @return the new {@code StringExpression}
4907      */
4908     public static StringExpression format(String format, Object... args) {
4909         return StringFormatter.format(format, args);
4910     }
4911 
4912     /**
4913      * Creates a {@link javafx.beans.binding.StringExpression} that holds the
4914      * value of multiple {@code Objects} formatted according to a format
4915      * {@code String} and a specified {@code Locale}
4916      * <p>
4917      * If one of the arguments implements
4918      * {@link javafx.beans.value.ObservableValue} and the value of this
4919      * {@code ObservableValue} changes, the change is automatically reflected in
4920      * the {@code StringExpression}.
4921      * <p>
4922      * See {@code java.util.Formatter} for formatting rules. See
4923      * {@code java.util.Locale} for details on {@code Locale}.
4924      *
4925      * @param locale
4926      *            the {@code Locale} to use during formatting
4927      * @param format
4928      *            the formatting {@code String}
4929      * @param args
4930      *            the {@code Objects} that should be inserted in the formatting
4931      *            {@code String}
4932      * @return the new {@code StringExpression}
4933      */
4934     public static StringExpression format(Locale locale, String format,
4935             Object... args) {
4936         return StringFormatter.format(locale, format, args);
4937     }
4938 
4939     private static String getStringSafe(String value) {
4940         return value == null ? "" : value;
4941     }
4942 
4943     private static BooleanBinding equal(final ObservableStringValue op1, final ObservableStringValue op2, final Observable... dependencies) {
4944         if ((op1 == null) || (op2 == null)) {
4945             throw new NullPointerException("Operands cannot be null.");
4946         }
4947         assert (dependencies != null) && (dependencies.length > 0);
4948 
4949         return new BooleanBinding() {
4950             {
4951                 super.bind(dependencies);
4952             }
4953 
4954             @Override
4955             public void dispose() {
4956                 super.unbind(dependencies);
4957             }
4958 
4959             @Override
4960             protected boolean computeValue() {
4961                 final String s1 = getStringSafe(op1.get());
4962                 final String s2 = getStringSafe(op2.get());
4963                 return s1.equals(s2);
4964             }
4965 
4966             @Override
4967             public ObservableList<?> getDependencies() {
4968                 return (dependencies.length == 1)?
4969                         FXCollections.singletonObservableList(dependencies[0])
4970                         : new ImmutableObservableList<Observable>(dependencies);
4971             }
4972         };
4973     }
4974 
4975     /**
4976      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
4977      * if the values of two instances of
4978      * {@link javafx.beans.value.ObservableStringValue} are equal.
4979      * <p>
4980      * Note: In this comparison a {@code String} that is {@code null} is
4981      * considered equal to an empty {@code String}.
4982      *
4983      * @param op1
4984      *            the first operand
4985      * @param op2
4986      *            the second operand
4987      * @return the new {@code BooleanBinding}
4988      * @throws NullPointerException
4989      *             if one of the operands is {@code null}
4990      */
4991     public static BooleanBinding equal(final ObservableStringValue op1, final ObservableStringValue op2) {
4992         return equal(op1, op2, op1, op2);
4993     }
4994 
4995     /**
4996      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
4997      * if the value of a {@link javafx.beans.value.ObservableStringValue} is
4998      * equal to a constant value.
4999      * <p>
5000      * Note: In this comparison a {@code String} that is {@code null} is
5001      * considered equal to an empty {@code String}.
5002      *
5003      * @param op1
5004      *            the {@code ObservableStringValue}
5005      * @param op2
5006      *            the constant value
5007      * @return the new {@code BooleanBinding}
5008      * @throws NullPointerException
5009      *             if the {@code ObservableStringValue} is {@code null}
5010      */
5011     public static BooleanBinding equal(final ObservableStringValue op1, String op2) {
5012         return equal(op1, StringConstant.valueOf(op2), op1);
5013     }
5014 
5015     /**
5016      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5017      * if the value of a {@link javafx.beans.value.ObservableStringValue} is
5018      * equal to a constant value.
5019      * <p>
5020      * Note: In this comparison a {@code String} that is {@code null} is
5021      * considered equal to an empty {@code String}.
5022      *
5023      * @param op1
5024      *            the constant value
5025      * @param op2
5026      *            the {@code ObservableStringValue}
5027      * @return the new {@code BooleanBinding}
5028      * @throws NullPointerException
5029      *             if the {@code ObservableStringValue} is {@code null}
5030      */
5031     public static BooleanBinding equal(String op1, final ObservableStringValue op2) {
5032         return equal(StringConstant.valueOf(op1), op2, op2);
5033     }
5034 
5035     private static BooleanBinding notEqual(final ObservableStringValue op1, final ObservableStringValue op2, final Observable... dependencies) {
5036         if ((op1 == null) || (op2 == null)) {
5037             throw new NullPointerException("Operands cannot be null.");
5038         }
5039         assert (dependencies != null) && (dependencies.length > 0);
5040 
5041         return new BooleanBinding() {
5042             {
5043                 super.bind(dependencies);
5044             }
5045 
5046             @Override
5047             public void dispose() {
5048                 super.unbind(dependencies);
5049             }
5050 
5051             @Override
5052             protected boolean computeValue() {
5053                 final String s1 = getStringSafe(op1.get());
5054                 final String s2 = getStringSafe(op2.get());
5055                 return ! s1.equals(s2);
5056             }
5057 
5058             @Override
5059             public ObservableList<?> getDependencies() {
5060                 return (dependencies.length == 1)?
5061                         FXCollections.singletonObservableList(dependencies[0])
5062                         : new ImmutableObservableList<Observable>(dependencies);
5063             }
5064         };
5065     }
5066 
5067     /**
5068      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5069      * if the values of two instances of
5070      * {@link javafx.beans.value.ObservableStringValue} are not equal.
5071      * <p>
5072      * Note: In this comparison a {@code String} that is {@code null} is
5073      * considered equal to an empty {@code String}.
5074      *
5075      * @param op1
5076      *            the first operand
5077      * @param op2
5078      *            the second operand
5079      * @return the new {@code BooleanBinding}
5080      * @throws NullPointerException
5081      *             if one of the operands is {@code null}
5082      */
5083     public static BooleanBinding notEqual(final ObservableStringValue op1, final ObservableStringValue op2) {
5084         return notEqual(op1, op2, op1, op2);
5085     }
5086 
5087     /**
5088      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5089      * if the value of a {@link javafx.beans.value.ObservableStringValue} is not
5090      * equal to a constant value.
5091      * <p>
5092      * Note: In this comparison a {@code String} that is {@code null} is
5093      * considered equal to an empty {@code String}.
5094      *
5095      * @param op1
5096      *            the {@code ObservableStringValue}
5097      * @param op2
5098      *            the constant value
5099      * @return the new {@code BooleanBinding}
5100      * @throws NullPointerException
5101      *             if the {@code ObservableStringValue} is {@code null}
5102      */
5103     public static BooleanBinding notEqual(final ObservableStringValue op1, String op2) {
5104         return notEqual(op1, StringConstant.valueOf(op2), op1);
5105     }
5106 
5107     /**
5108      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5109      * if the value of a {@link javafx.beans.value.ObservableStringValue} is not
5110      * equal to a constant value.
5111      * <p>
5112      * Note: In this comparison a {@code String} that is {@code null} is
5113      * considered equal to an empty {@code String}.
5114      *
5115      * @param op1
5116      *            the constant value
5117      * @param op2
5118      *            the {@code ObservableStringValue}
5119      * @return the new {@code BooleanBinding}
5120      * @throws NullPointerException
5121      *             if the {@code ObservableStringValue} is {@code null}
5122      */
5123     public static BooleanBinding notEqual(String op1, final ObservableStringValue op2) {
5124         return notEqual(StringConstant.valueOf(op1), op2, op2);
5125     }
5126 
5127     private static BooleanBinding equalIgnoreCase(final ObservableStringValue op1, final ObservableStringValue op2, final Observable... dependencies) {
5128         if ((op1 == null) || (op2 == null)) {
5129             throw new NullPointerException("Operands cannot be null.");
5130         }
5131         assert (dependencies != null) && (dependencies.length > 0);
5132 
5133         return new BooleanBinding() {
5134             {
5135                 super.bind(dependencies);
5136             }
5137 
5138             @Override
5139             public void dispose() {
5140                 super.unbind(dependencies);
5141             }
5142 
5143             @Override
5144             protected boolean computeValue() {
5145                 final String s1 = getStringSafe(op1.get());
5146                 final String s2 = getStringSafe(op2.get());
5147                 return s1.equalsIgnoreCase(s2);
5148             }
5149 
5150             @Override
5151             public ObservableList<?> getDependencies() {
5152                 return (dependencies.length == 1)?
5153                         FXCollections.singletonObservableList(dependencies[0])
5154                         : new ImmutableObservableList<Observable>(dependencies);
5155             }
5156         };
5157     }
5158 
5159     /**
5160      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5161      * if the values of two instances of
5162      * {@link javafx.beans.value.ObservableStringValue} are equal ignoring case.
5163      * <p>
5164      * Note: In this comparison a {@code String} that is {@code null} is
5165      * considered equal to an empty {@code String}.
5166      *
5167      * @param op1
5168      *            the first operand
5169      * @param op2
5170      *            the second operand
5171      * @return the new {@code BooleanBinding}
5172      * @throws NullPointerException
5173      *             if one of the operands is {@code null}
5174      */
5175     public static BooleanBinding equalIgnoreCase(final ObservableStringValue op1, final ObservableStringValue op2) {
5176         return equalIgnoreCase(op1, op2, op1, op2);
5177     }
5178 
5179     /**
5180      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5181      * if the value of a {@link javafx.beans.value.ObservableStringValue} is
5182      * equal to a constant value ignoring case.
5183      * <p>
5184      * Note: In this comparison a {@code String} that is {@code null} is
5185      * considered equal to an empty {@code String}.
5186      *
5187      * @param op1
5188      *            the {@code ObservableStringValue}
5189      * @param op2
5190      *            the constant value
5191      * @return the new {@code BooleanBinding}
5192      * @throws NullPointerException
5193      *             if the {@code ObservableStringValue} is {@code null}
5194      */
5195     public static BooleanBinding equalIgnoreCase(final ObservableStringValue op1, String op2) {
5196         return equalIgnoreCase(op1, StringConstant.valueOf(op2), op1);
5197     }
5198 
5199     /**
5200      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5201      * if the value of a {@link javafx.beans.value.ObservableStringValue} is
5202      * equal to a constant value ignoring case.
5203      * <p>
5204      * Note: In this comparison a {@code String} that is {@code null} is
5205      * considered equal to an empty {@code String}.
5206      *
5207      * @param op1
5208      *            the constant value
5209      * @param op2
5210      *            the {@code ObservableStringValue}
5211      * @return the new {@code BooleanBinding}
5212      * @throws NullPointerException
5213      *             if the {@code ObservableStringValue} is {@code null}
5214      */
5215     public static BooleanBinding equalIgnoreCase(String op1, final ObservableStringValue op2) {
5216         return equalIgnoreCase(StringConstant.valueOf(op1), op2, op2);
5217     }
5218 
5219     private static BooleanBinding notEqualIgnoreCase(final ObservableStringValue op1, final ObservableStringValue op2, final Observable... dependencies) {
5220         if ((op1 == null) || (op2 == null)) {
5221             throw new NullPointerException("Operands cannot be null.");
5222         }
5223         assert (dependencies != null) && (dependencies.length > 0);
5224 
5225         return new BooleanBinding() {
5226             {
5227                 super.bind(dependencies);
5228             }
5229 
5230             @Override
5231             public void dispose() {
5232                 super.unbind(dependencies);
5233             }
5234 
5235             @Override
5236             protected boolean computeValue() {
5237                 final String s1 = getStringSafe(op1.get());
5238                 final String s2 = getStringSafe(op2.get());
5239                 return ! s1.equalsIgnoreCase(s2);
5240             }
5241 
5242             @Override
5243             public ObservableList<?> getDependencies() {
5244                 return (dependencies.length == 1)?
5245                         FXCollections.singletonObservableList(dependencies[0])
5246                         : new ImmutableObservableList<Observable>(dependencies);
5247             }
5248         };
5249     }
5250 
5251     /**
5252      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5253      * if the values of two instances of
5254      * {@link javafx.beans.value.ObservableStringValue} are not equal ignoring
5255      * case.
5256      * <p>
5257      * Note: In this comparison a {@code String} that is {@code null} is
5258      * considered equal to an empty {@code String}.
5259      *
5260      * @param op1
5261      *            the first operand
5262      * @param op2
5263      *            the second operand
5264      * @return the new {@code BooleanBinding}
5265      * @throws NullPointerException
5266      *             if one of the operands is {@code null}
5267      */
5268     public static BooleanBinding notEqualIgnoreCase(final ObservableStringValue op1, final ObservableStringValue op2) {
5269         return notEqualIgnoreCase(op1, op2, op1, op2);
5270     }
5271 
5272     /**
5273      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5274      * if the value of a {@link javafx.beans.value.ObservableStringValue} is not
5275      * equal to a constant value ignoring case.
5276      * <p>
5277      * Note: In this comparison a {@code String} that is {@code null} is
5278      * considered equal to an empty {@code String}.
5279      *
5280      * @param op1
5281      *            the {@code ObservableStringValue}
5282      * @param op2
5283      *            the constant value
5284      * @return the new {@code BooleanBinding}
5285      * @throws NullPointerException
5286      *             if the {@code ObservableStringValue} is {@code null}
5287      */
5288     public static BooleanBinding notEqualIgnoreCase(final ObservableStringValue op1, String op2) {
5289         return notEqualIgnoreCase(op1, StringConstant.valueOf(op2), op1);
5290     }
5291 
5292     /**
5293      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5294      * if the value of a {@link javafx.beans.value.ObservableStringValue} is not
5295      * equal to a constant value ignoring case.
5296      * <p>
5297      * Note: In this comparison a {@code String} that is {@code null} is
5298      * considered equal to an empty {@code String}.
5299      *
5300      * @param op1
5301      *            the constant value
5302      * @param op2
5303      *            the {@code ObservableStringValue}
5304      * @return the new {@code BooleanBinding}
5305      * @throws NullPointerException
5306      *             if the {@code ObservableStringValue} is {@code null}
5307      */
5308     public static BooleanBinding notEqualIgnoreCase(String op1, final ObservableStringValue op2) {
5309         return notEqualIgnoreCase(StringConstant.valueOf(op1), op2, op2);
5310     }
5311 
5312     private static BooleanBinding greaterThan(final ObservableStringValue op1, final ObservableStringValue op2, final Observable... dependencies) {
5313         if ((op1 == null) || (op2 == null)) {
5314             throw new NullPointerException("Operands cannot be null.");
5315         }
5316         assert (dependencies != null) && (dependencies.length > 0);
5317 
5318         return new BooleanBinding() {
5319             {
5320                 super.bind(dependencies);
5321             }
5322 
5323             @Override
5324             public void dispose() {
5325                 super.unbind(dependencies);
5326             }
5327 
5328             @Override
5329             protected boolean computeValue() {
5330                 final String s1 = getStringSafe(op1.get());
5331                 final String s2 = getStringSafe(op2.get());
5332                 return s1.compareTo(s2) > 0;
5333             }
5334 
5335             @Override
5336             public ObservableList<?> getDependencies() {
5337                 return (dependencies.length == 1)?
5338                         FXCollections.singletonObservableList(dependencies[0])
5339                         : new ImmutableObservableList<Observable>(dependencies);
5340             }
5341         };
5342     }
5343 
5344     /**
5345      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5346      * if the value of the first
5347      * {@link javafx.beans.value.ObservableStringValue} is greater than the
5348      * value of the second.
5349      * <p>
5350      * Note: In this comparison a {@code String} that is {@code null} is
5351      * considered equal to an empty {@code String}.
5352      *
5353      * @param op1
5354      *            the first operand
5355      * @param op2
5356      *            the second operand
5357      * @return the new {@code BooleanBinding}
5358      * @throws NullPointerException
5359      *             if one of the operands is {@code null}
5360      */
5361     public static BooleanBinding greaterThan(final ObservableStringValue op1, final ObservableStringValue op2) {
5362         return greaterThan(op1, op2, op1, op2);
5363     }
5364 
5365     /**
5366      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5367      * if the value of a {@link javafx.beans.value.ObservableStringValue} is
5368      * greater than a constant value.
5369      * <p>
5370      * Note: In this comparison a {@code String} that is {@code null} is
5371      * considered equal to an empty {@code String}.
5372      *
5373      * @param op1
5374      *            the {@code ObservableStringValue}
5375      * @param op2
5376      *            the constant value
5377      * @return the new {@code BooleanBinding}
5378      * @throws NullPointerException
5379      *             if the {@code ObservableStringValue} is {@code null}
5380      */
5381     public static BooleanBinding greaterThan(final ObservableStringValue op1, String op2) {
5382         return greaterThan(op1, StringConstant.valueOf(op2), op1);
5383     }
5384 
5385     /**
5386      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5387      * if the value of a constant value is greater than the value of a
5388      * {@link javafx.beans.value.ObservableStringValue}.
5389      * <p>
5390      * Note: In this comparison a {@code String} that is {@code null} is
5391      * considered equal to an empty {@code String}.
5392      *
5393      * @param op1
5394      *            the constant value
5395      * @param op2
5396      *            the {@code ObservableStringValue}
5397      * @return the new {@code BooleanBinding}
5398      * @throws NullPointerException
5399      *             if the {@code ObservableStringValue} is {@code null}
5400      */
5401     public static BooleanBinding greaterThan(String op1, final ObservableStringValue op2) {
5402         return greaterThan(StringConstant.valueOf(op1), op2, op2);
5403     }
5404 
5405     private static BooleanBinding lessThan(final ObservableStringValue op1, final ObservableStringValue op2, final Observable... dependencies) {
5406         return greaterThan(op2, op1, dependencies);
5407     }
5408 
5409     /**
5410      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5411      * if the value of the first
5412      * {@link javafx.beans.value.ObservableStringValue} is less than the value
5413      * of the second.
5414      * <p>
5415      * Note: In this comparison a {@code String} that is {@code null} is
5416      * considered equal to an empty {@code String}.
5417      *
5418      * @param op1
5419      *            the first operand
5420      * @param op2
5421      *            the second operand
5422      * @return the new {@code BooleanBinding}
5423      * @throws NullPointerException
5424      *             if one of the operands is {@code null}
5425      */
5426     public static BooleanBinding lessThan(final ObservableStringValue op1, final ObservableStringValue op2) {
5427         return lessThan(op1, op2, op1, op2);
5428     }
5429 
5430     /**
5431      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5432      * if the value of a {@link javafx.beans.value.ObservableStringValue} is
5433      * less than a constant value.
5434      * <p>
5435      * Note: In this comparison a {@code String} that is {@code null} is
5436      * considered equal to an empty {@code String}.
5437      *
5438      * @param op1
5439      *            the {@code ObservableStringValue}
5440      * @param op2
5441      *            the constant value
5442      * @return the new {@code BooleanBinding}
5443      * @throws NullPointerException
5444      *             if the {@code ObservableStringValue} is {@code null}
5445      */
5446     public static BooleanBinding lessThan(final ObservableStringValue op1, String op2) {
5447         return lessThan(op1, StringConstant.valueOf(op2), op1);
5448     }
5449 
5450     /**
5451      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5452      * if a constant value is less than the value of a
5453      * {@link javafx.beans.value.ObservableStringValue}.
5454      * <p>
5455      * Note: In this comparison a {@code String} that is {@code null} is
5456      * considered equal to an empty {@code String}.
5457      *
5458      * @param op1
5459      *            the constant value
5460      * @param op2
5461      *            the {@code ObservableStringValue}
5462      * @return the new {@code BooleanBinding}
5463      * @throws NullPointerException
5464      *             if the {@code ObservableStringValue} is {@code null}
5465      */
5466     public static BooleanBinding lessThan(String op1, final ObservableStringValue op2) {
5467         return lessThan(StringConstant.valueOf(op1), op2, op2);
5468     }
5469 
5470     private static BooleanBinding greaterThanOrEqual(final ObservableStringValue op1, final ObservableStringValue op2, final Observable... dependencies) {
5471         if ((op1 == null) || (op2 == null)) {
5472             throw new NullPointerException("Operands cannot be null.");
5473         }
5474         assert (dependencies != null) && (dependencies.length > 0);
5475 
5476         return new BooleanBinding() {
5477             {
5478                 super.bind(dependencies);
5479             }
5480 
5481             @Override
5482             public void dispose() {
5483                 super.unbind(dependencies);
5484             }
5485 
5486             @Override
5487             protected boolean computeValue() {
5488                 final String s1 = getStringSafe(op1.get());
5489                 final String s2 = getStringSafe(op2.get());
5490                 return s1.compareTo(s2) >= 0;
5491             }
5492 
5493             @Override
5494             public ObservableList<?> getDependencies() {
5495                 return (dependencies.length == 1)?
5496                         FXCollections.singletonObservableList(dependencies[0])
5497                         : new ImmutableObservableList<Observable>(dependencies);
5498             }
5499         };
5500     }
5501 
5502     /**
5503      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5504      * if the value of the first
5505      * {@link javafx.beans.value.ObservableStringValue} is greater than or equal
5506      * to the value of the second.
5507      * <p>
5508      * Note: In this comparison a {@code String} that is {@code null} is
5509      * considered equal to an empty {@code String}.
5510      *
5511      * @param op1
5512      *            the first operand
5513      * @param op2
5514      *            the second operand
5515      * @return the new {@code BooleanBinding}
5516      * @throws NullPointerException
5517      *             if one of the operands is {@code null}
5518      */
5519     public static BooleanBinding greaterThanOrEqual(final ObservableStringValue op1, final ObservableStringValue op2) {
5520         return greaterThanOrEqual(op1, op2, op1, op2);
5521     }
5522 
5523     /**
5524      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5525      * if the value of a {@link javafx.beans.value.ObservableStringValue} is
5526      * greater than or equal to a constant value.
5527      * <p>
5528      * Note: In this comparison a {@code String} that is {@code null} is
5529      * considered equal to an empty {@code String}.
5530      *
5531      * @param op1
5532      *            the {@code ObservableStringValue}
5533      * @param op2
5534      *            the constant value
5535      * @return the new {@code BooleanBinding}
5536      * @throws NullPointerException
5537      *             if the {@code ObservableStringValue} is {@code null}
5538      */
5539     public static BooleanBinding greaterThanOrEqual(final ObservableStringValue op1, String op2) {
5540         return greaterThanOrEqual(op1, StringConstant.valueOf(op2), op1);
5541     }
5542 
5543     /**
5544      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5545      * if a constant value is greater than or equal to the value of a
5546      * {@link javafx.beans.value.ObservableStringValue}.
5547      * <p>
5548      * Note: In this comparison a {@code String} that is {@code null} is
5549      * considered equal to an empty {@code String}.
5550      *
5551      * @param op1
5552      *            the constant value
5553      * @param op2
5554      *            the {@code ObservableStringValue}
5555      * @return the new {@code BooleanBinding}
5556      * @throws NullPointerException
5557      *             if the {@code ObservableStringValue} is {@code null}
5558      */
5559     public static BooleanBinding greaterThanOrEqual(String op1, final ObservableStringValue op2) {
5560         return greaterThanOrEqual(StringConstant.valueOf(op1), op2, op2);
5561     }
5562 
5563     private static BooleanBinding lessThanOrEqual(final ObservableStringValue op1, final ObservableStringValue op2, final Observable... dependencies) {
5564         return greaterThanOrEqual(op2, op1, dependencies);
5565     }
5566 
5567     /**
5568      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5569      * if the value of the first
5570      * {@link javafx.beans.value.ObservableStringValue} is less than or equal to
5571      * the value of the second.
5572      * <p>
5573      * Note: In this comparison a {@code String} that is {@code null} is
5574      * considered equal to an empty {@code String}.
5575      *
5576      * @param op1
5577      *            the first operand
5578      * @param op2
5579      *            the second operand
5580      * @return the new {@code BooleanBinding}
5581      * @throws NullPointerException
5582      *             if one of the operands is {@code null}
5583      */
5584     public static BooleanBinding lessThanOrEqual(final ObservableStringValue op1, final ObservableStringValue op2) {
5585         return lessThanOrEqual(op1, op2, op1, op2);
5586     }
5587 
5588     /**
5589      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5590      * if the value of a {@link javafx.beans.value.ObservableStringValue} is
5591      * less than or equal to a constant value.
5592      * <p>
5593      * Note: In this comparison a {@code String} that is {@code null} is
5594      * considered equal to an empty {@code String}.
5595      *
5596      * @param op1
5597      *            the {@code ObservableStringValue}
5598      * @param op2
5599      *            the constant value
5600      * @return the new {@code BooleanBinding}
5601      * @throws NullPointerException
5602      *             if the {@code ObservableStringValue} is {@code null}
5603      */
5604     public static BooleanBinding lessThanOrEqual(final ObservableStringValue op1, String op2) {
5605         return lessThanOrEqual(op1, StringConstant.valueOf(op2), op1);
5606     }
5607 
5608     /**
5609      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5610      * if a constant value is less than or equal to the value of a
5611      * {@link javafx.beans.value.ObservableStringValue}.
5612      * <p>
5613      * Note: In this comparison a {@code String} that is {@code null} is
5614      * considered equal to an empty {@code String}.
5615      *
5616      * @param op1
5617      *            the constant value
5618      * @param op2
5619      *            the {@code ObservableStringValue}
5620      * @return the new {@code BooleanBinding}
5621      * @throws NullPointerException
5622      *             if the {@code ObservableStringValue} is {@code null}
5623      */
5624     public static BooleanBinding lessThanOrEqual(String op1, final ObservableStringValue op2) {
5625         return lessThanOrEqual(StringConstant.valueOf(op1), op2, op2);
5626     }
5627 
5628     /**
5629      * Creates a new {@link javafx.beans.binding.IntegerBinding} that holds the length of a
5630      * {@link javafx.beans.value.ObservableStringValue}.
5631      * <p>
5632      * Note: In this comparison a {@code String} that is {@code null} is
5633      * considered to have a length of {@code 0}.
5634      *
5635      * @param op
5636      *            the {@code ObservableStringValue}
5637      * @return the new {@code IntegerBinding}
5638      * @throws NullPointerException
5639      *             if the {@code ObservableStringValue} is {@code null}
5640      * @since JavaFX 8.0
5641      */
5642     public static IntegerBinding length(final ObservableStringValue op) {
5643         if (op == null) {
5644             throw new NullPointerException("Operand cannot be null");
5645         }
5646 
5647         return new IntegerBinding() {
5648             {
5649                 super.bind(op);
5650             }
5651 
5652             @Override
5653             public void dispose() {
5654                 super.unbind(op);
5655             }
5656 
5657             @Override
5658             protected int computeValue() {
5659                 return getStringSafe(op.get()).length();
5660             }
5661 
5662             @Override
5663             public ObservableList<?> getDependencies() {
5664                 return FXCollections.singletonObservableList(op);
5665             }
5666         };
5667     }
5668 
5669     /**
5670      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5671      * if the value of a {@link javafx.beans.value.ObservableStringValue} is empty.
5672      * <p>
5673      * Note: In this comparison a {@code String} that is {@code null} is
5674      * considered to be empty.
5675      *
5676      * @param op
5677      *            the {@code ObservableStringValue}
5678      * @return the new {@code BooleanBinding}
5679      * @throws NullPointerException
5680      *             if the {@code ObservableStringValue} is {@code null}
5681      * @since JavaFX 8.0
5682      */
5683     public static BooleanBinding isEmpty(final ObservableStringValue op) {
5684         if (op == null) {
5685             throw new NullPointerException("Operand cannot be null");
5686         }
5687 
5688         return new BooleanBinding() {
5689             {
5690                 super.bind(op);
5691             }
5692 
5693             @Override
5694             public void dispose() {
5695                 super.unbind(op);
5696             }
5697 
5698             @Override
5699             protected boolean computeValue() {
5700                 return getStringSafe(op.get()).isEmpty();
5701             }
5702 
5703             @Override
5704             public ObservableList<?> getDependencies() {
5705                 return FXCollections.singletonObservableList(op);
5706             }
5707         };
5708     }
5709 
5710     /**
5711      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5712      * if the value of a {@link javafx.beans.value.ObservableStringValue} is not empty.
5713      * <p>
5714      * Note: In this comparison a {@code String} that is {@code null} is
5715      * considered to be empty.
5716      *
5717      * @param op
5718      *            the {@code ObservableStringValue}
5719      * @return the new {@code BooleanBinding}
5720      * @throws NullPointerException
5721      *             if the {@code ObservableStringValue} is {@code null}
5722      * @since JavaFX 8.0
5723      */
5724     public static BooleanBinding isNotEmpty(final ObservableStringValue op) {
5725         if (op == null) {
5726             throw new NullPointerException("Operand cannot be null");
5727         }
5728 
5729         return new BooleanBinding() {
5730             {
5731                 super.bind(op);
5732             }
5733 
5734             @Override
5735             public void dispose() {
5736                 super.unbind(op);
5737             }
5738 
5739             @Override
5740             protected boolean computeValue() {
5741                 return !getStringSafe(op.get()).isEmpty();
5742             }
5743 
5744             @Override
5745             public ObservableList<?> getDependencies() {
5746                 return FXCollections.singletonObservableList(op);
5747             }
5748         };
5749     }
5750 
5751     // Object
5752     // =================================================================================================================
5753 
5754     private static BooleanBinding equal(final ObservableObjectValue<?> op1, final ObservableObjectValue<?> op2, final Observable... dependencies) {
5755         if ((op1 == null) || (op2 == null)) {
5756             throw new NullPointerException("Operands cannot be null.");
5757         }
5758         assert (dependencies != null) && (dependencies.length > 0);
5759 
5760         return new BooleanBinding() {
5761             {
5762                 super.bind(dependencies);
5763             }
5764 
5765             @Override
5766             public void dispose() {
5767                 super.unbind(dependencies);
5768             }
5769 
5770             @Override
5771             protected boolean computeValue() {
5772                 final Object obj1 = op1.get();
5773                 final Object obj2 = op2.get();
5774                 return obj1 == null ? obj2 == null : obj1.equals(obj2);
5775             }
5776 
5777             @Override
5778             public ObservableList<?> getDependencies() {
5779                 return (dependencies.length == 1)?
5780                         FXCollections.singletonObservableList(dependencies[0])
5781                         : new ImmutableObservableList<Observable>(dependencies);
5782             }
5783         };
5784     }
5785 
5786     /**
5787      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5788      * if the values of two instances of
5789      * {@link javafx.beans.value.ObservableObjectValue} are equal.
5790      *
5791      * @param op1
5792      *            the first operand
5793      * @param op2
5794      *            the second operand
5795      * @return the new {@code BooleanBinding}
5796      * @throws NullPointerException
5797      *             if one of the operands is {@code null}
5798      */
5799     public static BooleanBinding equal(final ObservableObjectValue<?> op1, final ObservableObjectValue<?> op2) {
5800         return equal(op1, op2, op1, op2);
5801     }
5802 
5803     /**
5804      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5805      * if the value of an {@link javafx.beans.value.ObservableObjectValue} is
5806      * equal to a constant value.
5807      *
5808      * @param op1
5809      *            the {@code ObservableObjectValue}
5810      * @param op2
5811      *            the constant value
5812      * @return the new {@code BooleanBinding}
5813      * @throws NullPointerException
5814      *             if the {@code ObservableObjectValue} is {@code null}
5815      */
5816     public static BooleanBinding equal(final ObservableObjectValue<?> op1, Object op2) {
5817         return equal(op1, ObjectConstant.valueOf(op2), op1);
5818     }
5819 
5820     /**
5821      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5822      * if the value of an {@link javafx.beans.value.ObservableObjectValue} is
5823      * equal to a constant value.
5824      *
5825      * @param op1
5826      *            the constant value
5827      * @param op2
5828      *            the {@code ObservableObjectValue}
5829      * @return the new {@code BooleanBinding}
5830      * @throws NullPointerException
5831      *             if the {@code ObservableObjectValue} is {@code null}
5832      */
5833     public static BooleanBinding equal(Object op1, final ObservableObjectValue<?> op2) {
5834         return equal(ObjectConstant.valueOf(op1), op2, op2);
5835     }
5836 
5837     private static BooleanBinding notEqual(final ObservableObjectValue<?> op1, final ObservableObjectValue<?> op2, final Observable... dependencies) {
5838         if ((op1 == null) || (op2 == null)) {
5839             throw new NullPointerException("Operands cannot be null.");
5840         }
5841         assert (dependencies != null) && (dependencies.length > 0);
5842 
5843         return new BooleanBinding() {
5844             {
5845                 super.bind(dependencies);
5846             }
5847 
5848             @Override
5849             public void dispose() {
5850                 super.unbind(dependencies);
5851             }
5852 
5853             @Override
5854             protected boolean computeValue() {
5855                 final Object obj1 = op1.get();
5856                 final Object obj2 = op2.get();
5857                 return obj1 == null ? obj2 != null : ! obj1.equals(obj2);
5858             }
5859 
5860             @Override
5861             public ObservableList<?> getDependencies() {
5862                 return (dependencies.length == 1)?
5863                         FXCollections.singletonObservableList(dependencies[0])
5864                         : new ImmutableObservableList<Observable>(dependencies);
5865             }
5866         };
5867     }
5868 
5869     /**
5870      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5871      * if the values of two instances of
5872      * {@link javafx.beans.value.ObservableObjectValue} are not equal.
5873      *
5874      * @param op1
5875      *            the first operand
5876      * @param op2
5877      *            the second operand
5878      * @return the new {@code BooleanBinding}
5879      * @throws NullPointerException
5880      *             if one of the operands is {@code null}
5881      */
5882     public static BooleanBinding notEqual(final ObservableObjectValue<?> op1, final ObservableObjectValue<?> op2) {
5883         return notEqual(op1, op2, op1, op2);
5884     }
5885 
5886     /**
5887      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5888      * if the value of an {@link javafx.beans.value.ObservableObjectValue} is
5889      * not equal to a constant value.
5890      *
5891      * @param op1
5892      *            the {@code ObservableObjectValue}
5893      * @param op2
5894      *            the constant value
5895      * @return the new {@code BooleanBinding}
5896      * @throws NullPointerException
5897      *             if the {@code ObservableObjectValue} is {@code null}
5898      */
5899     public static BooleanBinding notEqual(final ObservableObjectValue<?> op1, Object op2) {
5900         return notEqual(op1, ObjectConstant.valueOf(op2), op1);
5901     }
5902 
5903     /**
5904      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5905      * if the value of an {@link javafx.beans.value.ObservableObjectValue} is
5906      * not equal to a constant value.
5907      *
5908      * @param op1
5909      *            the constant value
5910      * @param op2
5911      *            the {@code ObservableObjectValue}
5912      * @return the new {@code BooleanBinding}
5913      * @throws NullPointerException
5914      *             if the {@code ObservableObjectValue} is {@code null}
5915      */
5916     public static BooleanBinding notEqual(Object op1, final ObservableObjectValue<?> op2) {
5917         return notEqual(ObjectConstant.valueOf(op1), op2, op2);
5918     }
5919 
5920     /**
5921      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5922      * if the value of an {@link javafx.beans.value.ObservableObjectValue} is
5923      * {@code null}.
5924      *
5925      * @param op
5926      *            the {@code ObservableObjectValue}
5927      * @return the new {@code BooleanBinding}
5928      * @throws NullPointerException
5929      *             if the {@code ObservableObjectValue} is {@code null}
5930      */
5931     public static BooleanBinding isNull(final ObservableObjectValue<?> op) {
5932         if (op == null) {
5933             throw new NullPointerException("Operand cannot be null.");
5934         }
5935 
5936         return new BooleanBinding() {
5937             {
5938                 super.bind(op);
5939             }
5940 
5941             @Override
5942             public void dispose() {
5943                 super.unbind(op);
5944             }
5945 
5946             @Override
5947             protected boolean computeValue() {
5948                 return op.get() == null;
5949             }
5950 
5951             @Override
5952             public ObservableList<?> getDependencies() {
5953                 return FXCollections.singletonObservableList(op);
5954             }
5955         };
5956     }
5957 
5958     /**
5959      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
5960      * if the value of an {@link javafx.beans.value.ObservableObjectValue} is
5961      * not {@code null}.
5962      *
5963      * @param op
5964      *            the {@code ObservableObjectValue}
5965      * @return the new {@code BooleanBinding}
5966      * @throws NullPointerException
5967      *             if the {@code ObservableObjectValue} is {@code null}
5968      */
5969     public static BooleanBinding isNotNull(final ObservableObjectValue<?> op) {
5970         if (op == null) {
5971             throw new NullPointerException("Operand cannot be null.");
5972         }
5973 
5974         return new BooleanBinding() {
5975             {
5976                 super.bind(op);
5977             }
5978 
5979             @Override
5980             public void dispose() {
5981                 super.unbind(op);
5982             }
5983 
5984             @Override
5985             protected boolean computeValue() {
5986                 return op.get() != null;
5987             }
5988 
5989             @Override
5990             public ObservableList<?> getDependencies() {
5991                 return FXCollections.singletonObservableList(op);
5992             }
5993         };
5994     }
5995 
5996     // List
5997     // =================================================================================================================
5998 
5999     /**
6000      * Creates a new {@link javafx.beans.binding.IntegerBinding} that contains the size
6001      * of an {@link javafx.collections.ObservableList}.
6002      *
6003      * @param op
6004      *            the {@code ObservableList}
6005      * @param <E> type of the {@code List} elements
6006      * @return the new {@code IntegerBinding}
6007      * @throws NullPointerException
6008      *             if the {@code ObservableList} is {@code null}
6009      * @since JavaFX 2.1
6010      */
6011     public static <E> IntegerBinding size(final ObservableList<E> op) {
6012         if (op == null) {
6013             throw new NullPointerException("List cannot be null.");
6014         }
6015 
6016         return new IntegerBinding() {
6017             {
6018                 super.bind(op);
6019             }
6020 
6021             @Override
6022             public void dispose() {
6023                 super.unbind(op);
6024             }
6025 
6026             @Override
6027             protected int computeValue() {
6028                 return op.size();
6029             }
6030 
6031             @Override
6032             public ObservableList<?> getDependencies() {
6033                 return FXCollections.singletonObservableList(op);
6034             }
6035         };
6036     }
6037 
6038     /**
6039      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
6040      * if a given {@link javafx.collections.ObservableList} is empty.
6041      *
6042      * @param op
6043      *            the {@code ObservableList}
6044      * @param <E> type of the {@code List} elements
6045      * @return the new {@code BooleanBinding}
6046      * @throws NullPointerException
6047      *             if the {@code ObservableList} is {@code null}
6048      * @since JavaFX 2.1
6049      */
6050     public static <E> BooleanBinding isEmpty(final ObservableList<E> op) {
6051         if (op == null) {
6052             throw new NullPointerException("List cannot be null.");
6053         }
6054 
6055         return new BooleanBinding() {
6056             {
6057                 super.bind(op);
6058             }
6059 
6060             @Override
6061             public void dispose() {
6062                 super.unbind(op);
6063             }
6064 
6065             @Override
6066             protected boolean computeValue() {
6067                 return op.isEmpty();
6068             }
6069 
6070             @Override
6071             public ObservableList<?> getDependencies() {
6072                 return FXCollections.singletonObservableList(op);
6073             }
6074         };
6075     }
6076 
6077     /**
6078      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
6079      * if a given {@link javafx.collections.ObservableList} is not empty.
6080      *
6081      * @param op
6082      *            the {@code ObservableList}
6083      * @param <E> type of the {@code List} elements
6084      * @return the new {@code BooleanBinding}
6085      * @throws NullPointerException
6086      *             if the {@code ObservableList} is {@code null}
6087      * @since JavaFX 8.0
6088      */
6089     public static <E> BooleanBinding isNotEmpty(final ObservableList<E> op)     {
6090         if (op == null) {
6091             throw new NullPointerException("List cannot be null.");
6092         }
6093 
6094         return new BooleanBinding() {
6095             {
6096                 super.bind(op);
6097             }
6098 
6099             @Override
6100             public void dispose() {
6101                 super.unbind(op);
6102             }
6103 
6104             @Override
6105             protected boolean computeValue() {
6106                 return !op.isEmpty();
6107             }
6108 
6109             @Override
6110             public ObservableList<?> getDependencies() {
6111                 return FXCollections.singletonObservableList(op);
6112             }
6113         };
6114     }
6115 
6116     /**
6117      * Creates a new {@link javafx.beans.binding.ObjectBinding} that contains the element
6118      * of an {@link javafx.collections.ObservableList} at the specified position. The {@code ObjectBinding}
6119      * will contain {@code null} if the {@code index} points behind the {@code ObservableList}.
6120      *
6121      * @param op the {@code ObservableList}
6122      * @param index the position in the {@code List}
6123      * @param <E> the type of the {@code List} elements
6124      * @return the new {@code ObjectBinding}
6125      * @throws NullPointerException if the {@code ObservableList} is {@code null}
6126      * @throws IllegalArgumentException if (@code index &lt; 0)
6127      * @since JavaFX 2.1
6128      */
6129     public static <E> ObjectBinding<E> valueAt(final ObservableList<E> op, final int index) {
6130         if (op == null) {
6131             throw new NullPointerException("List cannot be null.");
6132         }
6133         if (index < 0) {
6134             throw new IllegalArgumentException("Index cannot be negative");
6135         }
6136 
6137         return new ObjectBinding<E>() {
6138             {
6139                 super.bind(op);
6140             }
6141 
6142             @Override
6143             public void dispose() {
6144                 super.unbind(op);
6145             }
6146 
6147             @Override
6148             protected E computeValue() {
6149                 try {
6150                     return op.get(index);
6151                 } catch (IndexOutOfBoundsException ex) {
6152                     Logging.getLogger().fine("Exception while evaluating binding", ex);
6153                 }
6154                 return null;
6155             }
6156 
6157             @Override
6158             public ObservableList<?> getDependencies() {
6159                 return FXCollections.singletonObservableList(op);
6160             }
6161         };
6162     }
6163 
6164     /**
6165      * Creates a new {@link javafx.beans.binding.ObjectBinding} that contains the element
6166      * of an {@link javafx.collections.ObservableList} at the specified position. The {@code ObjectBinding}
6167      * will contain {@code null} if the {@code index} is outside of the {@code ObservableList}.
6168      *
6169      * @param op the {@code ObservableList}
6170      * @param index the position in the {@code List}
6171      * @param <E> the type of the {@code List} elements
6172      * @return the new {@code ObjectBinding}
6173      * @throws NullPointerException if the {@code ObservableList} or {@code index} is {@code null}
6174      * @since JavaFX 2.1
6175      */
6176     public static <E> ObjectBinding<E> valueAt(final ObservableList<E> op, final ObservableIntegerValue index) {
6177         return valueAt(op, (ObservableNumberValue)index);
6178     }
6179 
6180     /**
6181      * Creates a new {@link javafx.beans.binding.ObjectBinding} that contains the element
6182      * of an {@link javafx.collections.ObservableList} at the specified position. The {@code ObjectBinding}
6183      * will contain {@code null} if the {@code index} is outside of the {@code ObservableList}.
6184      *
6185      * @param op the {@code ObservableList}
6186      * @param index the position in the {@code List}, converted to int
6187      * @param <E> the type of the {@code List} elements
6188      * @return the new {@code ObjectBinding}
6189      * @throws NullPointerException if the {@code ObservableList} or {@code index} is {@code null}
6190      * @since JavaFX 8.0
6191      */
6192     public static <E> ObjectBinding<E> valueAt(final ObservableList<E> op, final ObservableNumberValue index) {
6193         if ((op == null) || (index == null)) {
6194             throw new NullPointerException("Operands cannot be null.");
6195         }
6196 
6197         return new ObjectBinding<E>() {
6198             {
6199                 super.bind(op, index);
6200             }
6201 
6202             @Override
6203             public void dispose() {
6204                 super.unbind(op, index);
6205             }
6206 
6207             @Override
6208             protected E computeValue() {
6209                 try {
6210                     return op.get(index.intValue());
6211                 } catch (IndexOutOfBoundsException ex) {
6212                     Logging.getLogger().fine("Exception while evaluating binding", ex);
6213                 }
6214                 return null;
6215             }
6216 
6217             @Override
6218             public ObservableList<?> getDependencies() {
6219                 return new ImmutableObservableList<Observable>(op, index);
6220             }
6221         };
6222     }
6223 
6224     /**
6225      * Creates a new {@link javafx.beans.binding.BooleanBinding} that contains the element
6226      * of an {@link javafx.collections.ObservableList} at the specified position. The {@code BooleanBinding}
6227      * will hold {@code false} if the {@code index} points behind the {@code ObservableList}.
6228      *
6229      * @param op the {@code ObservableList}
6230      * @param index the position in the {@code List}
6231      * @return the new {@code BooleanBinding}
6232      * @throws NullPointerException if the {@code ObservableList} is {@code null}
6233      * @throws IllegalArgumentException if (@code index &lt; 0)
6234      * @since JavaFX 2.1
6235      */
6236     public static BooleanBinding booleanValueAt(final ObservableList<Boolean> op, final int index) {
6237         if (op == null) {
6238             throw new NullPointerException("List cannot be null.");
6239         }
6240         if (index < 0) {
6241             throw new IllegalArgumentException("Index cannot be negative");
6242         }
6243 
6244         return new BooleanBinding() {
6245             {
6246                 super.bind(op);
6247             }
6248 
6249             @Override
6250             public void dispose() {
6251                 super.unbind(op);
6252             }
6253 
6254             @Override
6255             protected boolean computeValue() {
6256                 try {
6257                     final Boolean value = op.get(index);
6258                     if (value == null) {
6259                         Logging.getLogger().fine("List element is null, returning default value instead.", new NullPointerException());
6260                     } else {
6261                         return value;
6262                     }
6263                 } catch (IndexOutOfBoundsException ex) {
6264                     Logging.getLogger().fine("Exception while evaluating binding", ex);
6265                 }
6266                 return false;
6267             }
6268 
6269             @Override
6270             public ObservableList<?> getDependencies() {
6271                 return FXCollections.singletonObservableList(op);
6272             }
6273         };
6274     }
6275 
6276     /**
6277      * Creates a new {@link javafx.beans.binding.BooleanBinding} that contains the element
6278      * of an {@link javafx.collections.ObservableList} at the specified position. The {@code BooleanBinding}
6279      * will hold {@code false} if the {@code index} is outside of the {@code ObservableList}.
6280      *
6281      * @param op the {@code ObservableList}
6282      * @param index the position in the {@code List}
6283      * @return the new {@code BooleanBinding}
6284      * @throws NullPointerException if the {@code ObservableList} or {@code index} is {@code null}
6285      * @since JavaFX 2.1
6286      */
6287     public static BooleanBinding booleanValueAt(final ObservableList<Boolean> op, final ObservableIntegerValue index) {
6288         return booleanValueAt(op, (ObservableNumberValue)index);
6289     }
6290 
6291     /**
6292      * Creates a new {@link javafx.beans.binding.BooleanBinding} that contains the element
6293      * of an {@link javafx.collections.ObservableList} at the specified position. The {@code BooleanBinding}
6294      * will hold {@code false} if the {@code index} is outside of the {@code ObservableList}.
6295      *
6296      * @param op the {@code ObservableList}
6297      * @param index the position in the {@code List}, converted to int
6298      * @return the new {@code BooleanBinding}
6299      * @throws NullPointerException if the {@code ObservableList} or {@code index} is {@code null}
6300      * @since JavaFX 8.0
6301      */
6302     public static BooleanBinding booleanValueAt(final ObservableList<Boolean> op, final ObservableNumberValue index) {
6303         if ((op == null) || (index == null)) {
6304             throw new NullPointerException("Operands cannot be null.");
6305         }
6306 
6307         return new BooleanBinding() {
6308             {
6309                 super.bind(op, index);
6310             }
6311 
6312             @Override
6313             public void dispose() {
6314                 super.unbind(op, index);
6315             }
6316 
6317             @Override
6318             protected boolean computeValue() {
6319                 try {
6320                     final Boolean value = op.get(index.intValue());
6321                     if (value == null) {
6322                         Logging.getLogger().fine("List element is null, returning default value instead.", new NullPointerException());
6323                     } else {
6324                         return value;
6325                     }
6326                 } catch (IndexOutOfBoundsException ex) {
6327                     Logging.getLogger().fine("Exception while evaluating binding", ex);
6328                 }
6329                 return false;
6330             }
6331 
6332             @Override
6333             public ObservableList<?> getDependencies() {
6334                 return new ImmutableObservableList<Observable>(op, index);
6335             }
6336         };
6337     }
6338 
6339     /**
6340      * Creates a new {@link javafx.beans.binding.DoubleBinding} that contains the element
6341      * of an {@link javafx.collections.ObservableList} at the specified position. The {@code DoubleBinding}
6342      * will hold {@code 0.0} if the {@code index} points behind the {@code ObservableList}.
6343      *
6344      * @param op the {@code ObservableList}
6345      * @param index the position in the {@code List}
6346      * @return the new {@code DoubleBinding}
6347      * @throws NullPointerException if the {@code ObservableList} is {@code null}
6348      * @throws IllegalArgumentException if (@code index &lt; 0)
6349      * @since JavaFX 2.1
6350      */
6351     public static DoubleBinding doubleValueAt(final ObservableList<? extends Number> op, final int index) {
6352         if (op == null) {
6353             throw new NullPointerException("List cannot be null.");
6354         }
6355         if (index < 0) {
6356             throw new IllegalArgumentException("Index cannot be negative");
6357         }
6358 
6359         return new DoubleBinding() {
6360             {
6361                 super.bind(op);
6362             }
6363 
6364             @Override
6365             public void dispose() {
6366                 super.unbind(op);
6367             }
6368 
6369             @Override
6370             protected double computeValue() {
6371                 try {
6372                     final Number value = op.get(index);
6373                     if (value == null) {
6374                         Logging.getLogger().fine("List element is null, returning default value instead.", new NullPointerException());
6375                     } else {
6376                         return value.doubleValue();
6377                     }
6378                 } catch (IndexOutOfBoundsException ex) {
6379                     Logging.getLogger().fine("Exception while evaluating binding", ex);
6380                 }
6381                 return 0.0;
6382             }
6383 
6384             @Override
6385             public ObservableList<?> getDependencies() {
6386                 return FXCollections.singletonObservableList(op);
6387             }
6388         };
6389     }
6390 
6391     /**
6392      * Creates a new {@link javafx.beans.binding.DoubleBinding} that contains the element
6393      * of an {@link javafx.collections.ObservableList} at the specified position. The {@code DoubleBinding}
6394      * will hold {@code 0.0} if the {@code index} is outside of the {@code ObservableList}.
6395      *
6396      * @param op the {@code ObservableList}
6397      * @param index the position in the {@code List}
6398      * @return the new {@code DoubleBinding}
6399      * @throws NullPointerException if the {@code ObservableList} or {@code index} is {@code null}
6400      * @since JavaFX 2.1
6401      */
6402     public static DoubleBinding doubleValueAt(final ObservableList<? extends Number> op, final ObservableIntegerValue index) {
6403         return doubleValueAt(op, (ObservableNumberValue)index);
6404     }
6405 
6406     /**
6407      * Creates a new {@link javafx.beans.binding.DoubleBinding} that contains the element
6408      * of an {@link javafx.collections.ObservableList} at the specified position. The {@code DoubleBinding}
6409      * will hold {@code 0.0} if the {@code index} is outside of the {@code ObservableList}.
6410      *
6411      * @param op the {@code ObservableList}
6412      * @param index the position in the {@code List}, converted to int
6413      * @return the new {@code DoubleBinding}
6414      * @throws NullPointerException if the {@code ObservableList} or {@code index} is {@code null}
6415      * @since JavaFX 8.0
6416      */
6417     public static DoubleBinding doubleValueAt(final ObservableList<? extends Number> op, final ObservableNumberValue index) {
6418         if ((op == null) || (index == null)) {
6419             throw new NullPointerException("Operands cannot be null.");
6420         }
6421 
6422         return new DoubleBinding() {
6423             {
6424                 super.bind(op, index);
6425             }
6426 
6427             @Override
6428             public void dispose() {
6429                 super.unbind(op, index);
6430             }
6431 
6432             @Override
6433             protected double computeValue() {
6434                 try {
6435                     final Number value = op.get(index.intValue());
6436                     if (value == null) {
6437                         Logging.getLogger().fine("List element is null, returning default value instead.", new NullPointerException());
6438                     } else {
6439                         return value.doubleValue();
6440                     }
6441                 } catch (IndexOutOfBoundsException ex) {
6442                     Logging.getLogger().fine("Exception while evaluating binding", ex);
6443                 }
6444                 return 0.0;
6445             }
6446 
6447             @Override
6448             public ObservableList<?> getDependencies() {
6449                 return new ImmutableObservableList<Observable>(op, index);
6450             }
6451         };
6452     }
6453 
6454     /**
6455      * Creates a new {@link javafx.beans.binding.FloatBinding} that contains the element
6456      * of an {@link javafx.collections.ObservableList} at the specified position. The {@code FloatBinding}
6457      * will hold {@code 0.0f} if the {@code index} points behind the {@code ObservableList}.
6458      *
6459      * @param op the {@code ObservableList}
6460      * @param index the position in the {@code List}
6461      * @return the new {@code FloatBinding}
6462      * @throws NullPointerException if the {@code ObservableList} is {@code null}
6463      * @throws IllegalArgumentException if (@code index &lt; 0)
6464      * @since JavaFX 2.1
6465      */
6466     public static FloatBinding floatValueAt(final ObservableList<? extends Number> op, final int index) {
6467         if (op == null) {
6468             throw new NullPointerException("List cannot be null.");
6469         }
6470         if (index < 0) {
6471             throw new IllegalArgumentException("Index cannot be negative");
6472         }
6473 
6474         return new FloatBinding() {
6475             {
6476                 super.bind(op);
6477             }
6478 
6479             @Override
6480             public void dispose() {
6481                 super.unbind(op);
6482             }
6483 
6484             @Override
6485             protected float computeValue() {
6486                 try {
6487                     final Number value = op.get(index);
6488                     if (value == null) {
6489                         Logging.getLogger().fine("List element is null, returning default value instead.", new NullPointerException());
6490                     } else {
6491                         return value.floatValue();
6492                     }
6493                 } catch (IndexOutOfBoundsException ex) {
6494                     Logging.getLogger().fine("Exception while evaluating binding", ex);
6495                 }
6496                 return 0.0f;
6497             }
6498 
6499             @Override
6500             public ObservableList<?> getDependencies() {
6501                 return FXCollections.singletonObservableList(op);
6502             }
6503         };
6504     }
6505 
6506     /**
6507      * Creates a new {@link javafx.beans.binding.FloatBinding} that contains the element
6508      * of an {@link javafx.collections.ObservableList} at the specified position. The {@code FloatBinding}
6509      * will hold {@code 0.0f} if the {@code index} is outside of the {@code ObservableList}.
6510      *
6511      * @param op the {@code ObservableList}
6512      * @param index the position in the {@code List}
6513      * @return the new {@code FloatBinding}
6514      * @throws NullPointerException if the {@code ObservableList} or {@code index} is {@code null}
6515      * @since JavaFX 2.1
6516      */
6517     public static FloatBinding floatValueAt(final ObservableList<? extends Number> op, final ObservableIntegerValue index) {
6518         return floatValueAt(op, (ObservableNumberValue)index);
6519     }
6520 
6521     /**
6522      * Creates a new {@link javafx.beans.binding.FloatBinding} that contains the element
6523      * of an {@link javafx.collections.ObservableList} at the specified position. The {@code FloatBinding}
6524      * will hold {@code 0.0f} if the {@code index} is outside of the {@code ObservableList}.
6525      *
6526      * @param op the {@code ObservableList}
6527      * @param index the position in the {@code List}, converted to int
6528      * @return the new {@code FloatBinding}
6529      * @throws NullPointerException if the {@code ObservableList} or {@code index} is {@code null}
6530      * @since JavaFX 8.0
6531      */
6532     public static FloatBinding floatValueAt(final ObservableList<? extends Number> op, final ObservableNumberValue index) {
6533         if ((op == null) || (index == null)) {
6534             throw new NullPointerException("Operands cannot be null.");
6535         }
6536 
6537         return new FloatBinding() {
6538             {
6539                 super.bind(op, index);
6540             }
6541 
6542             @Override
6543             public void dispose() {
6544                 super.unbind(op, index);
6545             }
6546 
6547             @Override
6548             protected float computeValue() {
6549                 try {
6550                     final Number value = op.get(index.intValue());
6551                     if (value == null) {
6552                         Logging.getLogger().fine("List element is null, returning default value instead.", new NullPointerException());
6553                     } else {
6554                         return value.floatValue();
6555                     }
6556                 } catch (IndexOutOfBoundsException ex) {
6557                     Logging.getLogger().fine("Exception while evaluating binding", ex);
6558                 }
6559                 return 0.0f;
6560             }
6561 
6562             @Override
6563             public ObservableList<?> getDependencies() {
6564                 return new ImmutableObservableList<Observable>(op, index);
6565             }
6566         };
6567     }
6568 
6569     /**
6570      * Creates a new {@link javafx.beans.binding.IntegerBinding} that contains the element
6571      * of an {@link javafx.collections.ObservableList} at the specified position. The {@code IntegerBinding}
6572      * will hold {@code 0} if the {@code index} points behind the {@code ObservableList}.
6573      *
6574      * @param op the {@code ObservableList}
6575      * @param index the position in the {@code List}
6576      * @return the new {@code IntegerBinding}
6577      * @throws NullPointerException if the {@code ObservableList} is {@code null}
6578      * @throws IllegalArgumentException if (@code index &lt; 0)
6579      * @since JavaFX 2.1
6580      */
6581     public static IntegerBinding integerValueAt(final ObservableList<? extends Number> op, final int index) {
6582         if (op == null) {
6583             throw new NullPointerException("List cannot be null.");
6584         }
6585         if (index < 0) {
6586             throw new IllegalArgumentException("Index cannot be negative");
6587         }
6588 
6589         return new IntegerBinding() {
6590             {
6591                 super.bind(op);
6592             }
6593 
6594             @Override
6595             public void dispose() {
6596                 super.unbind(op);
6597             }
6598 
6599             @Override
6600             protected int computeValue() {
6601                 try {
6602                     final Number value = op.get(index);
6603                     if (value == null) {
6604                         Logging.getLogger().fine("List element is null, returning default value instead.", new NullPointerException());
6605                     } else {
6606                         return value.intValue();
6607                     }
6608                 } catch (IndexOutOfBoundsException ex) {
6609                     Logging.getLogger().fine("Exception while evaluating binding", ex);
6610                 }
6611                 return 0;
6612             }
6613 
6614             @Override
6615             public ObservableList<?> getDependencies() {
6616                 return FXCollections.singletonObservableList(op);
6617             }
6618         };
6619     }
6620 
6621     /**
6622      * Creates a new {@link javafx.beans.binding.IntegerBinding} that contains the element
6623      * of an {@link javafx.collections.ObservableList} at the specified position. The {@code IntegerBinding}
6624      * will hold {@code 0} if the {@code index} is outside of the {@code ObservableList}.
6625      *
6626      * @param op the {@code ObservableList}
6627      * @param index the position in the {@code List}
6628      * @return the new {@code IntegerBinding}
6629      * @throws NullPointerException if the {@code ObservableList} or {@code index} is {@code null}
6630      * @since JavaFX 2.1
6631      */
6632     public static IntegerBinding integerValueAt(final ObservableList<? extends Number> op, final ObservableIntegerValue index) {
6633         return integerValueAt(op, (ObservableNumberValue)index);
6634     }
6635 
6636     /**
6637      * Creates a new {@link javafx.beans.binding.IntegerBinding} that contains the element
6638      * of an {@link javafx.collections.ObservableList} at the specified position. The {@code IntegerBinding}
6639      * will hold {@code 0} if the {@code index} is outside of the {@code ObservableList}.
6640      *
6641      * @param op the {@code ObservableList}
6642      * @param index the position in the {@code List}, converted to int
6643      * @return the new {@code IntegerBinding}
6644      * @throws NullPointerException if the {@code ObservableList} or {@code index} is {@code null}
6645      * @since JavaFX 8.0
6646      */
6647     public static IntegerBinding integerValueAt(final ObservableList<? extends Number> op, final ObservableNumberValue index) {
6648         if ((op == null) || (index == null)) {
6649             throw new NullPointerException("Operands cannot be null.");
6650         }
6651 
6652         return new IntegerBinding() {
6653             {
6654                 super.bind(op, index);
6655             }
6656 
6657             @Override
6658             public void dispose() {
6659                 super.unbind(op, index);
6660             }
6661 
6662             @Override
6663             protected int computeValue() {
6664                 try {
6665                     final Number value = op.get(index.intValue());
6666                     if (value == null) {
6667                         Logging.getLogger().fine("List element is null, returning default value instead.", new NullPointerException());
6668                     } else {
6669                         return value.intValue();
6670                     }
6671                 } catch (IndexOutOfBoundsException ex) {
6672                     Logging.getLogger().fine("Exception while evaluating binding", ex);
6673                 }
6674                 return 0;
6675             }
6676 
6677             @Override
6678             public ObservableList<?> getDependencies() {
6679                 return new ImmutableObservableList<Observable>(op, index);
6680             }
6681         };
6682     }
6683 
6684     /**
6685      * Creates a new {@link javafx.beans.binding.LongBinding} that contains the element
6686      * of an {@link javafx.collections.ObservableList} at the specified position. The {@code LongBinding}
6687      * will hold {@code 0L} if the {@code index} points behind the {@code ObservableList}.
6688      *
6689      * @param op the {@code ObservableList}
6690      * @param index the position in the {@code List}
6691      * @return the new {@code LongBinding}
6692      * @throws NullPointerException if the {@code ObservableList} is {@code null}
6693      * @throws IllegalArgumentException if (@code index &lt; 0)
6694      * @since JavaFX 2.1
6695      */
6696     public static LongBinding longValueAt(final ObservableList<? extends Number> op, final int index) {
6697         if (op == null) {
6698             throw new NullPointerException("List cannot be null.");
6699         }
6700         if (index < 0) {
6701             throw new IllegalArgumentException("Index cannot be negative");
6702         }
6703 
6704         return new LongBinding() {
6705             {
6706                 super.bind(op);
6707             }
6708 
6709             @Override
6710             public void dispose() {
6711                 super.unbind(op);
6712             }
6713 
6714             @Override
6715             protected long computeValue() {
6716                 try {
6717                     final Number value = op.get(index);
6718                     if (value == null) {
6719                         Logging.getLogger().fine("List element is null, returning default value instead.", new NullPointerException());
6720                     } else {
6721                         return value.longValue();
6722                     }
6723                 } catch (IndexOutOfBoundsException ex) {
6724                     Logging.getLogger().fine("Exception while evaluating binding", ex);
6725                 }
6726                 return 0L;
6727             }
6728 
6729             @Override
6730             public ObservableList<?> getDependencies() {
6731                 return FXCollections.singletonObservableList(op);
6732             }
6733         };
6734     }
6735 
6736     /**
6737      * Creates a new {@link javafx.beans.binding.LongBinding} that contains the element
6738      * of an {@link javafx.collections.ObservableList} at the specified position. The {@code LongBinding}
6739      * will hold {@code 0L} if the {@code index} is outside of the {@code ObservableList}.
6740      *
6741      * @param op the {@code ObservableList}
6742      * @param index the position in the {@code List}
6743      * @return the new {@code LongBinding}
6744      * @throws NullPointerException if the {@code ObservableList} or {@code index} is {@code null}
6745      * @since JavaFX 2.1
6746      */
6747     public static LongBinding longValueAt(final ObservableList<? extends Number> op, final ObservableIntegerValue index) {
6748         return longValueAt(op, (ObservableNumberValue)index);
6749     }
6750 
6751     /**
6752      * Creates a new {@link javafx.beans.binding.LongBinding} that contains the element
6753      * of an {@link javafx.collections.ObservableList} at the specified position. The {@code LongBinding}
6754      * will hold {@code 0L} if the {@code index} is outside of the {@code ObservableList}.
6755      *
6756      * @param op the {@code ObservableList}
6757      * @param index the position in the {@code List}, converted to int
6758      * @return the new {@code LongBinding}
6759      * @throws NullPointerException if the {@code ObservableList} or {@code index} is {@code null}
6760      * @since JavaFX 8.0
6761      */
6762     public static LongBinding longValueAt(final ObservableList<? extends Number> op, final ObservableNumberValue index) {
6763         if ((op == null) || (index == null)) {
6764             throw new NullPointerException("Operands cannot be null.");
6765         }
6766 
6767         return new LongBinding() {
6768             {
6769                 super.bind(op, index);
6770             }
6771 
6772             @Override
6773             public void dispose() {
6774                 super.unbind(op, index);
6775             }
6776 
6777             @Override
6778             protected long computeValue() {
6779                 try {
6780                     final Number value = op.get(index.intValue());
6781                     if (value == null) {
6782                         Logging.getLogger().fine("List element is null, returning default value instead.", new NullPointerException());
6783                     } else {
6784                         return value.longValue();
6785                     }
6786                 } catch (IndexOutOfBoundsException ex) {
6787                     Logging.getLogger().fine("Exception while evaluating binding", ex);
6788                 }
6789                 return 0L;
6790             }
6791 
6792             @Override
6793             public ObservableList<?> getDependencies() {
6794                 return new ImmutableObservableList<Observable>(op, index);
6795             }
6796         };
6797     }
6798 
6799     /**
6800      * Creates a new {@link javafx.beans.binding.StringBinding} that contains the element
6801      * of an {@link javafx.collections.ObservableList} at the specified position. The {@code StringBinding}
6802      * will hold {@code null} if the {@code index} points behind the {@code ObservableList}.
6803      *
6804      * @param op the {@code ObservableList}
6805      * @param index the position in the {@code List}
6806      * @return the new {@code StringBinding}
6807      * @throws NullPointerException if the {@code ObservableList} is {@code null}
6808      * @throws IllegalArgumentException if (@code index &lt; 0)
6809      * @since JavaFX 2.1
6810      */
6811     public static StringBinding stringValueAt(final ObservableList<String> op, final int index) {
6812         if (op == null) {
6813             throw new NullPointerException("List cannot be null.");
6814         }
6815         if (index < 0) {
6816             throw new IllegalArgumentException("Index cannot be negative");
6817         }
6818 
6819         return new StringBinding() {
6820             {
6821                 super.bind(op);
6822             }
6823 
6824             @Override
6825             public void dispose() {
6826                 super.unbind(op);
6827             }
6828 
6829             @Override
6830             protected String computeValue() {
6831                 try {
6832                     return op.get(index);
6833                 } catch (IndexOutOfBoundsException ex) {
6834                     Logging.getLogger().fine("Exception while evaluating binding", ex);
6835                 }
6836                 return null;
6837             }
6838 
6839             @Override
6840             public ObservableList<?> getDependencies() {
6841                 return FXCollections.singletonObservableList(op);
6842             }
6843         };
6844     }
6845 
6846     /**
6847      * Creates a new {@link javafx.beans.binding.StringBinding} that contains the element
6848      * of an {@link javafx.collections.ObservableList} at the specified position. The {@code StringBinding}
6849      * will hold {@code ""} if the {@code index} is outside of the {@code ObservableList}.
6850      *
6851      * @param op the {@code ObservableList}
6852      * @param index the position in the {@code List}
6853      * @return the new {@code StringBinding}
6854      * @throws NullPointerException if the {@code ObservableList} or {@code index} is {@code null}
6855      * @since JavaFX 2.1
6856      */
6857     public static StringBinding stringValueAt(final ObservableList<String> op, final ObservableIntegerValue index) {
6858         return stringValueAt(op, (ObservableNumberValue)index);
6859     }
6860 
6861     /**
6862      * Creates a new {@link javafx.beans.binding.StringBinding} that contains the element
6863      * of an {@link javafx.collections.ObservableList} at the specified position. The {@code StringBinding}
6864      * will hold {@code ""} if the {@code index} is outside of the {@code ObservableList}.
6865      *
6866      * @param op the {@code ObservableList}
6867      * @param index the position in the {@code List}, converted to int
6868      * @return the new {@code StringBinding}
6869      * @throws NullPointerException if the {@code ObservableList} or {@code index} is {@code null}
6870      * @since JavaFX 8.0
6871      */
6872     public static StringBinding stringValueAt(final ObservableList<String> op, final ObservableNumberValue index) {
6873         if ((op == null) || (index == null)) {
6874             throw new NullPointerException("Operands cannot be null.");
6875         }
6876 
6877         return new StringBinding() {
6878             {
6879                 super.bind(op, index);
6880             }
6881 
6882             @Override
6883             public void dispose() {
6884                 super.unbind(op, index);
6885             }
6886 
6887             @Override
6888             protected String computeValue() {
6889                 try {
6890                     return op.get(index.intValue());
6891                 } catch (IndexOutOfBoundsException ex) {
6892                     Logging.getLogger().fine("Exception while evaluating binding", ex);
6893                 }
6894                 return null;
6895             }
6896 
6897             @Override
6898             public ObservableList<?> getDependencies() {
6899                 return new ImmutableObservableList<Observable>(op, index);
6900             }
6901         };
6902     }
6903 
6904     // Set
6905     // =================================================================================================================
6906 
6907     /**
6908      * Creates a new {@link javafx.beans.binding.IntegerBinding} that contains the size
6909      * of an {@link javafx.collections.ObservableSet}.
6910      *
6911      * @param op
6912      *            the {@code ObservableSet}
6913      * @param <E> the type of the {@code Set} elements
6914      * @return the new {@code IntegerBinding}
6915      * @throws NullPointerException
6916      *             if the {@code ObservableSet} is {@code null}
6917      * @since JavaFX 2.1
6918      */
6919     public static <E> IntegerBinding size(final ObservableSet<E> op) {
6920         if (op == null) {
6921             throw new NullPointerException("Set cannot be null.");
6922         }
6923 
6924         return new IntegerBinding() {
6925             {
6926                 super.bind(op);
6927             }
6928 
6929             @Override
6930             public void dispose() {
6931                 super.unbind(op);
6932             }
6933 
6934             @Override
6935             protected int computeValue() {
6936                 return op.size();
6937             }
6938 
6939             @Override
6940             public ObservableList<?> getDependencies() {
6941                 return FXCollections.singletonObservableList(op);
6942             }
6943         };
6944     }
6945 
6946     /**
6947      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
6948      * if a given {@link javafx.collections.ObservableSet} is empty.
6949      *
6950      * @param op
6951      *            the {@code ObservableSet}
6952      * @param <E> the type of the {@code Set} elements
6953      * @return the new {@code BooleanBinding}
6954      * @throws NullPointerException
6955      *             if the {@code ObservableSet} is {@code null}
6956      * @since JavaFX 2.1
6957      */
6958     public static <E> BooleanBinding isEmpty(final ObservableSet<E> op) {
6959         if (op == null) {
6960             throw new NullPointerException("Set cannot be null.");
6961         }
6962 
6963         return new BooleanBinding() {
6964             {
6965                 super.bind(op);
6966             }
6967 
6968             @Override
6969             public void dispose() {
6970                 super.unbind(op);
6971             }
6972 
6973             @Override
6974             protected boolean computeValue() {
6975                 return op.isEmpty();
6976             }
6977 
6978             @Override
6979             public ObservableList<?> getDependencies() {
6980                 return FXCollections.singletonObservableList(op);
6981             }
6982         };
6983     }
6984 
6985     /**
6986      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
6987      * if a given {@link javafx.collections.ObservableSet} is not empty.
6988      *
6989      * @param op
6990      *            the {@code ObservableSet}
6991      * @param <E> the type of the {@code Set} elements
6992      * @return the new {@code BooleanBinding}
6993      * @throws NullPointerException
6994      *             if the {@code ObservableSet} is {@code null}
6995      * @since JavaFX 8.0
6996      */
6997     public static <E> BooleanBinding isNotEmpty(final ObservableSet<E> op)     {
6998         if (op == null) {
6999             throw new NullPointerException("List cannot be null.");
7000         }
7001 
7002         return new BooleanBinding() {
7003             {
7004                 super.bind(op);
7005             }
7006 
7007             @Override
7008             public void dispose() {
7009                 super.unbind(op);
7010             }
7011 
7012             @Override
7013             protected boolean computeValue() {
7014                 return !op.isEmpty();
7015             }
7016 
7017             @Override
7018             public ObservableList<?> getDependencies() {
7019                 return FXCollections.singletonObservableList(op);
7020             }
7021         };
7022     }
7023 
7024     // Array
7025     // =================================================================================================================
7026 
7027     /**
7028      * Creates a new {@link javafx.beans.binding.IntegerBinding} that contains the size
7029      * of an {@link javafx.collections.ObservableArray}.
7030      *
7031      * @param op the {@code ObservableArray}
7032      * @return the new {@code IntegerBinding}
7033      * @throws NullPointerException
7034      *             if the {@code ObservableArray} is {@code null}
7035      * @since JavaFX 8.0
7036      */
7037     public static IntegerBinding size(final ObservableArray op) {
7038         if (op == null) {
7039             throw new NullPointerException("Array cannot be null.");
7040         }
7041 
7042         return new IntegerBinding() {
7043             {
7044                 super.bind(op);
7045             }
7046 
7047             @Override
7048             public void dispose() {
7049                 super.unbind(op);
7050             }
7051 
7052             @Override
7053             protected int computeValue() {
7054                 return op.size();
7055             }
7056 
7057             @Override
7058             public ObservableList<?> getDependencies() {
7059                 return FXCollections.singletonObservableList(op);
7060             }
7061         };
7062     }
7063 
7064     /**
7065      * Creates a new {@link javafx.beans.binding.FloatBinding} that contains the element
7066      * of an {@link javafx.collections.ObservableArray} at the specified position. The {@code FloatBinding}
7067      * will hold {@code 0.0f} if the {@code index} points behind the {@code ObservableArray}.
7068      *
7069      * @param op the {@code ObservableArray}
7070      * @param index the position in the {@code ObservableArray}
7071      * @return the new {@code FloatBinding}
7072      * @throws NullPointerException if the {@code ObservableArray} is {@code null}
7073      * @throws IllegalArgumentException if (@code index &lt; 0)
7074      * @since JavaFX 8.0
7075      */
7076     public static FloatBinding floatValueAt(final ObservableFloatArray op, final int index) {
7077         if (op == null) {
7078             throw new NullPointerException("Array cannot be null.");
7079         }
7080         if (index < 0) {
7081             throw new IllegalArgumentException("Index cannot be negative");
7082         }
7083 
7084         return new FloatBinding() {
7085             {
7086                 super.bind(op);
7087             }
7088 
7089             @Override
7090             public void dispose() {
7091                 super.unbind(op);
7092             }
7093 
7094             @Override
7095             protected float computeValue() {
7096                 try {
7097                     return op.get(index);
7098                 } catch (IndexOutOfBoundsException ex) {
7099                     Logging.getLogger().fine("Exception while evaluating binding", ex);
7100                 }
7101                 return 0.0f;
7102             }
7103 
7104             @Override
7105             public ObservableList<?> getDependencies() {
7106                 return FXCollections.singletonObservableList(op);
7107             }
7108         };
7109     }
7110 
7111     /**
7112      * Creates a new {@link javafx.beans.binding.FloatBinding} that contains the element
7113      * of an {@link javafx.collections.ObservableArray} at the specified position. The {@code FloatBinding}
7114      * will hold {@code 0.0f} if the {@code index} is outside of the {@code ObservableArray}.
7115      *
7116      * @param op the {@code ObservableArray}
7117      * @param index the position in the {@code ObservableArray}
7118      * @return the new {@code FloatBinding}
7119      * @throws NullPointerException if the {@code ObservableArray} or {@code index} is {@code null}
7120      * @since JavaFX 8.0
7121      */
7122     public static FloatBinding floatValueAt(final ObservableFloatArray op, final ObservableIntegerValue index) {
7123         return floatValueAt(op, (ObservableNumberValue)index);
7124     }
7125 
7126     /**
7127      * Creates a new {@link javafx.beans.binding.FloatBinding} that contains the element
7128      * of an {@link javafx.collections.ObservableArray} at the specified position. The {@code FloatBinding}
7129      * will hold {@code 0.0f} if the {@code index} is outside of the {@code ObservableArray}.
7130      *
7131      * @param op the {@code ObservableArray}
7132      * @param index the position in the {@code ObservableArray}, converted to int
7133      * @return the new {@code FloatBinding}
7134      * @throws NullPointerException if the {@code ObservableArray} or {@code index} is {@code null}
7135      * @since JavaFX 8.0
7136      */
7137     public static FloatBinding floatValueAt(final ObservableFloatArray op, final ObservableNumberValue index) {
7138         if ((op == null) || (index == null)) {
7139             throw new NullPointerException("Operands cannot be null.");
7140         }
7141 
7142         return new FloatBinding() {
7143             {
7144                 super.bind(op, index);
7145             }
7146 
7147             @Override
7148             public void dispose() {
7149                 super.unbind(op, index);
7150             }
7151 
7152             @Override
7153             protected float computeValue() {
7154                 try {
7155                     return op.get(index.intValue());
7156                 } catch (IndexOutOfBoundsException ex) {
7157                     Logging.getLogger().fine("Exception while evaluating binding", ex);
7158                 }
7159                 return 0.0f;
7160             }
7161 
7162             @Override
7163             public ObservableList<?> getDependencies() {
7164                 return new ImmutableObservableList<>(op, index);
7165             }
7166         };
7167     }
7168 
7169     /**
7170      * Creates a new {@link javafx.beans.binding.IntegerBinding} that contains the element
7171      * of an {@link javafx.collections.ObservableArray} at the specified position. The {@code IntegerBinding}
7172      * will hold {@code 0} if the {@code index} points behind the {@code ObservableArray}.
7173      *
7174      * @param op the {@code ObservableArray}
7175      * @param index the position in the {@code ObservableArray}
7176      * @return the new {@code IntegerBinding}
7177      * @throws NullPointerException if the {@code ObservableArray} is {@code null}
7178      * @throws IllegalArgumentException if (@code index &lt; 0)
7179      * @since JavaFX 8.0
7180      */
7181     public static IntegerBinding integerValueAt(final ObservableIntegerArray op, final int index) {
7182         if (op == null) {
7183             throw new NullPointerException("Array cannot be null.");
7184         }
7185         if (index < 0) {
7186             throw new IllegalArgumentException("Index cannot be negative");
7187         }
7188 
7189         return new IntegerBinding() {
7190             {
7191                 super.bind(op);
7192             }
7193 
7194             @Override
7195             public void dispose() {
7196                 super.unbind(op);
7197             }
7198 
7199             @Override
7200             protected int computeValue() {
7201                 try {
7202                     return op.get(index);
7203                 } catch (IndexOutOfBoundsException ex) {
7204                     Logging.getLogger().fine("Exception while evaluating binding", ex);
7205                 }
7206                 return 0;
7207             }
7208 
7209             @Override
7210             public ObservableList<?> getDependencies() {
7211                 return FXCollections.singletonObservableList(op);
7212             }
7213         };
7214     }
7215 
7216     /**
7217      * Creates a new {@link javafx.beans.binding.IntegerBinding} that contains the element
7218      * of an {@link javafx.collections.ObservableArray} at the specified position. The {@code IntegerBinding}
7219      * will hold {@code 0} if the {@code index} is outside of the {@code ObservableArray}.
7220      *
7221      * @param op the {@code ObservableArray}
7222      * @param index the position in the {@code ObservableArray}
7223      * @return the new {@code IntegerBinding}
7224      * @throws NullPointerException if the {@code ObservableArray} or {@code index} is {@code null}
7225      * @since JavaFX 8.0
7226      */
7227     public static IntegerBinding integerValueAt(final ObservableIntegerArray op, final ObservableIntegerValue index) {
7228         return integerValueAt(op, (ObservableNumberValue)index);
7229     }
7230 
7231     /**
7232      * Creates a new {@link javafx.beans.binding.IntegerBinding} that contains the element
7233      * of an {@link javafx.collections.ObservableArray} at the specified position. The {@code IntegerBinding}
7234      * will hold {@code 0} if the {@code index} is outside of the {@code ObservableArray}.
7235      *
7236      * @param op the {@code ObservableArray}
7237      * @param index the position in the {@code ObservableArray}, converted to int
7238      * @return the new {@code IntegerBinding}
7239      * @throws NullPointerException if the {@code ObservableArray} or {@code index} is {@code null}
7240      * @since JavaFX 8.0
7241      */
7242     public static IntegerBinding integerValueAt(final ObservableIntegerArray op, final ObservableNumberValue index) {
7243         if ((op == null) || (index == null)) {
7244             throw new NullPointerException("Operands cannot be null.");
7245         }
7246 
7247         return new IntegerBinding() {
7248             {
7249                 super.bind(op, index);
7250             }
7251 
7252             @Override
7253             public void dispose() {
7254                 super.unbind(op, index);
7255             }
7256 
7257             @Override
7258             protected int computeValue() {
7259                 try {
7260                     return op.get(index.intValue());
7261                 } catch (IndexOutOfBoundsException ex) {
7262                     Logging.getLogger().fine("Exception while evaluating binding", ex);
7263                 }
7264                 return 0;
7265             }
7266 
7267             @Override
7268             public ObservableList<?> getDependencies() {
7269                 return new ImmutableObservableList<>(op, index);
7270             }
7271         };
7272     }
7273 
7274     // Map
7275     // =================================================================================================================
7276 
7277     /**
7278      * Creates a new {@link javafx.beans.binding.IntegerBinding} that contains the size
7279      * of an {@link javafx.collections.ObservableMap}.
7280      *
7281      * @param op
7282      *            the {@code ObservableMap}
7283      * @param <K> type of the key elements of the {@code Map}
7284      * @param <V> type of the value elements of the {@code Map}
7285      * @return the new {@code IntegerBinding}
7286      * @throws NullPointerException
7287      *             if the {@code ObservableMap} is {@code null}
7288      *
7289      * @since JavaFX 2.1
7290      */
7291     public static <K, V> IntegerBinding size(final ObservableMap<K, V> op) {
7292         if (op == null) {
7293             throw new NullPointerException("Map cannot be null.");
7294         }
7295 
7296         return new IntegerBinding() {
7297             {
7298                 super.bind(op);
7299             }
7300 
7301             @Override
7302             public void dispose() {
7303                 super.unbind(op);
7304             }
7305 
7306             @Override
7307             protected int computeValue() {
7308                 return op.size();
7309             }
7310 
7311             @Override
7312             public ObservableList<?> getDependencies() {
7313                 return FXCollections.singletonObservableList(op);
7314             }
7315         };
7316     }
7317 
7318     /**
7319      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
7320      * if a given {@link javafx.collections.ObservableMap} is empty.
7321      *
7322      * @param op
7323      *            the {@code ObservableMap}
7324      * @param <K> type of the key elements of the {@code Map}
7325      * @param <V> type of the value elements of the {@code Map}
7326      * @return the new {@code BooleanBinding}
7327      * @throws NullPointerException
7328      *             if the {@code ObservableMap} is {@code null}
7329      * @since JavaFX 2.1
7330      */
7331     public static <K, V> BooleanBinding isEmpty(final ObservableMap<K, V> op) {
7332         if (op == null) {
7333             throw new NullPointerException("Map cannot be null.");
7334         }
7335 
7336         return new BooleanBinding() {
7337             {
7338                 super.bind(op);
7339             }
7340 
7341             @Override
7342             public void dispose() {
7343                 super.unbind(op);
7344             }
7345 
7346             @Override
7347             protected boolean computeValue() {
7348                 return op.isEmpty();
7349             }
7350 
7351             @Override
7352             public ObservableList<?> getDependencies() {
7353                 return FXCollections.singletonObservableList(op);
7354             }
7355         };
7356     }
7357 
7358     /**
7359      * Creates a new {@link javafx.beans.binding.BooleanBinding} that holds {@code true}
7360      * if a given {@link javafx.collections.ObservableMap} is not empty.
7361      *
7362      * @param op
7363      *            the {@code ObservableMap}
7364      * @param <K> type of the key elements of the {@code Map}
7365      * @param <V> type of the value elements of the {@code Map}
7366      * @return the new {@code BooleanBinding}
7367      * @throws NullPointerException
7368      *             if the {@code ObservableMap} is {@code null}
7369      * @since JavaFX 8.0
7370      */
7371     public static <K, V> BooleanBinding isNotEmpty(final ObservableMap<K, V> op)     {
7372         if (op == null) {
7373             throw new NullPointerException("List cannot be null.");
7374         }
7375 
7376         return new BooleanBinding() {
7377             {
7378                 super.bind(op);
7379             }
7380 
7381             @Override
7382             public void dispose() {
7383                 super.unbind(op);
7384             }
7385 
7386             @Override
7387             protected boolean computeValue() {
7388                 return !op.isEmpty();
7389             }
7390 
7391             @Override
7392             public ObservableList<?> getDependencies() {
7393                 return FXCollections.singletonObservableList(op);
7394             }
7395         };
7396     }
7397 
7398     /**
7399      * Creates a new {@link javafx.beans.binding.ObjectBinding} that contains the mapping of a specific key
7400      * in an {@link javafx.collections.ObservableMap}.
7401      *
7402      * @param op the {@code ObservableMap}
7403      * @param key the key in the {@code Map}
7404      * @param <K> type of the key elements of the {@code Map}
7405      * @param <V> type of the value elements of the {@code Map}
7406      * @return the new {@code ObjectBinding}
7407      * @throws NullPointerException if the {@code ObservableMap} is {@code null}
7408      * @since JavaFX 2.1
7409      */
7410     public static <K, V> ObjectBinding<V> valueAt(final ObservableMap<K, V> op, final K key) {
7411         if (op == null) {
7412             throw new NullPointerException("Map cannot be null.");
7413         }
7414 
7415         return new ObjectBinding<V>() {
7416             {
7417                 super.bind(op);
7418             }
7419 
7420             @Override
7421             public void dispose() {
7422                 super.unbind(op);
7423             }
7424 
7425             @Override
7426             protected V computeValue() {
7427                 try {
7428                     return op.get(key);
7429                 } catch (ClassCastException ex) {
7430                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7431                     // ignore
7432                 } catch (NullPointerException ex) {
7433                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7434                     // ignore
7435                 }
7436                 return null;
7437             }
7438 
7439             @Override
7440             public ObservableList<?> getDependencies() {
7441                 return FXCollections.singletonObservableList(op);
7442             }
7443         };
7444     }
7445 
7446     /**
7447      * Creates a new {@link javafx.beans.binding.ObjectBinding} that contains the mapping of a specific key
7448      * in an {@link javafx.collections.ObservableMap}.
7449      *
7450      * @param op the {@code ObservableMap}
7451      * @param key the key in the {@code Map}
7452      * @param <K> type of the key elements of the {@code Map}
7453      * @param <V> type of the value elements of the {@code Map}
7454      * @return the new {@code ObjectBinding}
7455      * @throws NullPointerException if the {@code ObservableMap} or {@code key} is {@code null}
7456      * @since JavaFX 2.1
7457      */
7458     public static <K, V> ObjectBinding<V> valueAt(final ObservableMap<K, V> op, final ObservableValue<? extends K> key) {
7459         if ((op == null) || (key == null)) {
7460             throw new NullPointerException("Operands cannot be null.");
7461         }
7462 
7463         return new ObjectBinding<V>() {
7464             {
7465                 super.bind(op, key);
7466             }
7467 
7468             @Override
7469             public void dispose() {
7470                 super.unbind(op);
7471             }
7472 
7473             @Override
7474             protected V computeValue() {
7475                 try {
7476                     return op.get(key.getValue());
7477                 } catch (ClassCastException ex) {
7478                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7479                     // ignore
7480                 } catch (NullPointerException ex) {
7481                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7482                     // ignore
7483                 }
7484                 return null;
7485             }
7486 
7487             @Override
7488             public ObservableList<?> getDependencies() {
7489                 return new ImmutableObservableList<Observable>(op, key);
7490             }
7491         };
7492     }
7493 
7494     /**
7495      * Creates a new {@link javafx.beans.binding.BooleanBinding} that contains the mapping of a specific key
7496      * in an {@link javafx.collections.ObservableMap}. The {@code BooleanBinding}
7497      * will hold {@code false} if the {@code key} cannot be found in the {@code ObservableMap}.
7498      *
7499      * @param op the {@code ObservableMap}
7500      * @param key the key in the {@code Map}
7501      * @param <K> type of the key elements of the {@code Map}
7502      * @return the new {@code BooleanBinding}
7503      * @throws NullPointerException if the {@code ObservableMap} is {@code null}
7504      * @since JavaFX 2.1
7505      */
7506     public static <K> BooleanBinding booleanValueAt(final ObservableMap<K, Boolean> op, final K key) {
7507         if (op == null) {
7508             throw new NullPointerException("Map cannot be null.");
7509         }
7510 
7511         return new BooleanBinding() {
7512             {
7513                 super.bind(op);
7514             }
7515 
7516             @Override
7517             public void dispose() {
7518                 super.unbind(op);
7519             }
7520 
7521             @Override
7522             protected boolean computeValue() {
7523                 try {
7524                     final Boolean value = op.get(key);
7525                     if (value == null) {
7526                         Logging.getLogger().fine("Element not found in map, returning default value instead.", new NullPointerException());
7527                     } else {
7528                         return value;
7529                     }
7530                 } catch (ClassCastException ex) {
7531                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7532                     // ignore
7533                 } catch (NullPointerException ex) {
7534                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7535                     // ignore
7536                 }
7537                 return false;
7538             }
7539 
7540             @Override
7541             public ObservableList<?> getDependencies() {
7542                 return FXCollections.singletonObservableList(op);
7543             }
7544         };
7545     }
7546 
7547     /**
7548      * Creates a new {@link javafx.beans.binding.BooleanBinding} that contains the mapping of a specific key
7549      * in an {@link javafx.collections.ObservableMap}. The {@code BooleanBinding}
7550      * will hold {@code false} if the {@code key} cannot be found in the {@code ObservableMap}.
7551      *
7552      * @param op the {@code ObservableMap}
7553      * @param key the key in the {@code Map}
7554      * @param <K> type of the key elements of the {@code Map}
7555      * @return the new {@code BooleanBinding}
7556      * @throws NullPointerException if the {@code ObservableMap} or {@code key} is {@code null}
7557      * @since JavaFX 2.1
7558      */
7559     public static <K> BooleanBinding booleanValueAt(final ObservableMap<K, Boolean> op, final ObservableValue<? extends K> key) {
7560         if ((op == null) || (key == null)) {
7561             throw new NullPointerException("Operands cannot be null.");
7562         }
7563 
7564         return new BooleanBinding() {
7565             {
7566                 super.bind(op, key);
7567             }
7568 
7569             @Override
7570             public void dispose() {
7571                 super.unbind(op, key);
7572             }
7573 
7574             @Override
7575             protected boolean computeValue() {
7576                 try {
7577                     final Boolean value = op.get(key.getValue());
7578                     if (value == null) {
7579                         Logging.getLogger().fine("Element not found in map, returning default value instead.", new NullPointerException());
7580                     } else {
7581                         return value;
7582                     }
7583                 } catch (ClassCastException ex) {
7584                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7585                     // ignore
7586                 } catch (NullPointerException ex) {
7587                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7588                     // ignore
7589                 }
7590                 return false;
7591             }
7592 
7593             @Override
7594             public ObservableList<?> getDependencies() {
7595                 return new ImmutableObservableList<Observable>(op, key);
7596             }
7597         };
7598     }
7599 
7600     /**
7601      * Creates a new {@link javafx.beans.binding.DoubleBinding} that contains the mapping of a specific key
7602      * in an {@link javafx.collections.ObservableMap}. The {@code DoubleBinding}
7603      * will hold {@code 0.0} if the {@code key} cannot be found in the {@code ObservableMap}.
7604      *
7605      * @param op the {@code ObservableMap}
7606      * @param key the key in the {@code Map}
7607      * @param <K> type of the key elements of the {@code Map}
7608      * @return the new {@code DoubleBinding}
7609      * @throws NullPointerException if the {@code ObservableMap} is {@code null}
7610      * @since JavaFX 2.1
7611      */
7612     public static <K> DoubleBinding doubleValueAt(final ObservableMap<K, ? extends Number> op, final K key) {
7613         if (op == null) {
7614             throw new NullPointerException("Map cannot be null.");
7615         }
7616 
7617         return new DoubleBinding() {
7618             {
7619                 super.bind(op);
7620             }
7621 
7622             @Override
7623             public void dispose() {
7624                 super.unbind(op);
7625             }
7626 
7627             @Override
7628             protected double computeValue() {
7629                 try {
7630                     final Number value = op.get(key);
7631                     if (value == null) {
7632                         Logging.getLogger().fine("Element not found in map, returning default value instead.", new NullPointerException());
7633                     } else {
7634                         return value.doubleValue();
7635                     }
7636                 } catch (ClassCastException ex) {
7637                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7638                     // ignore
7639                 } catch (NullPointerException ex) {
7640                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7641                     // ignore
7642                 }
7643                 return 0.0;
7644             }
7645 
7646             @Override
7647             public ObservableList<?> getDependencies() {
7648                 return FXCollections.singletonObservableList(op);
7649             }
7650         };
7651     }
7652 
7653     /**
7654      * Creates a new {@link javafx.beans.binding.DoubleBinding} that contains the mapping of a specific key
7655      * in an {@link javafx.collections.ObservableMap}. The {@code DoubleBinding}
7656      * will hold {@code 0.0} if the {@code key} cannot be found in the {@code ObservableMap}.
7657      *
7658      * @param op the {@code ObservableMap}
7659      * @param key the key in the {@code Map}
7660      * @param <K> type of the key elements of the {@code Map}
7661      * @return the new {@code DoubleBinding}
7662      * @throws NullPointerException if the {@code ObservableMap} or {@code key} is {@code null}
7663      * @since JavaFX 2.1
7664      */
7665     public static <K> DoubleBinding doubleValueAt(final ObservableMap<K, ? extends Number> op, final ObservableValue<? extends K> key) {
7666         if ((op == null) || (key == null)) {
7667             throw new NullPointerException("Operands cannot be null.");
7668         }
7669 
7670         return new DoubleBinding() {
7671             {
7672                 super.bind(op, key);
7673             }
7674 
7675             @Override
7676             public void dispose() {
7677                 super.unbind(op, key);
7678             }
7679 
7680             @Override
7681             protected double computeValue() {
7682                 try {
7683                     final Number value = op.get(key.getValue());
7684                     if (value == null) {
7685                         Logging.getLogger().fine("Element not found in map, returning default value instead.", new NullPointerException());
7686                     } else {
7687                         return value.doubleValue();
7688                     }
7689                 } catch (ClassCastException ex) {
7690                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7691                     // ignore
7692                 } catch (NullPointerException ex) {
7693                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7694                     // ignore
7695                 }
7696                 return 0.0;
7697             }
7698 
7699             @Override
7700             public ObservableList<?> getDependencies() {
7701                 return new ImmutableObservableList<Observable>(op, key);
7702             }
7703         };
7704     }
7705 
7706     /**
7707      * Creates a new {@link javafx.beans.binding.FloatBinding} that contains the mapping of a specific key
7708      * in an {@link javafx.collections.ObservableMap}. The {@code FloatBinding}
7709      * will hold {@code 0.0f} if the {@code key} cannot be found in the {@code ObservableMap}.
7710      *
7711      * @param op the {@code ObservableMap}
7712      * @param key the key in the {@code Map}
7713      * @param <K> type of the key elements of the {@code Map}
7714      * @return the new {@code FloatBinding}
7715      * @throws NullPointerException if the {@code ObservableMap} is {@code null}
7716      * @since JavaFX 2.1
7717      */
7718     public static <K> FloatBinding floatValueAt(final ObservableMap<K, ? extends Number> op, final K key) {
7719         if (op == null) {
7720             throw new NullPointerException("Map cannot be null.");
7721         }
7722 
7723         return new FloatBinding() {
7724             {
7725                 super.bind(op);
7726             }
7727 
7728             @Override
7729             public void dispose() {
7730                 super.unbind(op);
7731             }
7732 
7733             @Override
7734             protected float computeValue() {
7735                 try {
7736                     final Number value = op.get(key);
7737                     if (value == null) {
7738                         Logging.getLogger().fine("Element not found in map, returning default value instead.", new NullPointerException());
7739                     } else {
7740                         return value.floatValue();
7741                     }
7742                 } catch (ClassCastException ex) {
7743                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7744                     // ignore
7745                 } catch (NullPointerException ex) {
7746                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7747                     // ignore
7748                 }
7749                 return 0.0f;
7750             }
7751 
7752             @Override
7753             public ObservableList<?> getDependencies() {
7754                 return FXCollections.singletonObservableList(op);
7755             }
7756         };
7757     }
7758 
7759     /**
7760      * Creates a new {@link javafx.beans.binding.FloatBinding} that contains the mapping of a specific key
7761      * in an {@link javafx.collections.ObservableMap}. The {@code FloatBinding}
7762      * will hold {@code 0.0f} if the {@code key} cannot be found in the {@code ObservableMap}.
7763      *
7764      * @param op the {@code ObservableMap}
7765      * @param key the key in the {@code Map}
7766      * @param <K> type of the key elements of the {@code Map}
7767      * @return the new {@code FloatBinding}
7768      * @throws NullPointerException if the {@code ObservableMap} or {@code key} is {@code null}
7769      * @since JavaFX 2.1
7770      */
7771     public static <K> FloatBinding floatValueAt(final ObservableMap<K, ? extends Number> op, final ObservableValue<? extends K> key) {
7772         if ((op == null) || (key == null)) {
7773             throw new NullPointerException("Operands cannot be null.");
7774         }
7775 
7776         return new FloatBinding() {
7777             {
7778                 super.bind(op, key);
7779             }
7780 
7781             @Override
7782             public void dispose() {
7783                 super.unbind(op, key);
7784             }
7785 
7786             @Override
7787             protected float computeValue() {
7788                 try {
7789                     final Number value = op.get(key.getValue());
7790                     if (value == null) {
7791                         Logging.getLogger().fine("Element not found in map, returning default value instead.", new NullPointerException());
7792                     } else {
7793                         return value.floatValue();
7794                     }
7795                 } catch (ClassCastException ex) {
7796                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7797                     // ignore
7798                 } catch (NullPointerException ex) {
7799                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7800                     // ignore
7801                 }
7802                 return 0.0f;
7803             }
7804 
7805             @Override
7806             public ObservableList<?> getDependencies() {
7807                 return new ImmutableObservableList<Observable>(op, key);
7808             }
7809         };
7810     }
7811 
7812     /**
7813      * Creates a new {@link javafx.beans.binding.IntegerBinding} that contains the mapping of a specific key
7814      * in an {@link javafx.collections.ObservableMap}. The {@code IntegerBinding}
7815      * will hold {@code 0} if the {@code key} cannot be found in the {@code ObservableMap}.
7816      *
7817      * @param op the {@code ObservableMap}
7818      * @param key the key in the {@code Map}
7819      * @param <K> type of the key elements of the {@code Map}
7820      * @return the new {@code IntegerBinding}
7821      * @throws NullPointerException if the {@code ObservableMap} is {@code null}
7822      * @since JavaFX 2.1
7823      */
7824     public static <K> IntegerBinding integerValueAt(final ObservableMap<K, ? extends Number> op, final K key) {
7825         if (op == null) {
7826             throw new NullPointerException("Map cannot be null.");
7827         }
7828 
7829         return new IntegerBinding() {
7830             {
7831                 super.bind(op);
7832             }
7833 
7834             @Override
7835             public void dispose() {
7836                 super.unbind(op);
7837             }
7838 
7839             @Override
7840             protected int computeValue() {
7841                 try {
7842                     final Number value = op.get(key);
7843                     if (value == null) {
7844                         Logging.getLogger().fine("Element not found in map, returning default value instead.", new NullPointerException());
7845                     } else {
7846                         return value.intValue();
7847                     }
7848                 } catch (ClassCastException ex) {
7849                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7850                     // ignore
7851                 } catch (NullPointerException ex) {
7852                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7853                     // ignore
7854                 }
7855                 return 0;
7856             }
7857 
7858             @Override
7859             public ObservableList<?> getDependencies() {
7860                 return FXCollections.singletonObservableList(op);
7861             }
7862         };
7863     }
7864 
7865     /**
7866      * Creates a new {@link javafx.beans.binding.IntegerBinding} that contains the mapping of a specific key
7867      * in an {@link javafx.collections.ObservableMap}. The {@code IntegerBinding}
7868      * will hold {@code 0} if the {@code key} cannot be found in the {@code ObservableMap}.
7869      *
7870      * @param op the {@code ObservableMap}
7871      * @param key the key in the {@code Map}
7872      * @param <K> type of the key elements of the {@code Map}
7873      * @return the new {@code IntegerBinding}
7874      * @throws NullPointerException if the {@code ObservableMap} or {@code key} is {@code null}
7875      * @since JavaFX 2.1
7876      */
7877     public static <K> IntegerBinding integerValueAt(final ObservableMap<K, ? extends Number> op, final ObservableValue<? extends K> key) {
7878         if ((op == null) || (key == null)) {
7879             throw new NullPointerException("Operands cannot be null.");
7880         }
7881 
7882         return new IntegerBinding() {
7883             {
7884                 super.bind(op, key);
7885             }
7886 
7887             @Override
7888             public void dispose() {
7889                 super.unbind(op, key);
7890             }
7891 
7892             @Override
7893             protected int computeValue() {
7894                 try {
7895                     final Number value = op.get(key.getValue());
7896                     if (value == null) {
7897                         Logging.getLogger().fine("Element not found in map, returning default value instead.", new NullPointerException());
7898                     } else {
7899                         return value.intValue();
7900                     }
7901                 } catch (ClassCastException ex) {
7902                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7903                     // ignore
7904                 } catch (NullPointerException ex) {
7905                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7906                     // ignore
7907                 }
7908                 return 0;
7909             }
7910 
7911             @Override
7912             public ObservableList<?> getDependencies() {
7913                 return new ImmutableObservableList<Observable>(op, key);
7914             }
7915         };
7916     }
7917 
7918     /**
7919      * Creates a new {@link javafx.beans.binding.LongBinding} that contains the mapping of a specific key
7920      * in an {@link javafx.collections.ObservableMap}. The {@code LongBinding}
7921      * will hold {@code 0L} if the {@code key} cannot be found in the {@code ObservableMap}.
7922      *
7923      * @param op the {@code ObservableMap}
7924      * @param key the key in the {@code Map}
7925      * @param <K> type of the key elements of the {@code Map}
7926      * @return the new {@code LongBinding}
7927      * @throws NullPointerException if the {@code ObservableMap} is {@code null}
7928      * @since JavaFX 2.1
7929      */
7930     public static <K> LongBinding longValueAt(final ObservableMap<K, ? extends Number> op, final K key) {
7931         if (op == null) {
7932             throw new NullPointerException("Map cannot be null.");
7933         }
7934 
7935         return new LongBinding() {
7936             {
7937                 super.bind(op);
7938             }
7939 
7940             @Override
7941             public void dispose() {
7942                 super.unbind(op);
7943             }
7944 
7945             @Override
7946             protected long computeValue() {
7947                 try {
7948                     final Number value = op.get(key);
7949                     if (value == null) {
7950                         Logging.getLogger().fine("Element not found in map, returning default value instead.", new NullPointerException());
7951                     } else {
7952                         return value.longValue();
7953                     }
7954                 } catch (ClassCastException ex) {
7955                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7956                     // ignore
7957                 } catch (NullPointerException ex) {
7958                     Logging.getLogger().warning("Exception while evaluating binding", ex);
7959                     // ignore
7960                 }
7961                 return 0L;
7962             }
7963 
7964             @Override
7965             public ObservableList<?> getDependencies() {
7966                 return FXCollections.singletonObservableList(op);
7967             }
7968         };
7969     }
7970 
7971     /**
7972      * Creates a new {@link javafx.beans.binding.LongBinding} that contains the mapping of a specific key
7973      * in an {@link javafx.collections.ObservableMap}. The {@code LongBinding}
7974      * will hold {@code 0L} if the {@code key} cannot be found in the {@code ObservableMap}.
7975      *
7976      * @param op the {@code ObservableMap}
7977      * @param key the key in the {@code Map}
7978      * @param <K> type of the key elements of the {@code Map}
7979      * @return the new {@code LongBinding}
7980      * @throws NullPointerException if the {@code ObservableMap} or {@code key} is {@code null}
7981      * @since JavaFX 2.1
7982      */
7983     public static <K> LongBinding longValueAt(final ObservableMap<K, ? extends Number> op, final ObservableValue<? extends K> key) {
7984         if ((op == null) || (key == null)) {
7985             throw new NullPointerException("Operands cannot be null.");
7986         }
7987 
7988         return new LongBinding() {
7989             {
7990                 super.bind(op, key);
7991             }
7992 
7993             @Override
7994             public void dispose() {
7995                 super.unbind(op, key);
7996             }
7997 
7998             @Override
7999             protected long computeValue() {
8000                 try {
8001                     final Number value = op.get(key.getValue());
8002                     if (value == null) {
8003                         Logging.getLogger().fine("Element not found in map, returning default value instead.", new NullPointerException());
8004                     } else {
8005                         return value.longValue();
8006                     }
8007                 } catch (ClassCastException ex) {
8008                     Logging.getLogger().warning("Exception while evaluating binding", ex);
8009                     // ignore
8010                 } catch (NullPointerException ex) {
8011                     Logging.getLogger().warning("Exception while evaluating binding", ex);
8012                     // ignore
8013                 }
8014                 return 0L;
8015             }
8016 
8017             @Override
8018             public ObservableList<?> getDependencies() {
8019                 return new ImmutableObservableList<Observable>(op, key);
8020             }
8021         };
8022     }
8023 
8024     /**
8025      * Creates a new {@link javafx.beans.binding.StringBinding} that contains the mapping of a specific key
8026      * in an {@link javafx.collections.ObservableMap}. The {@code StringBinding}
8027      * will hold {@code null} if the {@code key} cannot be found in the {@code ObservableMap}.
8028      *
8029      * @param op the {@code ObservableMap}
8030      * @param key the key in the {@code Map}
8031      * @param <K> type of the key elements of the {@code Map}
8032      * @return the new {@code StringBinding}
8033      * @throws NullPointerException if the {@code ObservableMap} is {@code null}
8034      * @since JavaFX 2.1
8035      */
8036     public static <K> StringBinding stringValueAt(final ObservableMap<K, String> op, final K key) {
8037         if (op == null) {
8038             throw new NullPointerException("Map cannot be null.");
8039         }
8040 
8041         return new StringBinding() {
8042             {
8043                 super.bind(op);
8044             }
8045 
8046             @Override
8047             public void dispose() {
8048                 super.unbind(op);
8049             }
8050 
8051             @Override
8052             protected String computeValue() {
8053                 try {
8054                     return op.get(key);
8055                 } catch (ClassCastException ex) {
8056                     Logging.getLogger().warning("Exception while evaluating binding", ex);
8057                     // ignore
8058                 } catch (NullPointerException ex) {
8059                     Logging.getLogger().warning("Exception while evaluating binding", ex);
8060                     // ignore
8061                 }
8062                 return null;
8063             }
8064 
8065             @Override
8066             public ObservableList<?> getDependencies() {
8067                 return FXCollections.singletonObservableList(op);
8068             }
8069         };
8070     }
8071 
8072     /**
8073      * Creates a new {@link javafx.beans.binding.StringBinding} that contains the mapping of a specific key
8074      * in an {@link javafx.collections.ObservableMap}. The {@code StringBinding}
8075      * will hold {@code ""} if the {@code key} cannot be found in the {@code ObservableMap}.
8076      *
8077      * @param op the {@code ObservableMap}
8078      * @param key the key in the {@code Map}
8079      * @param <K> type of the key elements of the {@code Map}
8080      * @return the new {@code StringBinding}
8081      * @throws NullPointerException if the {@code ObservableMap} or {@code key} is {@code null}
8082      * @since JavaFX 2.1
8083      */
8084     public static <K> StringBinding stringValueAt(final ObservableMap<K, String> op, final ObservableValue<? extends K> key) {
8085         if ((op == null) || (key == null)) {
8086             throw new NullPointerException("Operands cannot be null.");
8087         }
8088 
8089         return new StringBinding() {
8090             {
8091                 super.bind(op, key);
8092             }
8093 
8094             @Override
8095             public void dispose() {
8096                 super.unbind(op, key);
8097             }
8098 
8099             @Override
8100             protected String computeValue() {
8101                 try {
8102                     return op.get(key.getValue());
8103                 } catch (ClassCastException ex) {
8104                     Logging.getLogger().warning("Exception while evaluating binding", ex);
8105                     // ignore
8106                 } catch (NullPointerException ex) {
8107                     Logging.getLogger().warning("Exception while evaluating binding", ex);
8108                     // ignore
8109                 }
8110                 return null;
8111             }
8112 
8113             @Override
8114             public ObservableList<?> getDependencies() {
8115                 return new ImmutableObservableList<Observable>(op, key);
8116             }
8117         };
8118     }
8119 
8120 
8121 }