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