1 /* 2 * Copyright (c) 2010, 2014, 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.collections; 27 28 import com.sun.javafx.collections.ListListenerHelper; 29 import com.sun.javafx.collections.MapListenerHelper; 30 import com.sun.javafx.collections.SetListenerHelper; 31 import java.lang.reflect.Array; 32 import java.util.AbstractList; 33 import java.util.AbstractMap; 34 import java.util.AbstractSet; 35 import java.util.ArrayList; 36 import java.util.Arrays; 37 import java.util.Collection; 38 import java.util.Collections; 39 import java.util.Comparator; 40 import java.util.HashMap; 41 import java.util.HashSet; 42 import java.util.Iterator; 43 import java.util.List; 44 import java.util.ListIterator; 45 import java.util.Map; 46 import java.util.NoSuchElementException; 47 import java.util.Random; 48 import java.util.Set; 49 50 import javafx.beans.InvalidationListener; 51 52 import com.sun.javafx.collections.ObservableListWrapper; 53 import com.sun.javafx.collections.ObservableMapWrapper; 54 import com.sun.javafx.collections.ObservableSetWrapper; 55 import com.sun.javafx.collections.MapAdapterChange; 56 import com.sun.javafx.collections.ObservableFloatArrayImpl; 57 import com.sun.javafx.collections.ObservableIntegerArrayImpl; 58 import com.sun.javafx.collections.ObservableSequentialListWrapper; 59 import com.sun.javafx.collections.SetAdapterChange; 60 import com.sun.javafx.collections.SortableList; 61 import com.sun.javafx.collections.SourceAdapterChange; 62 import com.sun.javafx.collections.annotations.ReturnsUnmodifiableCollection; 63 import java.util.RandomAccess; 64 import javafx.beans.Observable; 65 import javafx.collections.ListChangeListener.Change; 66 import javafx.util.Callback; 67 68 /** 69 * Utility class that consists of static methods that are 1:1 copies of java.util.Collections methods. 70 * <br><br> 71 * The wrapper methods (like synchronizedObservableList or emptyObservableList) has exactly the same 72 * functionality as the methods in Collections, with exception that they return ObservableList and are 73 * therefore suitable for methods that require ObservableList on input. 74 * <br><br> 75 * The utility methods are here mainly for performance reasons. All methods are optimized in a way that 76 * they yield only limited number of notifications. On the other hand, java.util.Collections methods 77 * might call "modification methods" on an ObservableList multiple times, resulting in a number of notifications. 78 * 79 * @since JavaFX 2.0 80 */ 81 public class FXCollections { 82 /** Not to be instantiated. */ 83 private FXCollections() { } 84 85 /** 86 * Constructs an ObservableList that is backed by the specified list. 87 * Mutation operations on the ObservableList instance will be reported 88 * to observers that have registered on that instance.<br> 89 * Note that mutation operations made directly to the underlying list are 90 * <em>not</em> reported to observers of any ObservableList that 91 * wraps it. 92 * 93 * @param list a concrete List that backs this ObservableList 94 * @return a newly created ObservableList 95 */ 96 public static <E> ObservableList<E> observableList(List<E> list) { 97 if (list == null) { 98 throw new NullPointerException(); 99 } 100 return list instanceof RandomAccess ? new ObservableListWrapper<E>(list) : 101 new ObservableSequentialListWrapper<E>(list); 102 } 103 104 /** 105 * Constructs an ObservableList that is backed by the specified list. 106 * Mutation operations on the ObservableList instance will be reported 107 * to observers that have registered on that instance.<br> 108 * Note that mutation operations made directly to the underlying list are 109 * <em>not</em> reported to observers of any ObservableList that 110 * wraps it. 111 * <br> 112 * This list also reports mutations of the elements in it by using <code>extractor</code>. 113 * Observable objects returned by extractor (applied to each list element) are listened for changes 114 * and transformed into "update" change of ListChangeListener. 115 * 116 * @param list a concrete List that backs this ObservableList 117 * @param extractor element to Observable[] convertor 118 * @since JavaFX 2.1 119 * @return a newly created ObservableList 120 */ 121 public static <E> ObservableList<E> observableList(List<E> list, Callback<E, Observable[]> extractor) { 122 if (list == null || extractor == null) { 123 throw new NullPointerException(); 124 } 125 return list instanceof RandomAccess ? new ObservableListWrapper<E>(list, extractor) : 126 new ObservableSequentialListWrapper<E>(list, extractor); 127 } 128 129 /** 130 * Constructs an ObservableMap that is backed by the specified map. 131 * Mutation operations on the ObservableMap instance will be reported 132 * to observers that have registered on that instance.<br> 133 * Note that mutation operations made directly to the underlying map are <em>not</em> 134 * reported to observers of any ObservableMap that wraps it. 135 * @param map a Map that backs this ObservableMap 136 * @return a newly created ObservableMap 137 */ 138 public static <K, V> ObservableMap<K, V> observableMap(Map<K, V> map) { 139 if (map == null) { 140 throw new NullPointerException(); 141 } 142 return new ObservableMapWrapper<K, V>(map); 143 } 144 145 /** 146 * Constructs an ObservableSet that is backed by the specified set. 147 * Mutation operations on the ObservableSet instance will be reported 148 * to observers that have registered on that instance.<br> 149 * Note that mutation operations made directly to the underlying set are <em>not</em> 150 * reported to observers of any ObservableSet that wraps it. 151 * @param set a Set that backs this ObservableSet 152 * @return a newly created ObservableSet 153 * @since JavaFX 2.1 154 */ 155 public static <E> ObservableSet<E> observableSet(Set<E> set) { 156 if (set == null) { 157 throw new NullPointerException(); 158 } 159 return new ObservableSetWrapper<E>(set); 160 } 161 162 /** 163 * Constructs an ObservableSet backed by a HashSet 164 * that contains all the specified elements. 165 * @param elements elements that will be added into returned ObservableSet 166 * @return a newly created ObservableSet 167 * @since JavaFX 2.1 168 */ 169 public static <E> ObservableSet<E> observableSet(E... elements) { 170 if (elements == null) { 171 throw new NullPointerException(); 172 } 173 Set<E> set = new HashSet<E>(elements.length); 174 Collections.addAll(set, elements); 175 return new ObservableSetWrapper<E>(set); 176 } 177 178 /** 179 * Constructs a read-only interface to the specified ObservableMap. Only 180 * mutation operations made to the underlying ObservableMap will be reported 181 * to observers that have registered on the unmodifiable instance. This allows 182 * clients to track changes in a Map but disallows the ability to modify it. 183 * @param map an ObservableMap that is to be monitored by this interface 184 * @return a newly created UnmodifiableObservableMap 185 */ 186 @ReturnsUnmodifiableCollection 187 public static <K, V> ObservableMap<K, V> unmodifiableObservableMap(ObservableMap<K, V> map) { 188 if (map == null) { 189 throw new NullPointerException(); 190 } 191 return new com.sun.javafx.collections.UnmodifiableObservableMap<K, V>(map); 192 } 193 194 /** 195 * Creates and returns a typesafe wrapper on top of provided observable map. 196 * @param map an Observable map to be wrapped 197 * @param keyType the type of key that {@code map} is permitted to hold 198 * @param valueType the type of value that {@code map} is permitted to hold 199 * @return a dynamically typesafe view of the specified map 200 * @see Collections#checkedMap(java.util.Map, java.lang.Class) 201 * @since JavaFX 8.0 202 */ 203 public static <K, V> ObservableMap<K, V> checkedObservableMap(ObservableMap<K, V> map, Class<K> keyType, Class<V> valueType) { 204 if (map == null || keyType == null || valueType == null) { 205 throw new NullPointerException(); 206 } 207 return new CheckedObservableMap<K, V>(map, keyType, valueType); 208 } 209 210 /** 211 * Creates and returns a synchronized wrapper on top of provided observable map. 212 * @param map the map to be "wrapped" in a synchronized map. 213 * @return A synchronized version of the observable map 214 * @see Collections#synchronizedMap(java.util.Map) 215 * @since JavaFX 8.0 216 */ 217 public static <K, V> ObservableMap<K, V> synchronizedObservableMap(ObservableMap<K, V> map) { 218 if (map == null) { 219 throw new NullPointerException(); 220 } 221 return new SynchronizedObservableMap<K, V>(map); 222 } 223 224 private static ObservableMap EMPTY_OBSERVABLE_MAP = new EmptyObservableMap(); 225 226 /** 227 * Creates and empty unmodifiable observable map. 228 * @return An empty unmodifiable observable map 229 * @see Collections#emptyMap() 230 * @since JavaFX 8.0 231 */ 232 @SuppressWarnings("unchecked") 233 @ReturnsUnmodifiableCollection 234 public static <K, V> ObservableMap<K, V> emptyObservableMap() { 235 return EMPTY_OBSERVABLE_MAP; 236 } 237 238 /** 239 * Creates a new empty observable integer array. 240 * @return a newly created ObservableIntegerArray 241 * @since JavaFX 8.0 242 */ 243 public static ObservableIntegerArray observableIntegerArray() { 244 return new ObservableIntegerArrayImpl(); 245 } 246 247 /** 248 * Creates a new observable integer array with {@code values} set to it. 249 * @param values the values that will be in the new observable integer array 250 * @return a newly created ObservableIntegerArray 251 * @since JavaFX 8.0 252 */ 253 public static ObservableIntegerArray observableIntegerArray(int... values) { 254 return new ObservableIntegerArrayImpl(values); 255 } 256 257 /** 258 * Creates a new observable integer array with copy of elements in given 259 * {@code array}. 260 * @param array observable integer array to copy 261 * @return a newly created ObservableIntegerArray 262 * @since JavaFX 8.0 263 */ 264 public static ObservableIntegerArray observableIntegerArray(ObservableIntegerArray array) { 265 return new ObservableIntegerArrayImpl(array); 266 } 267 268 /** 269 * Creates a new empty observable float array. 270 * @return a newly created ObservableFloatArray 271 * @since JavaFX 8.0 272 */ 273 public static ObservableFloatArray observableFloatArray() { 274 return new ObservableFloatArrayImpl(); 275 } 276 277 /** 278 * Creates a new observable float array with {@code values} set to it. 279 * @param values the values that will be in the new observable float array 280 * @return a newly created ObservableFloatArray 281 * @since JavaFX 8.0 282 */ 283 public static ObservableFloatArray observableFloatArray(float... values) { 284 return new ObservableFloatArrayImpl(values); 285 } 286 287 /** 288 * Creates a new observable float array with copy of elements in given 289 * {@code array}. 290 * @param array observable float array to copy 291 * @return a newly created ObservableFloatArray 292 * @since JavaFX 8.0 293 */ 294 public static ObservableFloatArray observableFloatArray(ObservableFloatArray array) { 295 return new ObservableFloatArrayImpl(array); 296 } 297 298 /** 299 * Creates a new empty observable list that is backed by an arraylist. 300 * @see #observableList(java.util.List) 301 * @return a newly created ObservableList 302 */ 303 @SuppressWarnings("unchecked") 304 public static <E> ObservableList<E> observableArrayList() { 305 return observableList(new ArrayList()); 306 } 307 308 /** 309 * Creates a new empty observable list backed by an arraylist. 310 * 311 * This list reports element updates. 312 * @param extractor element to Observable[] convertor. Observable objects are listened for changes on the element. 313 * @see #observableList(java.util.List, javafx.util.Callback) 314 * @since JavaFX 2.1 315 * @return a newly created ObservableList 316 */ 317 public static <E> ObservableList<E> observableArrayList(Callback<E, Observable[]> extractor) { 318 return observableList(new ArrayList(), extractor); 319 } 320 321 /** 322 * Creates a new observable array list with {@code items} added to it. 323 * @return a newly created observableArrayList 324 * @param items the items that will be in the new observable ArrayList 325 * @see #observableArrayList() 326 */ 327 public static <E> ObservableList<E> observableArrayList(E... items) { 328 ObservableList<E> list = observableArrayList(); 329 list.addAll(items); 330 return list; 331 } 332 333 /** 334 * Creates a new observable array list and adds a content of collection {@code col} 335 * to it. 336 * @param col a collection which content should be added to the observableArrayList 337 * @return a newly created observableArrayList 338 */ 339 public static <E> ObservableList<E> observableArrayList(Collection<? extends E> col) { 340 ObservableList<E> list = observableArrayList(); 341 list.addAll(col); 342 return list; 343 } 344 345 /** 346 * Creates a new empty observable map that is backed by a HashMap. 347 * @param <K> the type of keys 348 * @param <V> the type of values 349 * @return a newly created observable HashMap 350 */ 351 public static <K,V> ObservableMap<K,V> observableHashMap() { 352 return observableMap(new HashMap<K, V>()); 353 } 354 355 /** 356 * Concatenates more observable lists into one. The resulting list 357 * would be backed by an arraylist. 358 * @param lists lists to concatenate 359 * @return new observable array list concatenated from the arguments 360 */ 361 public static <E> ObservableList<E> concat(ObservableList<E>... lists) { 362 if (lists.length == 0 ) { 363 return observableArrayList(); 364 } 365 if (lists.length == 1) { 366 return observableArrayList(lists[0]); 367 } 368 ArrayList<E> backingList = new ArrayList<E>(); 369 for (ObservableList<E> s : lists) { 370 backingList.addAll(s); 371 } 372 373 return observableList(backingList); 374 } 375 376 /** 377 * Creates and returns unmodifiable wrapper list on top of provided observable list. 378 * @param list an ObservableList that is to be wrapped 379 * @return an ObserableList wrapper that is unmodifiable 380 * @see Collections#unmodifiableList(java.util.List) 381 */ 382 @ReturnsUnmodifiableCollection 383 public static<E> ObservableList<E> unmodifiableObservableList(ObservableList<E> list) { 384 if (list == null) { 385 throw new NullPointerException(); 386 } 387 return new UnmodifiableObservableListImpl<E>(list); 388 } 389 390 /** 391 * Creates and returns a typesafe wrapper on top of provided observable list. 392 * @param list an Observable list to be wrapped 393 * @param type the type of element that <tt>list</tt> is permitted to hold 394 * @return a dynamically typesafe view of the specified list 395 * @see Collections#checkedList(java.util.List, java.lang.Class) 396 */ 397 public static<E> ObservableList<E> checkedObservableList(ObservableList<E> list, Class<E> type) { 398 if (list == null) { 399 throw new NullPointerException(); 400 } 401 return new CheckedObservableList<E>(list, type); 402 } 403 404 /** 405 * Creates and returns a synchronized wrapper on top of provided observable list. 406 * @param list the list to be "wrapped" in a synchronized list. 407 * @return A synchronized version of the observable list 408 * @see Collections#synchronizedList(java.util.List) 409 */ 410 public static<E> ObservableList<E> synchronizedObservableList(ObservableList<E> list) { 411 if (list == null) { 412 throw new NullPointerException(); 413 } 414 return new SynchronizedObservableList<E>(list); 415 } 416 417 private static ObservableList EMPTY_OBSERVABLE_LIST = new EmptyObservableList(); 418 419 420 /** 421 * Creates and empty unmodifiable observable list. 422 * @return An empty unmodifiable observable list 423 * @see Collections#emptyList() 424 */ 425 @SuppressWarnings("unchecked") 426 @ReturnsUnmodifiableCollection 427 public static<E> ObservableList<E> emptyObservableList() { 428 return EMPTY_OBSERVABLE_LIST; 429 } 430 431 /** 432 * Creates an unmodifiable observable list with single element. 433 * @param e the only elements that will be contained in this singleton observable list 434 * @return a singleton observable list 435 * @see Collections#singletonList(java.lang.Object) 436 */ 437 @ReturnsUnmodifiableCollection 438 public static<E> ObservableList<E> singletonObservableList(E e) { 439 return new SingletonObservableList<E>(e); 440 } 441 442 /** 443 * Creates and returns unmodifiable wrapper on top of provided observable set. 444 * @param set an ObservableSet that is to be wrapped 445 * @return an ObserableSet wrapper that is unmodifiable 446 * @see Collections#unmodifiableSet(java.util.Set) 447 * @since JavaFX 8.0 448 */ 449 @ReturnsUnmodifiableCollection 450 public static<E> ObservableSet<E> unmodifiableObservableSet(ObservableSet<E> set) { 451 if (set == null) { 452 throw new NullPointerException(); 453 } 454 return new UnmodifiableObservableSet<E>(set); 455 } 456 457 /** 458 * Creates and returns a typesafe wrapper on top of provided observable set. 459 * @param set an Observable set to be wrapped 460 * @param type the type of element that <tt>set</tt> is permitted to hold 461 * @return a dynamically typesafe view of the specified set 462 * @see Collections#checkedSet(java.util.Set, java.lang.Class) 463 * @since JavaFX 8.0 464 */ 465 public static<E> ObservableSet<E> checkedObservableSet(ObservableSet<E> set, Class<E> type) { 466 if (set == null) { 467 throw new NullPointerException(); 468 } 469 return new CheckedObservableSet<E>(set, type); 470 } 471 472 /** 473 * Creates and returns a synchronized wrapper on top of provided observable set. 474 * @param set the set to be "wrapped" in a synchronized set. 475 * @return A synchronized version of the observable set 476 * @see Collections#synchronizedSet(java.util.Set) 477 * @since JavaFX 8.0 478 */ 479 public static<E> ObservableSet<E> synchronizedObservableSet(ObservableSet<E> set) { 480 if (set == null) { 481 throw new NullPointerException(); 482 } 483 return new SynchronizedObservableSet<E>(set); 484 } 485 486 private static ObservableSet EMPTY_OBSERVABLE_SET = new EmptyObservableSet(); 487 488 /** 489 * Creates and empty unmodifiable observable set. 490 * @return An empty unmodifiable observable set 491 * @see Collections#emptySet() 492 * @since JavaFX 8.0 493 */ 494 @SuppressWarnings("unchecked") 495 @ReturnsUnmodifiableCollection 496 public static<E> ObservableSet<E> emptyObservableSet() { 497 return EMPTY_OBSERVABLE_SET; 498 } 499 500 /** 501 * Copies elements from src to dest. Fires only <b>one</b> change notification on dest. 502 * @param dest the destination observable list 503 * @param src the source list 504 * @see Collections#copy(java.util.List, java.util.List) 505 */ 506 @SuppressWarnings("unchecked") 507 public static <T> void copy(ObservableList<? super T> dest, List<? extends T> src) { 508 final int srcSize = src.size(); 509 if (srcSize > dest.size()) { 510 throw new IndexOutOfBoundsException("Source does not fit in dest"); 511 } 512 T[] destArray = (T[]) dest.toArray(); 513 System.arraycopy(src.toArray(), 0, destArray, 0, srcSize); 514 dest.setAll(destArray); 515 } 516 517 /** 518 * Fills the provided list with obj. Fires only <b>one</b> change notification on the list. 519 * @param list the list to fill 520 * @param obj the object to fill the list with 521 * @see Collections#fill(java.util.List, java.lang.Object) 522 */ 523 @SuppressWarnings("unchecked") 524 public static <T> void fill(ObservableList<? super T> list, T obj) { 525 T[] newContent = (T[]) new Object[list.size()]; 526 Arrays.fill(newContent, obj); 527 list.setAll(newContent); 528 } 529 530 /** 531 * Replace all oldVal elements in the list with newVal element. 532 * Fires only <b>one</b> change notification on the list. 533 * @param list the list which will have it's elements replaced 534 * @param oldVal the element that is going to be replace 535 * @param newVal the replacement 536 * @return true if the list was modified 537 * @see Collections#replaceAll(java.util.List, java.lang.Object, java.lang.Object) 538 */ 539 @SuppressWarnings("unchecked") 540 public static <T> boolean replaceAll(ObservableList<T> list, T oldVal, T newVal) { 541 T[] newContent = (T[]) list.toArray(); 542 boolean modified = false; 543 for (int i = 0 ; i < newContent.length; ++i) { 544 if (newContent[i].equals(oldVal)) { 545 newContent[i] = newVal; 546 modified = true; 547 } 548 } 549 if (modified) { 550 list.setAll(newContent); 551 } 552 return modified; 553 } 554 555 /** 556 * Reverse the order in the list 557 * Fires only <b>one</b> change notification on the list. 558 * @param list the list to be reversed 559 * @see Collections#reverse(java.util.List) 560 */ 561 @SuppressWarnings("unchecked") 562 public static void reverse(ObservableList list) { 563 Object[] newContent = list.toArray(); 564 for (int i = 0; i < newContent.length / 2; ++i) { 565 Object tmp = newContent[i]; 566 newContent[i] = newContent[newContent.length - i - 1]; 567 newContent[newContent.length -i - 1] = tmp; 568 } 569 list.setAll(newContent); 570 } 571 572 /** 573 * Rotates the list by distance. 574 * Fires only <b>one</b> change notification on the list. 575 * @param list the list to be rotated 576 * @param distance the distance of rotation 577 * @see Collections#rotate(java.util.List, int) 578 */ 579 @SuppressWarnings("unchecked") 580 public static void rotate(ObservableList list, int distance) { 581 Object[] newContent = list.toArray(); 582 583 int size = list.size(); 584 distance = distance % size; 585 if (distance < 0) 586 distance += size; 587 if (distance == 0) 588 return; 589 590 for (int cycleStart = 0, nMoved = 0; nMoved != size; cycleStart++) { 591 Object displaced = newContent[cycleStart]; 592 Object tmp; 593 int i = cycleStart; 594 do { 595 i += distance; 596 if (i >= size) 597 i -= size; 598 tmp = newContent[i]; 599 newContent[i] = displaced; 600 displaced = tmp; 601 nMoved ++; 602 } while(i != cycleStart); 603 } 604 list.setAll(newContent); 605 } 606 607 /** 608 * Shuffles all elements in the observable list. 609 * Fires only <b>one</b> change notification on the list. 610 * @param list the list to shuffle 611 * @see Collections#shuffle(java.util.List) 612 */ 613 public static void shuffle(ObservableList<?> list) { 614 if (r == null) { 615 r = new Random(); 616 } 617 shuffle(list, r); 618 } 619 private static Random r; 620 621 /** 622 * Shuffles all elements in the observable list. 623 * Fires only <b>one</b> change notification on the list. 624 * @param list the list to be shuffled 625 * @param rnd the random generator used for shuffling 626 * @see Collections#shuffle(java.util.List, java.util.Random) 627 */ 628 @SuppressWarnings("unchecked") 629 public static void shuffle(ObservableList list, Random rnd) { 630 Object newContent[] = list.toArray(); 631 632 for (int i = list.size(); i > 1; i--) { 633 swap(newContent, i - 1, rnd.nextInt(i)); 634 } 635 636 list.setAll(newContent); 637 } 638 639 private static void swap(Object[] arr, int i, int j) { 640 Object tmp = arr[i]; 641 arr[i] = arr[j]; 642 arr[j] = tmp; 643 } 644 645 /** 646 * Sorts the provided observable list. 647 * Fires only <b>one</b> change notification on the list. 648 * @see Collections#sort(java.util.List) 649 */ 650 @SuppressWarnings("unchecked") 651 public static <T extends Comparable<? super T>> void sort(ObservableList<T> list) { 652 if (list instanceof SortableList) { 653 ((SortableList<? extends T>)list).sort(); 654 } else { 655 List<T> newContent = new ArrayList<T>(list); 656 Collections.sort(newContent); 657 list.setAll((Collection<T>)newContent); 658 } 659 } 660 661 /** 662 * Sorts the provided observable list using the c comparator. 663 * Fires only <b>one</b> change notification on the list. 664 * @param list the list to sort 665 * @param c comparator used for sorting. Null if natural ordering is required. 666 * @see Collections#sort(java.util.List, java.util.Comparator) 667 */ 668 @SuppressWarnings("unchecked") 669 public static <T> void sort(ObservableList<T> list, Comparator<? super T> c) { 670 if (list instanceof SortableList) { 671 ((SortableList<? extends T>)list).sort(c); 672 } else { 673 List<T> newContent = new ArrayList<T>(list); 674 Collections.sort(newContent, c); 675 list.setAll((Collection<T>)newContent); 676 } 677 } 678 679 private static class EmptyObservableList<E> extends AbstractList<E> implements ObservableList<E> { 680 681 private static final ListIterator iterator = new ListIterator() { 682 683 @Override 684 public boolean hasNext() { 685 return false; 686 } 687 688 @Override 689 public Object next() { 690 throw new NoSuchElementException(); 691 } 692 693 @Override 694 public void remove() { 695 throw new UnsupportedOperationException(); 696 } 697 698 @Override 699 public boolean hasPrevious() { 700 return false; 701 } 702 703 @Override 704 public Object previous() { 705 throw new NoSuchElementException(); 706 } 707 708 @Override 709 public int nextIndex() { 710 return 0; 711 } 712 713 @Override 714 public int previousIndex() { 715 return -1; 716 } 717 718 @Override 719 public void set(Object e) { 720 throw new UnsupportedOperationException(); 721 } 722 723 @Override 724 public void add(Object e) { 725 throw new UnsupportedOperationException(); 726 } 727 }; 728 729 public EmptyObservableList() { 730 } 731 732 @Override 733 public final void addListener(InvalidationListener listener) { 734 } 735 736 @Override 737 public final void removeListener(InvalidationListener listener) { 738 } 739 740 741 @Override 742 public void addListener(ListChangeListener<? super E> o) { 743 } 744 745 @Override 746 public void removeListener(ListChangeListener<? super E> o) { 747 } 748 749 @Override 750 public int size() { 751 return 0; 752 } 753 754 @Override 755 public boolean contains(Object o) { 756 return false; 757 } 758 759 @Override 760 @SuppressWarnings("unchecked") 761 public Iterator<E> iterator() { 762 return iterator; 763 } 764 765 @Override 766 public boolean containsAll(Collection<?> c) { 767 return c.isEmpty(); 768 } 769 770 @Override 771 public E get(int index) { 772 throw new IndexOutOfBoundsException(); 773 } 774 775 @Override 776 public int indexOf(Object o) { 777 return -1; 778 } 779 780 @Override 781 public int lastIndexOf(Object o) { 782 return -1; 783 } 784 785 @Override 786 @SuppressWarnings("unchecked") 787 public ListIterator<E> listIterator() { 788 return iterator; 789 } 790 791 @Override 792 @SuppressWarnings("unchecked") 793 public ListIterator<E> listIterator(int index) { 794 if (index != 0) { 795 throw new IndexOutOfBoundsException(); 796 } 797 return iterator; 798 } 799 800 @Override 801 public List<E> subList(int fromIndex, int toIndex) { 802 if (fromIndex != 0 || toIndex != 0) { 803 throw new IndexOutOfBoundsException(); 804 } 805 return this; 806 } 807 808 @Override 809 public boolean addAll(E... elements) { 810 throw new UnsupportedOperationException(); 811 } 812 813 @Override 814 public boolean setAll(E... elements) { 815 throw new UnsupportedOperationException(); 816 } 817 818 @Override 819 public boolean setAll(Collection<? extends E> col) { 820 throw new UnsupportedOperationException(); 821 } 822 823 @Override 824 public boolean removeAll(E... elements) { 825 throw new UnsupportedOperationException(); 826 } 827 828 @Override 829 public boolean retainAll(E... elements) { 830 throw new UnsupportedOperationException(); 831 } 832 833 @Override 834 public void remove(int from, int to) { 835 throw new UnsupportedOperationException(); 836 } 837 } 838 839 private static class SingletonObservableList<E> extends AbstractList<E> implements ObservableList<E> { 840 841 private final E element; 842 843 public SingletonObservableList(E element) { 844 if (element == null) { 845 throw new NullPointerException(); 846 } 847 this.element = element; 848 } 849 850 @Override 851 public boolean addAll(E... elements) { 852 throw new UnsupportedOperationException(); 853 } 854 855 @Override 856 public boolean setAll(E... elements) { 857 throw new UnsupportedOperationException(); 858 } 859 860 @Override 861 public boolean setAll(Collection<? extends E> col) { 862 throw new UnsupportedOperationException(); 863 } 864 865 @Override 866 public boolean removeAll(E... elements) { 867 throw new UnsupportedOperationException(); 868 } 869 870 @Override 871 public boolean retainAll(E... elements) { 872 throw new UnsupportedOperationException(); 873 } 874 875 @Override 876 public void remove(int from, int to) { 877 throw new UnsupportedOperationException(); 878 } 879 880 @Override 881 public void addListener(InvalidationListener listener) { 882 } 883 884 @Override 885 public void removeListener(InvalidationListener listener) { 886 } 887 888 @Override 889 public void addListener(ListChangeListener<? super E> o) { 890 } 891 892 @Override 893 public void removeListener(ListChangeListener<? super E> o) { 894 } 895 896 @Override 897 public int size() { 898 return 1; 899 } 900 901 @Override 902 public boolean isEmpty() { 903 return false; 904 } 905 906 @Override 907 public boolean contains(Object o) { 908 return element.equals(o); 909 } 910 911 @Override 912 public E get(int index) { 913 if (index != 0) { 914 throw new IndexOutOfBoundsException(); 915 } 916 return element; 917 } 918 919 } 920 921 private static class UnmodifiableObservableListImpl<T> extends ObservableListBase<T> implements ObservableList<T> { 922 923 private final ObservableList<T> backingList; 924 private final ListChangeListener<T> listener; 925 926 public UnmodifiableObservableListImpl(ObservableList<T> backingList) { 927 this.backingList = backingList; 928 listener = c -> { 929 fireChange(new SourceAdapterChange<T>(UnmodifiableObservableListImpl.this, c)); 930 }; 931 this.backingList.addListener(new WeakListChangeListener<T>(listener)); 932 } 933 934 @Override 935 public T get(int index) { 936 return backingList.get(index); 937 } 938 939 @Override 940 public int size() { 941 return backingList.size(); 942 } 943 944 @Override 945 public boolean addAll(T... elements) { 946 throw new UnsupportedOperationException(); 947 } 948 949 @Override 950 public boolean setAll(T... elements) { 951 throw new UnsupportedOperationException(); 952 } 953 954 @Override 955 public boolean setAll(Collection<? extends T> col) { 956 throw new UnsupportedOperationException(); 957 } 958 959 @Override 960 public boolean removeAll(T... elements) { 961 throw new UnsupportedOperationException(); 962 } 963 964 @Override 965 public boolean retainAll(T... elements) { 966 throw new UnsupportedOperationException(); 967 } 968 969 @Override 970 public void remove(int from, int to) { 971 throw new UnsupportedOperationException(); 972 } 973 974 } 975 976 private static class SynchronizedList<T> implements List<T> { 977 final Object mutex; 978 private final List<T> backingList; 979 980 SynchronizedList(List<T> list, Object mutex) { 981 this.backingList = list; 982 this.mutex = mutex; 983 } 984 985 @Override 986 public int size() { 987 synchronized(mutex) { 988 return backingList.size(); 989 } 990 } 991 992 @Override 993 public boolean isEmpty() { 994 synchronized(mutex) { 995 return backingList.isEmpty(); 996 } 997 } 998 999 @Override 1000 public boolean contains(Object o) { 1001 synchronized(mutex) { 1002 return backingList.contains(o); 1003 } 1004 } 1005 1006 @Override 1007 public Iterator<T> iterator() { 1008 return backingList.iterator(); 1009 } 1010 1011 @Override 1012 public Object[] toArray() { 1013 synchronized(mutex) { 1014 return backingList.toArray(); 1015 } 1016 } 1017 1018 @Override 1019 public <T> T[] toArray(T[] a) { 1020 synchronized(mutex) { 1021 return backingList.toArray(a); 1022 } 1023 } 1024 1025 @Override 1026 public boolean add(T e) { 1027 synchronized(mutex) { 1028 return backingList.add(e); 1029 } 1030 } 1031 1032 @Override 1033 public boolean remove(Object o) { 1034 synchronized(mutex) { 1035 return backingList.remove(o); 1036 } 1037 } 1038 1039 @Override 1040 public boolean containsAll(Collection<?> c) { 1041 synchronized(mutex) { 1042 return backingList.containsAll(c); 1043 } 1044 } 1045 1046 @Override 1047 public boolean addAll(Collection<? extends T> c) { 1048 synchronized(mutex) { 1049 return backingList.addAll(c); 1050 } 1051 } 1052 1053 @Override 1054 public boolean addAll(int index, Collection<? extends T> c) { 1055 synchronized(mutex) { 1056 return backingList.addAll(index, c); 1057 1058 } 1059 } 1060 1061 @Override 1062 public boolean removeAll(Collection<?> c) { 1063 synchronized(mutex) { 1064 return backingList.removeAll(c); 1065 } 1066 } 1067 1068 @Override 1069 public boolean retainAll(Collection<?> c) { 1070 synchronized(mutex) { 1071 return backingList.retainAll(c); 1072 } 1073 } 1074 1075 @Override 1076 public void clear() { 1077 synchronized(mutex) { 1078 backingList.clear(); 1079 } 1080 } 1081 1082 @Override 1083 public T get(int index) { 1084 synchronized(mutex) { 1085 return backingList.get(index); 1086 } 1087 } 1088 1089 @Override 1090 public T set(int index, T element) { 1091 synchronized(mutex) { 1092 return backingList.set(index, element); 1093 } 1094 } 1095 1096 @Override 1097 public void add(int index, T element) { 1098 synchronized(mutex) { 1099 backingList.add(index, element); 1100 } 1101 } 1102 1103 @Override 1104 public T remove(int index) { 1105 synchronized(mutex) { 1106 return backingList.remove(index); 1107 } 1108 } 1109 1110 @Override 1111 public int indexOf(Object o) { 1112 synchronized(mutex) { 1113 return backingList.indexOf(o); 1114 } 1115 } 1116 1117 @Override 1118 public int lastIndexOf(Object o) { 1119 synchronized(mutex) { 1120 return backingList.lastIndexOf(o); 1121 } 1122 } 1123 1124 @Override 1125 public ListIterator<T> listIterator() { 1126 return backingList.listIterator(); 1127 } 1128 1129 @Override 1130 public ListIterator<T> listIterator(int index) { 1131 synchronized(mutex) { 1132 return backingList.listIterator(index); 1133 } 1134 } 1135 1136 @Override 1137 public List<T> subList(int fromIndex, int toIndex) { 1138 synchronized(mutex) { 1139 return new SynchronizedList<T>(backingList.subList(fromIndex, toIndex), 1140 mutex); 1141 } 1142 } 1143 1144 @Override 1145 public String toString() { 1146 synchronized(mutex) { 1147 return backingList.toString(); 1148 } 1149 } 1150 1151 @Override 1152 public int hashCode() { 1153 synchronized(mutex) { 1154 return backingList.hashCode(); 1155 } 1156 } 1157 1158 @Override 1159 public boolean equals(Object o) { 1160 synchronized(mutex) { 1161 return backingList.equals(o); 1162 } 1163 } 1164 1165 } 1166 1167 private static class SynchronizedObservableList<T> extends SynchronizedList<T> implements ObservableList<T> { 1168 1169 private ListListenerHelper helper; 1170 1171 private final ObservableList<T> backingList; 1172 private final ListChangeListener<T> listener; 1173 1174 SynchronizedObservableList(ObservableList<T> seq, Object mutex) { 1175 super(seq, mutex); 1176 this.backingList = seq; 1177 listener = c -> { 1178 ListListenerHelper.fireValueChangedEvent(helper, new SourceAdapterChange<T>(SynchronizedObservableList.this, c)); 1179 }; 1180 backingList.addListener(new WeakListChangeListener<T>(listener)); 1181 } 1182 1183 SynchronizedObservableList(ObservableList<T> seq) { 1184 this(seq, new Object()); 1185 } 1186 1187 @Override 1188 public boolean addAll(T... elements) { 1189 synchronized(mutex) { 1190 return backingList.addAll(elements); 1191 } 1192 } 1193 1194 @Override 1195 public boolean setAll(T... elements) { 1196 synchronized(mutex) { 1197 return backingList.setAll(elements); 1198 } 1199 } 1200 1201 @Override 1202 public boolean removeAll(T... elements) { 1203 synchronized(mutex) { 1204 return backingList.removeAll(elements); 1205 } 1206 } 1207 1208 @Override 1209 public boolean retainAll(T... elements) { 1210 synchronized(mutex) { 1211 return backingList.retainAll(elements); 1212 } 1213 } 1214 1215 @Override 1216 public void remove(int from, int to) { 1217 synchronized(mutex) { 1218 backingList.remove(from, to); 1219 } 1220 } 1221 1222 @Override 1223 public boolean setAll(Collection<? extends T> col) { 1224 synchronized(mutex) { 1225 return backingList.setAll(col); 1226 } 1227 } 1228 1229 @Override 1230 public final void addListener(InvalidationListener listener) { 1231 synchronized (mutex) { 1232 helper = ListListenerHelper.addListener(helper, listener); 1233 } 1234 } 1235 1236 @Override 1237 public final void removeListener(InvalidationListener listener) { 1238 synchronized (mutex) { 1239 helper = ListListenerHelper.removeListener(helper, listener); 1240 } 1241 } 1242 1243 @Override 1244 public void addListener(ListChangeListener<? super T> listener) { 1245 synchronized (mutex) { 1246 helper = ListListenerHelper.addListener(helper, listener); 1247 } 1248 } 1249 1250 @Override 1251 public void removeListener(ListChangeListener<? super T> listener) { 1252 synchronized (mutex) { 1253 helper = ListListenerHelper.removeListener(helper, listener); 1254 } 1255 } 1256 1257 1258 } 1259 1260 private static class CheckedObservableList<T> extends ObservableListBase<T> implements ObservableList<T> { 1261 1262 private final ObservableList<T> list; 1263 private final Class<T> type; 1264 private final ListChangeListener<T> listener; 1265 1266 CheckedObservableList(ObservableList<T> list, Class<T> type) { 1267 if (list == null || type == null) { 1268 throw new NullPointerException(); 1269 } 1270 this.list = list; 1271 this.type = type; 1272 listener = c -> { 1273 fireChange(new SourceAdapterChange<T>(CheckedObservableList.this, c)); 1274 }; 1275 list.addListener(new WeakListChangeListener<T>(listener)); 1276 } 1277 1278 void typeCheck(Object o) { 1279 if (o != null && !type.isInstance(o)) { 1280 throw new ClassCastException("Attempt to insert " 1281 + o.getClass() + " element into collection with element type " 1282 + type); 1283 } 1284 } 1285 1286 @Override 1287 public int size() { 1288 return list.size(); 1289 } 1290 1291 @Override 1292 public boolean isEmpty() { 1293 return list.isEmpty(); 1294 } 1295 1296 @Override 1297 public boolean contains(Object o) { 1298 return list.contains(o); 1299 } 1300 1301 @Override 1302 public Object[] toArray() { 1303 return list.toArray(); 1304 } 1305 1306 @Override 1307 public <T> T[] toArray(T[] a) { 1308 return list.toArray(a); 1309 } 1310 1311 @Override 1312 public String toString() { 1313 return list.toString(); 1314 } 1315 1316 @Override 1317 public boolean remove(Object o) { 1318 return list.remove(o); 1319 } 1320 1321 @Override 1322 public boolean containsAll(Collection<?> coll) { 1323 return list.containsAll(coll); 1324 } 1325 1326 @Override 1327 public boolean removeAll(Collection<?> coll) { 1328 return list.removeAll(coll); 1329 } 1330 1331 @Override 1332 public boolean retainAll(Collection<?> coll) { 1333 return list.retainAll(coll); 1334 } 1335 1336 @Override 1337 public boolean removeAll(T... elements) { 1338 return list.removeAll(elements); 1339 } 1340 1341 @Override 1342 public boolean retainAll(T... elements) { 1343 return list.retainAll(elements); 1344 } 1345 1346 @Override 1347 public void remove(int from, int to) { 1348 list.remove(from, to); 1349 } 1350 1351 @Override 1352 public void clear() { 1353 list.clear(); 1354 } 1355 1356 @Override 1357 public boolean equals(Object o) { 1358 return o == this || list.equals(o); 1359 } 1360 1361 @Override 1362 public int hashCode() { 1363 return list.hashCode(); 1364 } 1365 1366 @Override 1367 public T get(int index) { 1368 return list.get(index); 1369 } 1370 1371 @Override 1372 public T remove(int index) { 1373 return list.remove(index); 1374 } 1375 1376 @Override 1377 public int indexOf(Object o) { 1378 return list.indexOf(o); 1379 } 1380 1381 @Override 1382 public int lastIndexOf(Object o) { 1383 return list.lastIndexOf(o); 1384 } 1385 1386 @Override 1387 public T set(int index, T element) { 1388 typeCheck(element); 1389 return list.set(index, element); 1390 } 1391 1392 @Override 1393 public void add(int index, T element) { 1394 typeCheck(element); 1395 list.add(index, element); 1396 } 1397 1398 @Override 1399 @SuppressWarnings("unchecked") 1400 public boolean addAll(int index, Collection<? extends T> c) { 1401 T[] a = null; 1402 try { 1403 a = c.toArray((T[]) Array.newInstance(type, 0)); 1404 } catch (ArrayStoreException e) { 1405 throw new ClassCastException(); 1406 } 1407 1408 return this.list.addAll(index, Arrays.asList(a)); 1409 } 1410 1411 @Override 1412 @SuppressWarnings("unchecked") 1413 public boolean addAll(Collection<? extends T> coll) { 1414 T[] a = null; 1415 try { 1416 a = coll.toArray((T[]) Array.newInstance(type, 0)); 1417 } catch (ArrayStoreException e) { 1418 throw new ClassCastException(); 1419 } 1420 1421 return this.list.addAll(Arrays.asList(a)); 1422 } 1423 1424 @Override 1425 public ListIterator<T> listIterator() { 1426 return listIterator(0); 1427 } 1428 1429 @Override 1430 public ListIterator<T> listIterator(final int index) { 1431 return new ListIterator<T>() { 1432 1433 ListIterator<T> i = list.listIterator(index); 1434 1435 @Override 1436 public boolean hasNext() { 1437 return i.hasNext(); 1438 } 1439 1440 @Override 1441 public T next() { 1442 return i.next(); 1443 } 1444 1445 @Override 1446 public boolean hasPrevious() { 1447 return i.hasPrevious(); 1448 } 1449 1450 @Override 1451 public T previous() { 1452 return i.previous(); 1453 } 1454 1455 @Override 1456 public int nextIndex() { 1457 return i.nextIndex(); 1458 } 1459 1460 @Override 1461 public int previousIndex() { 1462 return i.previousIndex(); 1463 } 1464 1465 @Override 1466 public void remove() { 1467 i.remove(); 1468 } 1469 1470 @Override 1471 public void set(T e) { 1472 typeCheck(e); 1473 i.set(e); 1474 } 1475 1476 @Override 1477 public void add(T e) { 1478 typeCheck(e); 1479 i.add(e); 1480 } 1481 }; 1482 } 1483 1484 @Override 1485 public Iterator<T> iterator() { 1486 return new Iterator<T>() { 1487 1488 private final Iterator<T> it = list.iterator(); 1489 1490 @Override 1491 public boolean hasNext() { 1492 return it.hasNext(); 1493 } 1494 1495 @Override 1496 public T next() { 1497 return it.next(); 1498 } 1499 1500 @Override 1501 public void remove() { 1502 it.remove(); 1503 } 1504 }; 1505 } 1506 1507 @Override 1508 public boolean add(T e) { 1509 typeCheck(e); 1510 return list.add(e); 1511 } 1512 1513 @Override 1514 public List<T> subList(int fromIndex, int toIndex) { 1515 return Collections.checkedList(list.subList(fromIndex, toIndex), type); 1516 } 1517 1518 @Override 1519 @SuppressWarnings("unchecked") 1520 public boolean addAll(T... elements) { 1521 try { 1522 T[] array = (T[]) Array.newInstance(type, elements.length); 1523 System.arraycopy(elements, 0, array, 0, elements.length); 1524 return list.addAll(array); 1525 } catch (ArrayStoreException e) { 1526 throw new ClassCastException(); 1527 } 1528 } 1529 1530 @Override 1531 @SuppressWarnings("unchecked") 1532 public boolean setAll(T... elements) { 1533 try { 1534 T[] array = (T[]) Array.newInstance(type, elements.length); 1535 System.arraycopy(elements, 0, array, 0, elements.length); 1536 return list.setAll(array); 1537 } catch (ArrayStoreException e) { 1538 throw new ClassCastException(); 1539 } 1540 } 1541 1542 @Override 1543 @SuppressWarnings("unchecked") 1544 public boolean setAll(Collection<? extends T> col) { 1545 T[] a = null; 1546 try { 1547 a = col.toArray((T[]) Array.newInstance(type, 0)); 1548 } catch (ArrayStoreException e) { 1549 throw new ClassCastException(); 1550 } 1551 1552 return list.setAll(Arrays.asList(a)); 1553 } 1554 } 1555 1556 private static class EmptyObservableSet<E> extends AbstractSet<E> implements ObservableSet<E> { 1557 1558 public EmptyObservableSet() { 1559 } 1560 1561 @Override 1562 public void addListener(InvalidationListener listener) { 1563 } 1564 1565 @Override 1566 public void removeListener(InvalidationListener listener) { 1567 } 1568 1569 @Override 1570 public void addListener(SetChangeListener<? super E> listener) { 1571 } 1572 1573 @Override 1574 public void removeListener(SetChangeListener<? super E> listener) { 1575 } 1576 1577 @Override 1578 public int size() { 1579 return 0; 1580 } 1581 1582 @Override 1583 public boolean isEmpty() { 1584 return true; 1585 } 1586 1587 @Override 1588 public boolean contains(Object obj) { 1589 return false; 1590 } 1591 1592 @Override 1593 public boolean containsAll(Collection<?> c) { 1594 return c.isEmpty(); 1595 } 1596 1597 @Override 1598 public Object[] toArray() { 1599 return new Object[0]; 1600 } 1601 1602 @Override 1603 public <E> E[] toArray(E[] a) { 1604 if (a.length > 0) 1605 a[0] = null; 1606 return a; 1607 } 1608 1609 @Override 1610 public Iterator<E> iterator() { 1611 return new Iterator() { 1612 1613 @Override 1614 public boolean hasNext() { 1615 return false; 1616 } 1617 1618 @Override 1619 public Object next() { 1620 throw new NoSuchElementException(); 1621 } 1622 1623 @Override 1624 public void remove() { 1625 throw new UnsupportedOperationException(); 1626 } 1627 }; 1628 } 1629 1630 } 1631 1632 private static class UnmodifiableObservableSet<E> extends AbstractSet<E> implements ObservableSet<E> { 1633 1634 private final ObservableSet<E> backingSet; 1635 private SetListenerHelper<E> listenerHelper; 1636 private SetChangeListener<E> listener; 1637 1638 public UnmodifiableObservableSet(ObservableSet<E> backingSet) { 1639 this.backingSet = backingSet; 1640 this.listener = null; 1641 } 1642 1643 private void initListener() { 1644 if (listener == null) { 1645 listener = c -> { 1646 callObservers(new SetAdapterChange<E>(UnmodifiableObservableSet.this, c)); 1647 }; 1648 this.backingSet.addListener(new WeakSetChangeListener<E>(listener)); 1649 } 1650 } 1651 1652 private void callObservers(SetChangeListener.Change<? extends E> change) { 1653 SetListenerHelper.fireValueChangedEvent(listenerHelper, change); 1654 } 1655 1656 @Override 1657 public Iterator<E> iterator() { 1658 return new Iterator<E>() { 1659 private final Iterator<? extends E> i = backingSet.iterator(); 1660 1661 @Override 1662 public boolean hasNext() { 1663 return i.hasNext(); 1664 } 1665 1666 @Override 1667 public E next() { 1668 return i.next(); 1669 } 1670 1671 @Override 1672 public void remove() { 1673 throw new UnsupportedOperationException(); 1674 } 1675 }; 1676 } 1677 1678 @Override 1679 public int size() { 1680 return backingSet.size(); 1681 } 1682 1683 @Override 1684 public void addListener(InvalidationListener listener) { 1685 initListener(); 1686 listenerHelper = SetListenerHelper.addListener(listenerHelper, listener); 1687 } 1688 1689 @Override 1690 public void removeListener(InvalidationListener listener) { 1691 listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener); 1692 } 1693 1694 @Override 1695 public void addListener(SetChangeListener<? super E> listener) { 1696 initListener(); 1697 listenerHelper = SetListenerHelper.addListener(listenerHelper, listener); 1698 } 1699 1700 @Override 1701 public void removeListener(SetChangeListener<? super E> listener) { 1702 listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener); 1703 } 1704 1705 @Override 1706 public boolean add(E e) { 1707 throw new UnsupportedOperationException(); 1708 } 1709 1710 @Override 1711 public boolean remove(Object o) { 1712 throw new UnsupportedOperationException(); 1713 } 1714 1715 @Override 1716 public boolean addAll(Collection<? extends E> c) { 1717 throw new UnsupportedOperationException(); 1718 } 1719 1720 @Override 1721 public boolean retainAll(Collection<?> c) { 1722 throw new UnsupportedOperationException(); 1723 } 1724 1725 @Override 1726 public boolean removeAll(Collection<?> c) { 1727 throw new UnsupportedOperationException(); 1728 } 1729 1730 @Override 1731 public void clear() { 1732 throw new UnsupportedOperationException(); 1733 } 1734 } 1735 1736 private static class SynchronizedSet<E> implements Set<E> { 1737 final Object mutex; 1738 private final Set<E> backingSet; 1739 1740 SynchronizedSet(Set<E> set, Object mutex) { 1741 this.backingSet = set; 1742 this.mutex = mutex; 1743 } 1744 1745 SynchronizedSet(Set<E> set) { 1746 this(set, new Object()); 1747 } 1748 1749 @Override 1750 public int size() { 1751 synchronized(mutex) { 1752 return backingSet.size(); 1753 } 1754 } 1755 1756 @Override 1757 public boolean isEmpty() { 1758 synchronized(mutex) { 1759 return backingSet.isEmpty(); 1760 } 1761 } 1762 1763 @Override 1764 public boolean contains(Object o) { 1765 synchronized(mutex) { 1766 return backingSet.contains(o); 1767 } 1768 } 1769 1770 @Override 1771 public Iterator<E> iterator() { 1772 return backingSet.iterator(); 1773 } 1774 1775 @Override 1776 public Object[] toArray() { 1777 synchronized(mutex) { 1778 return backingSet.toArray(); 1779 } 1780 } 1781 1782 @Override 1783 public <E> E[] toArray(E[] a) { 1784 synchronized(mutex) { 1785 return backingSet.toArray(a); 1786 } 1787 } 1788 1789 @Override 1790 public boolean add(E e) { 1791 synchronized(mutex) { 1792 return backingSet.add(e); 1793 } 1794 } 1795 1796 @Override 1797 public boolean remove(Object o) { 1798 synchronized(mutex) { 1799 return backingSet.remove(o); 1800 } 1801 } 1802 1803 @Override 1804 public boolean containsAll(Collection<?> c) { 1805 synchronized(mutex) { 1806 return backingSet.containsAll(c); 1807 } 1808 } 1809 1810 @Override 1811 public boolean addAll(Collection<? extends E> c) { 1812 synchronized(mutex) { 1813 return backingSet.addAll(c); 1814 } 1815 } 1816 1817 @Override 1818 public boolean retainAll(Collection<?> c) { 1819 synchronized(mutex) { 1820 return backingSet.retainAll(c); 1821 } 1822 } 1823 1824 @Override 1825 public boolean removeAll(Collection<?> c) { 1826 synchronized(mutex) { 1827 return backingSet.removeAll(c); 1828 } 1829 } 1830 1831 @Override 1832 public void clear() { 1833 synchronized(mutex) { 1834 backingSet.clear(); 1835 } 1836 } 1837 1838 @Override 1839 public boolean equals(Object o) { 1840 if (o == this) { 1841 return true; 1842 } 1843 synchronized(mutex) { 1844 return backingSet.equals(o); 1845 } 1846 } 1847 1848 @Override 1849 public int hashCode() { 1850 synchronized (mutex) { 1851 return backingSet.hashCode(); 1852 } 1853 } 1854 } 1855 1856 private static class SynchronizedObservableSet<E> extends SynchronizedSet<E> implements ObservableSet<E> { 1857 1858 private final ObservableSet<E> backingSet; 1859 private SetListenerHelper listenerHelper; 1860 private final SetChangeListener<E> listener; 1861 1862 SynchronizedObservableSet(ObservableSet<E> set, Object mutex) { 1863 super(set, mutex); 1864 backingSet = set; 1865 listener = c -> { 1866 SetListenerHelper.fireValueChangedEvent(listenerHelper, new SetAdapterChange<E>(SynchronizedObservableSet.this, c)); 1867 }; 1868 backingSet.addListener(new WeakSetChangeListener<E>(listener)); 1869 } 1870 1871 SynchronizedObservableSet(ObservableSet<E> set) { 1872 this(set, new Object()); 1873 } 1874 1875 @Override 1876 public void addListener(InvalidationListener listener) { 1877 synchronized (mutex) { 1878 listenerHelper = SetListenerHelper.addListener(listenerHelper, listener); 1879 } 1880 } 1881 1882 @Override 1883 public void removeListener(InvalidationListener listener) { 1884 synchronized (mutex) { 1885 listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener); 1886 } 1887 } 1888 @Override 1889 public void addListener(SetChangeListener<? super E> listener) { 1890 synchronized (mutex) { 1891 listenerHelper = SetListenerHelper.addListener(listenerHelper, listener); 1892 } 1893 } 1894 1895 @Override 1896 public void removeListener(SetChangeListener<? super E> listener) { 1897 synchronized (mutex) { 1898 listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener); 1899 } 1900 } 1901 } 1902 1903 private static class CheckedObservableSet<E> extends AbstractSet<E> implements ObservableSet<E> { 1904 1905 private final ObservableSet<E> backingSet; 1906 private final Class<E> type; 1907 private SetListenerHelper listenerHelper; 1908 private final SetChangeListener<E> listener; 1909 1910 CheckedObservableSet(ObservableSet<E> set, Class<E> type) { 1911 if (set == null || type == null) { 1912 throw new NullPointerException(); 1913 } 1914 backingSet = set; 1915 this.type = type; 1916 listener = c -> { 1917 callObservers(new SetAdapterChange<E>(CheckedObservableSet.this, c)); 1918 }; 1919 backingSet.addListener(new WeakSetChangeListener<E>(listener)); 1920 } 1921 1922 private void callObservers(SetChangeListener.Change<? extends E> c) { 1923 SetListenerHelper.fireValueChangedEvent(listenerHelper, c); 1924 } 1925 1926 void typeCheck(Object o) { 1927 if (o != null && !type.isInstance(o)) { 1928 throw new ClassCastException("Attempt to insert " 1929 + o.getClass() + " element into collection with element type " 1930 + type); 1931 } 1932 } 1933 1934 @Override 1935 public void addListener(InvalidationListener listener) { 1936 listenerHelper = SetListenerHelper.addListener(listenerHelper, listener); 1937 } 1938 1939 @Override 1940 public void removeListener(InvalidationListener listener) { 1941 listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener); 1942 } 1943 1944 @Override 1945 public void addListener(SetChangeListener<? super E> listener) { 1946 listenerHelper = SetListenerHelper.addListener(listenerHelper, listener); 1947 } 1948 1949 @Override 1950 public void removeListener(SetChangeListener<? super E> listener) { 1951 listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener); 1952 } 1953 1954 @Override 1955 public int size() { 1956 return backingSet.size(); 1957 } 1958 1959 @Override 1960 public boolean isEmpty() { 1961 return backingSet.isEmpty(); 1962 } 1963 1964 @Override 1965 public boolean contains(Object o) { 1966 return backingSet.contains(o); 1967 } 1968 1969 @Override 1970 public Object[] toArray() { 1971 return backingSet.toArray(); 1972 } 1973 1974 @Override 1975 public <T> T[] toArray(T[] a) { 1976 return backingSet.toArray(a); 1977 } 1978 1979 @Override 1980 public boolean add(E e) { 1981 typeCheck(e); 1982 return backingSet.add(e); 1983 } 1984 1985 @Override 1986 public boolean remove(Object o) { 1987 return backingSet.remove(o); 1988 } 1989 1990 @Override 1991 public boolean containsAll(Collection<?> c) { 1992 return backingSet.containsAll(c); 1993 } 1994 1995 @Override 1996 @SuppressWarnings("unchecked") 1997 public boolean addAll(Collection<? extends E> c) { 1998 E[] a = null; 1999 try { 2000 a = c.toArray((E[]) Array.newInstance(type, 0)); 2001 } catch (ArrayStoreException e) { 2002 throw new ClassCastException(); 2003 } 2004 2005 return backingSet.addAll(Arrays.asList(a)); 2006 } 2007 2008 @Override 2009 public boolean retainAll(Collection<?> c) { 2010 return backingSet.retainAll(c); 2011 } 2012 2013 @Override 2014 public boolean removeAll(Collection<?> c) { 2015 return backingSet.removeAll(c); 2016 } 2017 2018 @Override 2019 public void clear() { 2020 backingSet.clear(); 2021 } 2022 2023 @Override 2024 public boolean equals(Object o) { 2025 return o == this || backingSet.equals(o); 2026 } 2027 2028 @Override 2029 public int hashCode() { 2030 return backingSet.hashCode(); 2031 } 2032 2033 @Override 2034 public Iterator<E> iterator() { 2035 final Iterator<E> it = backingSet.iterator(); 2036 2037 return new Iterator<E>() { 2038 @Override 2039 public boolean hasNext() { 2040 return it.hasNext(); 2041 } 2042 2043 @Override 2044 public E next() { 2045 return it.next(); 2046 } 2047 2048 @Override 2049 public void remove() { 2050 it.remove(); 2051 } 2052 }; 2053 } 2054 2055 } 2056 2057 private static class EmptyObservableMap<K, V> extends AbstractMap<K, V> implements ObservableMap<K, V> { 2058 2059 public EmptyObservableMap() { 2060 } 2061 2062 @Override 2063 public void addListener(InvalidationListener listener) { 2064 } 2065 2066 @Override 2067 public void removeListener(InvalidationListener listener) { 2068 } 2069 2070 @Override 2071 public void addListener(MapChangeListener<? super K, ? super V> listener) { 2072 } 2073 2074 @Override 2075 public void removeListener(MapChangeListener<? super K, ? super V> listener) { 2076 } 2077 2078 @Override 2079 public int size() { 2080 return 0; 2081 } 2082 2083 @Override 2084 public boolean isEmpty() { 2085 return true; 2086 } 2087 2088 @Override 2089 public boolean containsKey(Object key) { 2090 return false; 2091 } 2092 2093 @Override 2094 public boolean containsValue(Object value) { 2095 return false; 2096 } 2097 2098 @Override 2099 public V get(Object key) { 2100 return null; 2101 } 2102 2103 @Override 2104 public Set<K> keySet() { 2105 return emptyObservableSet(); 2106 } 2107 2108 @Override 2109 public Collection<V> values() { 2110 return emptyObservableSet(); 2111 } 2112 2113 @Override 2114 public Set<Map.Entry<K,V>> entrySet() { 2115 return emptyObservableSet(); 2116 } 2117 2118 @Override 2119 public boolean equals(Object o) { 2120 return (o instanceof Map) && ((Map<?,?>)o).isEmpty(); 2121 } 2122 2123 @Override 2124 public int hashCode() { 2125 return 0; 2126 } 2127 } 2128 2129 private static class CheckedObservableMap<K, V> extends AbstractMap<K, V> implements ObservableMap<K, V> { 2130 2131 private final ObservableMap<K, V> backingMap; 2132 private final Class<K> keyType; 2133 private final Class<V> valueType; 2134 private MapListenerHelper listenerHelper; 2135 private final MapChangeListener<K, V> listener; 2136 2137 CheckedObservableMap(ObservableMap<K, V> map, Class<K> keyType, Class<V> valueType) { 2138 backingMap = map; 2139 this.keyType = keyType; 2140 this.valueType = valueType; 2141 listener = c -> { 2142 callObservers(new MapAdapterChange<K, V>(CheckedObservableMap.this, c)); 2143 }; 2144 backingMap.addListener(new WeakMapChangeListener<K, V>(listener)); 2145 } 2146 2147 private void callObservers(MapChangeListener.Change<? extends K, ? extends V> c) { 2148 MapListenerHelper.fireValueChangedEvent(listenerHelper, c); 2149 } 2150 2151 void typeCheck(Object key, Object value) { 2152 if (key != null && !keyType.isInstance(key)) { 2153 throw new ClassCastException("Attempt to insert " 2154 + key.getClass() + " key into map with key type " 2155 + keyType); 2156 } 2157 2158 if (value != null && !valueType.isInstance(value)) { 2159 throw new ClassCastException("Attempt to insert " 2160 + value.getClass() + " value into map with value type " 2161 + valueType); 2162 } 2163 } 2164 2165 @Override 2166 public void addListener(InvalidationListener listener) { 2167 listenerHelper = MapListenerHelper.addListener(listenerHelper, listener); 2168 } 2169 2170 @Override 2171 public void removeListener(InvalidationListener listener) { 2172 listenerHelper = MapListenerHelper.removeListener(listenerHelper, listener); 2173 } 2174 2175 @Override 2176 public void addListener(MapChangeListener<? super K, ? super V> listener) { 2177 listenerHelper = MapListenerHelper.addListener(listenerHelper, listener); 2178 } 2179 2180 @Override 2181 public void removeListener(MapChangeListener<? super K, ? super V> listener) { 2182 listenerHelper = MapListenerHelper.removeListener(listenerHelper, listener); 2183 } 2184 2185 @Override 2186 public int size() { 2187 return backingMap.size(); 2188 } 2189 2190 @Override 2191 public boolean isEmpty() { 2192 return backingMap.isEmpty(); 2193 } 2194 2195 @Override 2196 public boolean containsKey(Object key) { 2197 return backingMap.containsKey(key); 2198 } 2199 2200 @Override 2201 public boolean containsValue(Object value) { 2202 return backingMap.containsValue(value); 2203 } 2204 2205 @Override 2206 public V get(Object key) { 2207 return backingMap.get(key); 2208 } 2209 2210 @Override 2211 public V put(K key, V value) { 2212 typeCheck(key, value); 2213 return backingMap.put(key, value); 2214 } 2215 2216 @Override 2217 public V remove(Object key) { 2218 return backingMap.remove(key); 2219 } 2220 2221 @Override 2222 @SuppressWarnings("unchecked") 2223 public void putAll(Map t) { 2224 // Satisfy the following goals: 2225 // - good diagnostics in case of type mismatch 2226 // - all-or-nothing semantics 2227 // - protection from malicious t 2228 // - correct behavior if t is a concurrent map 2229 Object[] entries = t.entrySet().toArray(); 2230 List<Map.Entry<K,V>> checked = 2231 new ArrayList<Map.Entry<K,V>>(entries.length); 2232 for (Object o : entries) { 2233 Map.Entry<?,?> e = (Map.Entry<?,?>) o; 2234 Object k = e.getKey(); 2235 Object v = e.getValue(); 2236 typeCheck(k, v); 2237 checked.add( 2238 new AbstractMap.SimpleImmutableEntry<K,V>((K) k, (V) v)); 2239 } 2240 for (Map.Entry<K,V> e : checked) 2241 backingMap.put(e.getKey(), e.getValue()); 2242 } 2243 2244 @Override 2245 public void clear() { 2246 backingMap.clear(); 2247 } 2248 2249 @Override 2250 public Set<K> keySet() { 2251 return backingMap.keySet(); 2252 } 2253 2254 @Override 2255 public Collection<V> values() { 2256 return backingMap.values(); 2257 } 2258 2259 private transient Set<Map.Entry<K,V>> entrySet = null; 2260 2261 @Override 2262 public Set entrySet() { 2263 if (entrySet==null) 2264 entrySet = new CheckedEntrySet<K,V>(backingMap.entrySet(), valueType); 2265 return entrySet; 2266 } 2267 2268 @Override 2269 public boolean equals(Object o) { 2270 return o == this || backingMap.equals(o); 2271 } 2272 2273 @Override 2274 public int hashCode() { 2275 return backingMap.hashCode(); 2276 } 2277 2278 static class CheckedEntrySet<K,V> implements Set<Map.Entry<K,V>> { 2279 private final Set<Map.Entry<K,V>> s; 2280 private final Class<V> valueType; 2281 2282 CheckedEntrySet(Set<Map.Entry<K, V>> s, Class<V> valueType) { 2283 this.s = s; 2284 this.valueType = valueType; 2285 } 2286 2287 @Override 2288 public int size() { 2289 return s.size(); 2290 } 2291 2292 @Override 2293 public boolean isEmpty() { 2294 return s.isEmpty(); 2295 } 2296 2297 @Override 2298 public String toString() { 2299 return s.toString(); 2300 } 2301 2302 @Override 2303 public int hashCode() { 2304 return s.hashCode(); 2305 } 2306 2307 @Override 2308 public void clear() { 2309 s.clear(); 2310 } 2311 2312 @Override 2313 public boolean add(Map.Entry<K, V> e) { 2314 throw new UnsupportedOperationException(); 2315 } 2316 2317 @Override 2318 public boolean addAll(Collection<? extends Map.Entry<K, V>> coll) { 2319 throw new UnsupportedOperationException(); 2320 } 2321 2322 @Override 2323 public Iterator<Map.Entry<K,V>> iterator() { 2324 final Iterator<Map.Entry<K, V>> i = s.iterator(); 2325 final Class<V> valueType = this.valueType; 2326 2327 return new Iterator<Map.Entry<K,V>>() { 2328 @Override 2329 public boolean hasNext() { 2330 return i.hasNext(); 2331 } 2332 2333 @Override 2334 public void remove() { 2335 i.remove(); 2336 } 2337 2338 @Override 2339 public Map.Entry<K,V> next() { 2340 return checkedEntry(i.next(), valueType); 2341 } 2342 }; 2343 } 2344 2345 @Override 2346 @SuppressWarnings("unchecked") 2347 public Object[] toArray() { 2348 Object[] source = s.toArray(); 2349 2350 /* 2351 * Ensure that we don't get an ArrayStoreException even if 2352 * s.toArray returns an array of something other than Object 2353 */ 2354 Object[] dest = (CheckedEntry.class.isInstance( 2355 source.getClass().getComponentType()) ? source : 2356 new Object[source.length]); 2357 2358 for (int i = 0; i < source.length; i++) 2359 dest[i] = checkedEntry((Map.Entry<K,V>)source[i], 2360 valueType); 2361 return dest; 2362 } 2363 2364 @Override 2365 @SuppressWarnings("unchecked") 2366 public <T> T[] toArray(T[] a) { 2367 // We don't pass a to s.toArray, to avoid window of 2368 // vulnerability wherein an unscrupulous multithreaded client 2369 // could get his hands on raw (unwrapped) Entries from s. 2370 T[] arr = s.toArray(a.length==0 ? a : Arrays.copyOf(a, 0)); 2371 2372 for (int i=0; i<arr.length; i++) 2373 arr[i] = (T) checkedEntry((Map.Entry<K,V>)arr[i], 2374 valueType); 2375 if (arr.length > a.length) 2376 return arr; 2377 2378 System.arraycopy(arr, 0, a, 0, arr.length); 2379 if (a.length > arr.length) 2380 a[arr.length] = null; 2381 return a; 2382 } 2383 2384 /** 2385 * This method is overridden to protect the backing set against 2386 * an object with a nefarious equals function that senses 2387 * that the equality-candidate is Map.Entry and calls its 2388 * setValue method. 2389 */ 2390 @Override 2391 public boolean contains(Object o) { 2392 if (!(o instanceof Map.Entry)) 2393 return false; 2394 Map.Entry<?,?> e = (Map.Entry<?,?>) o; 2395 return s.contains( 2396 (e instanceof CheckedEntry) ? e : checkedEntry(e, valueType)); 2397 } 2398 2399 /** 2400 * The bulk collection methods are overridden to protect 2401 * against an unscrupulous collection whose contains(Object o) 2402 * method senses when o is a Map.Entry, and calls o.setValue. 2403 */ 2404 @Override 2405 public boolean containsAll(Collection<?> c) { 2406 for (Object o : c) 2407 if (!contains(o)) // Invokes safe contains() above 2408 return false; 2409 return true; 2410 } 2411 2412 @Override 2413 public boolean remove(Object o) { 2414 if (!(o instanceof Map.Entry)) 2415 return false; 2416 return s.remove(new AbstractMap.SimpleImmutableEntry 2417 <Object, Object>((Map.Entry<?,?>)o)); 2418 } 2419 2420 @Override 2421 public boolean removeAll(Collection<?> c) { 2422 return batchRemove(c, false); 2423 } 2424 2425 @Override 2426 public boolean retainAll(Collection<?> c) { 2427 return batchRemove(c, true); 2428 } 2429 2430 private boolean batchRemove(Collection<?> c, boolean complement) { 2431 boolean modified = false; 2432 Iterator<Map.Entry<K,V>> it = iterator(); 2433 while (it.hasNext()) { 2434 if (c.contains(it.next()) != complement) { 2435 it.remove(); 2436 modified = true; 2437 } 2438 } 2439 return modified; 2440 } 2441 2442 @Override 2443 public boolean equals(Object o) { 2444 if (o == this) 2445 return true; 2446 if (!(o instanceof Set)) 2447 return false; 2448 Set<?> that = (Set<?>) o; 2449 return that.size() == s.size() 2450 && containsAll(that); // Invokes safe containsAll() above 2451 } 2452 2453 static <K,V,T> CheckedEntry<K,V,T> checkedEntry(Map.Entry<K,V> e, 2454 Class<T> valueType) { 2455 return new CheckedEntry<K,V,T>(e, valueType); 2456 } 2457 2458 /** 2459 * This "wrapper class" serves two purposes: it prevents 2460 * the client from modifying the backing Map, by short-circuiting 2461 * the setValue method, and it protects the backing Map against 2462 * an ill-behaved Map.Entry that attempts to modify another 2463 * Map.Entry when asked to perform an equality check. 2464 */ 2465 private static class CheckedEntry<K,V,T> implements Map.Entry<K,V> { 2466 private final Map.Entry<K, V> e; 2467 private final Class<T> valueType; 2468 2469 CheckedEntry(Map.Entry<K, V> e, Class<T> valueType) { 2470 this.e = e; 2471 this.valueType = valueType; 2472 } 2473 2474 @Override 2475 public K getKey() { 2476 return e.getKey(); 2477 } 2478 2479 @Override 2480 public V getValue() { 2481 return e.getValue(); 2482 } 2483 2484 @Override 2485 public int hashCode() { 2486 return e.hashCode(); 2487 } 2488 2489 @Override 2490 public String toString() { 2491 return e.toString(); 2492 } 2493 2494 @Override 2495 public V setValue(V value) { 2496 if (value != null && !valueType.isInstance(value)) 2497 throw new ClassCastException(badValueMsg(value)); 2498 return e.setValue(value); 2499 } 2500 2501 private String badValueMsg(Object value) { 2502 return "Attempt to insert " + value.getClass() + 2503 " value into map with value type " + valueType; 2504 } 2505 2506 @Override 2507 public boolean equals(Object o) { 2508 if (o == this) 2509 return true; 2510 if (!(o instanceof Map.Entry)) 2511 return false; 2512 return e.equals(new AbstractMap.SimpleImmutableEntry 2513 <Object, Object>((Map.Entry<?,?>)o)); 2514 } 2515 } 2516 } 2517 2518 } 2519 2520 private static class SynchronizedMap<K, V> implements Map<K, V> { 2521 final Object mutex; 2522 private final Map<K, V> backingMap; 2523 2524 SynchronizedMap(Map<K, V> map, Object mutex) { 2525 backingMap = map; 2526 this.mutex = mutex; 2527 } 2528 2529 SynchronizedMap(Map<K, V> map) { 2530 this(map, new Object()); 2531 } 2532 2533 @Override 2534 public int size() { 2535 synchronized (mutex) { 2536 return backingMap.size(); 2537 } 2538 } 2539 2540 @Override 2541 public boolean isEmpty() { 2542 synchronized (mutex) { 2543 return backingMap.isEmpty(); 2544 } 2545 } 2546 2547 @Override 2548 public boolean containsKey(Object key) { 2549 synchronized (mutex) { 2550 return backingMap.containsKey(key); 2551 } 2552 } 2553 2554 @Override 2555 public boolean containsValue(Object value) { 2556 synchronized (mutex) { 2557 return backingMap.containsValue(value); 2558 } 2559 } 2560 2561 @Override 2562 public V get(Object key) { 2563 synchronized (mutex) { 2564 return backingMap.get(key); 2565 } 2566 } 2567 2568 @Override 2569 public V put(K key, V value) { 2570 synchronized (mutex) { 2571 return backingMap.put(key, value); 2572 } 2573 } 2574 2575 @Override 2576 public V remove(Object key) { 2577 synchronized (mutex) { 2578 return backingMap.remove(key); 2579 } 2580 } 2581 2582 @Override 2583 public void putAll(Map<? extends K, ? extends V> m) { 2584 synchronized (mutex) { 2585 backingMap.putAll(m); 2586 } 2587 } 2588 2589 @Override 2590 public void clear() { 2591 synchronized (mutex) { 2592 backingMap.clear(); 2593 } 2594 } 2595 2596 private transient Set<K> keySet = null; 2597 private transient Set<Map.Entry<K,V>> entrySet = null; 2598 private transient Collection<V> values = null; 2599 2600 @Override 2601 public Set<K> keySet() { 2602 synchronized(mutex) { 2603 if (keySet==null) 2604 keySet = new SynchronizedSet<K>(backingMap.keySet(), mutex); 2605 return keySet; 2606 } 2607 } 2608 2609 @Override 2610 public Collection<V> values() { 2611 synchronized(mutex) { 2612 if (values==null) 2613 values = new SynchronizedCollection<V>(backingMap.values(), mutex); 2614 return values; 2615 } 2616 } 2617 2618 @Override 2619 public Set<Entry<K, V>> entrySet() { 2620 synchronized(mutex) { 2621 if (entrySet==null) 2622 entrySet = new SynchronizedSet<Map.Entry<K,V>>(backingMap.entrySet(), mutex); 2623 return entrySet; 2624 } 2625 } 2626 2627 @Override 2628 public boolean equals(Object o) { 2629 if (o == this) { 2630 return true; 2631 } 2632 synchronized(mutex) { 2633 return backingMap.equals(o); 2634 } 2635 } 2636 2637 @Override 2638 public int hashCode() { 2639 synchronized(mutex) { 2640 return backingMap.hashCode(); 2641 } 2642 } 2643 2644 } 2645 2646 private static class SynchronizedCollection<E> implements Collection<E> { 2647 2648 private final Collection<E> backingCollection; 2649 final Object mutex; 2650 2651 SynchronizedCollection(Collection<E> c, Object mutex) { 2652 backingCollection = c; 2653 this.mutex = mutex; 2654 } 2655 2656 SynchronizedCollection(Collection<E> c) { 2657 this(c, new Object()); 2658 } 2659 2660 @Override 2661 public int size() { 2662 synchronized (mutex) { 2663 return backingCollection.size(); 2664 } 2665 } 2666 2667 @Override 2668 public boolean isEmpty() { 2669 synchronized (mutex) { 2670 return backingCollection.isEmpty(); 2671 } 2672 } 2673 2674 @Override 2675 public boolean contains(Object o) { 2676 synchronized (mutex) { 2677 return backingCollection.contains(o); 2678 } 2679 } 2680 2681 @Override 2682 public Iterator<E> iterator() { 2683 return backingCollection.iterator(); 2684 } 2685 2686 @Override 2687 public Object[] toArray() { 2688 synchronized (mutex) { 2689 return backingCollection.toArray(); 2690 } 2691 } 2692 2693 @Override 2694 public <T> T[] toArray(T[] a) { 2695 synchronized (mutex) { 2696 return backingCollection.toArray(a); 2697 } 2698 } 2699 2700 @Override 2701 public boolean add(E e) { 2702 synchronized (mutex) { 2703 return backingCollection.add(e); 2704 } 2705 } 2706 2707 @Override 2708 public boolean remove(Object o) { 2709 synchronized (mutex) { 2710 return backingCollection.remove(o); 2711 } 2712 } 2713 2714 @Override 2715 public boolean containsAll(Collection<?> c) { 2716 synchronized (mutex) { 2717 return backingCollection.containsAll(c); 2718 } 2719 } 2720 2721 @Override 2722 public boolean addAll(Collection<? extends E> c) { 2723 synchronized (mutex) { 2724 return backingCollection.addAll(c); 2725 } 2726 } 2727 2728 @Override 2729 public boolean removeAll(Collection<?> c) { 2730 synchronized (mutex) { 2731 return backingCollection.removeAll(c); 2732 } 2733 } 2734 2735 @Override 2736 public boolean retainAll(Collection<?> c) { 2737 synchronized (mutex) { 2738 return backingCollection.retainAll(c); 2739 } 2740 } 2741 2742 @Override 2743 public void clear() { 2744 synchronized (mutex) { 2745 backingCollection.clear(); 2746 } 2747 } 2748 } 2749 2750 private static class SynchronizedObservableMap<K, V> extends SynchronizedMap<K, V> implements ObservableMap<K, V> { 2751 2752 private final ObservableMap<K, V> backingMap; 2753 private MapListenerHelper listenerHelper; 2754 private final MapChangeListener<K, V> listener; 2755 2756 SynchronizedObservableMap(ObservableMap<K, V> map, Object mutex) { 2757 super(map, mutex); 2758 backingMap = map; 2759 listener = c -> { 2760 MapListenerHelper.fireValueChangedEvent(listenerHelper, new MapAdapterChange<K, V>(SynchronizedObservableMap.this, c)); 2761 }; 2762 backingMap.addListener(new WeakMapChangeListener<K, V>(listener)); 2763 } 2764 2765 SynchronizedObservableMap(ObservableMap<K, V> map) { 2766 this(map, new Object()); 2767 } 2768 2769 @Override 2770 public void addListener(InvalidationListener listener) { 2771 synchronized (mutex) { 2772 listenerHelper = MapListenerHelper.addListener(listenerHelper, listener); 2773 } 2774 } 2775 2776 @Override 2777 public void removeListener(InvalidationListener listener) { 2778 synchronized (mutex) { 2779 listenerHelper = MapListenerHelper.removeListener(listenerHelper, listener); 2780 } 2781 } 2782 2783 @Override 2784 public void addListener(MapChangeListener<? super K, ? super V> listener) { 2785 synchronized (mutex) { 2786 listenerHelper = MapListenerHelper.addListener(listenerHelper, listener); 2787 } 2788 } 2789 2790 @Override 2791 public void removeListener(MapChangeListener<? super K, ? super V> listener) { 2792 synchronized (mutex) { 2793 listenerHelper = MapListenerHelper.removeListener(listenerHelper, listener); 2794 } 2795 } 2796 2797 } 2798 2799 }