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.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 } 1672 1673 @Override 1674 public int size() { 1675 return backingSet.size(); 1676 } 1677 1678 @Override 1679 public boolean isEmpty() { 1680 return backingSet.isEmpty(); 1681 } 1682 1683 @Override 1684 public boolean contains(Object o) { 1685 return backingSet.contains(o); 1686 } 1687 1688 @Override 1689 public void addListener(InvalidationListener listener) { 1690 initListener(); 1691 listenerHelper = SetListenerHelper.addListener(listenerHelper, listener); 1692 } 1693 1694 @Override 1695 public void removeListener(InvalidationListener listener) { 1696 listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener); 1697 } 1698 1699 @Override 1700 public void addListener(SetChangeListener<? super E> listener) { 1701 initListener(); 1702 listenerHelper = SetListenerHelper.addListener(listenerHelper, listener); 1703 } 1704 1705 @Override 1706 public void removeListener(SetChangeListener<? super E> listener) { 1707 listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener); 1708 } 1709 1710 @Override 1711 public boolean add(E e) { 1712 throw new UnsupportedOperationException(); 1713 } 1714 1715 @Override 1716 public boolean remove(Object o) { 1717 throw new UnsupportedOperationException(); 1718 } 1719 1720 @Override 1721 public boolean addAll(Collection<? extends E> c) { 1722 throw new UnsupportedOperationException(); 1723 } 1724 1725 @Override 1726 public boolean retainAll(Collection<?> c) { 1727 throw new UnsupportedOperationException(); 1728 } 1729 1730 @Override 1731 public boolean removeAll(Collection<?> c) { 1732 throw new UnsupportedOperationException(); 1733 } 1734 1735 @Override 1736 public void clear() { 1737 throw new UnsupportedOperationException(); 1738 } 1739 } 1740 1741 private static class SynchronizedSet<E> implements Set<E> { 1742 final Object mutex; 1743 private final Set<E> backingSet; 1744 1745 SynchronizedSet(Set<E> set, Object mutex) { 1746 this.backingSet = set; 1747 this.mutex = mutex; 1748 } 1749 1750 SynchronizedSet(Set<E> set) { 1751 this(set, new Object()); 1752 } 1753 1754 @Override 1755 public int size() { 1756 synchronized(mutex) { 1757 return backingSet.size(); 1758 } 1759 } 1760 1761 @Override 1762 public boolean isEmpty() { 1763 synchronized(mutex) { 1764 return backingSet.isEmpty(); 1765 } 1766 } 1767 1768 @Override 1769 public boolean contains(Object o) { 1770 synchronized(mutex) { 1771 return backingSet.contains(o); 1772 } 1773 } 1774 1775 @Override 1776 public Iterator<E> iterator() { 1777 return backingSet.iterator(); 1778 } 1779 1780 @Override 1781 public Object[] toArray() { 1782 synchronized(mutex) { 1783 return backingSet.toArray(); 1784 } 1785 } 1786 1787 @Override 1788 public <E> E[] toArray(E[] a) { 1789 synchronized(mutex) { 1790 return backingSet.toArray(a); 1791 } 1792 } 1793 1794 @Override 1795 public boolean add(E e) { 1796 synchronized(mutex) { 1797 return backingSet.add(e); 1798 } 1799 } 1800 1801 @Override 1802 public boolean remove(Object o) { 1803 synchronized(mutex) { 1804 return backingSet.remove(o); 1805 } 1806 } 1807 1808 @Override 1809 public boolean containsAll(Collection<?> c) { 1810 synchronized(mutex) { 1811 return backingSet.containsAll(c); 1812 } 1813 } 1814 1815 @Override 1816 public boolean addAll(Collection<? extends E> c) { 1817 synchronized(mutex) { 1818 return backingSet.addAll(c); 1819 } 1820 } 1821 1822 @Override 1823 public boolean retainAll(Collection<?> c) { 1824 synchronized(mutex) { 1825 return backingSet.retainAll(c); 1826 } 1827 } 1828 1829 @Override 1830 public boolean removeAll(Collection<?> c) { 1831 synchronized(mutex) { 1832 return backingSet.removeAll(c); 1833 } 1834 } 1835 1836 @Override 1837 public void clear() { 1838 synchronized(mutex) { 1839 backingSet.clear(); 1840 } 1841 } 1842 1843 @Override 1844 public boolean equals(Object o) { 1845 if (o == this) { 1846 return true; 1847 } 1848 synchronized(mutex) { 1849 return backingSet.equals(o); 1850 } 1851 } 1852 1853 @Override 1854 public int hashCode() { 1855 synchronized (mutex) { 1856 return backingSet.hashCode(); 1857 } 1858 } 1859 } 1860 1861 private static class SynchronizedObservableSet<E> extends SynchronizedSet<E> implements ObservableSet<E> { 1862 1863 private final ObservableSet<E> backingSet; 1864 private SetListenerHelper listenerHelper; 1865 private final SetChangeListener<E> listener; 1866 1867 SynchronizedObservableSet(ObservableSet<E> set, Object mutex) { 1868 super(set, mutex); 1869 backingSet = set; 1870 listener = c -> { 1871 SetListenerHelper.fireValueChangedEvent(listenerHelper, new SetAdapterChange<E>(SynchronizedObservableSet.this, c)); 1872 }; 1873 backingSet.addListener(new WeakSetChangeListener<E>(listener)); 1874 } 1875 1876 SynchronizedObservableSet(ObservableSet<E> set) { 1877 this(set, new Object()); 1878 } 1879 1880 @Override 1881 public void addListener(InvalidationListener listener) { 1882 synchronized (mutex) { 1883 listenerHelper = SetListenerHelper.addListener(listenerHelper, listener); 1884 } 1885 } 1886 1887 @Override 1888 public void removeListener(InvalidationListener listener) { 1889 synchronized (mutex) { 1890 listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener); 1891 } 1892 } 1893 @Override 1894 public void addListener(SetChangeListener<? super E> listener) { 1895 synchronized (mutex) { 1896 listenerHelper = SetListenerHelper.addListener(listenerHelper, listener); 1897 } 1898 } 1899 1900 @Override 1901 public void removeListener(SetChangeListener<? super E> listener) { 1902 synchronized (mutex) { 1903 listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener); 1904 } 1905 } 1906 } 1907 1908 private static class CheckedObservableSet<E> extends AbstractSet<E> implements ObservableSet<E> { 1909 1910 private final ObservableSet<E> backingSet; 1911 private final Class<E> type; 1912 private SetListenerHelper listenerHelper; 1913 private final SetChangeListener<E> listener; 1914 1915 CheckedObservableSet(ObservableSet<E> set, Class<E> type) { 1916 if (set == null || type == null) { 1917 throw new NullPointerException(); 1918 } 1919 backingSet = set; 1920 this.type = type; 1921 listener = c -> { 1922 callObservers(new SetAdapterChange<E>(CheckedObservableSet.this, c)); 1923 }; 1924 backingSet.addListener(new WeakSetChangeListener<E>(listener)); 1925 } 1926 1927 private void callObservers(SetChangeListener.Change<? extends E> c) { 1928 SetListenerHelper.fireValueChangedEvent(listenerHelper, c); 1929 } 1930 1931 void typeCheck(Object o) { 1932 if (o != null && !type.isInstance(o)) { 1933 throw new ClassCastException("Attempt to insert " 1934 + o.getClass() + " element into collection with element type " 1935 + type); 1936 } 1937 } 1938 1939 @Override 1940 public void addListener(InvalidationListener listener) { 1941 listenerHelper = SetListenerHelper.addListener(listenerHelper, listener); 1942 } 1943 1944 @Override 1945 public void removeListener(InvalidationListener listener) { 1946 listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener); 1947 } 1948 1949 @Override 1950 public void addListener(SetChangeListener<? super E> listener) { 1951 listenerHelper = SetListenerHelper.addListener(listenerHelper, listener); 1952 } 1953 1954 @Override 1955 public void removeListener(SetChangeListener<? super E> listener) { 1956 listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener); 1957 } 1958 1959 @Override 1960 public int size() { 1961 return backingSet.size(); 1962 } 1963 1964 @Override 1965 public boolean isEmpty() { 1966 return backingSet.isEmpty(); 1967 } 1968 1969 @Override 1970 public boolean contains(Object o) { 1971 return backingSet.contains(o); 1972 } 1973 1974 @Override 1975 public Object[] toArray() { 1976 return backingSet.toArray(); 1977 } 1978 1979 @Override 1980 public <T> T[] toArray(T[] a) { 1981 return backingSet.toArray(a); 1982 } 1983 1984 @Override 1985 public boolean add(E e) { 1986 typeCheck(e); 1987 return backingSet.add(e); 1988 } 1989 1990 @Override 1991 public boolean remove(Object o) { 1992 return backingSet.remove(o); 1993 } 1994 1995 @Override 1996 public boolean containsAll(Collection<?> c) { 1997 return backingSet.containsAll(c); 1998 } 1999 2000 @Override 2001 @SuppressWarnings("unchecked") 2002 public boolean addAll(Collection<? extends E> c) { 2003 E[] a = null; 2004 try { 2005 a = c.toArray((E[]) Array.newInstance(type, 0)); 2006 } catch (ArrayStoreException e) { 2007 throw new ClassCastException(); 2008 } 2009 2010 return backingSet.addAll(Arrays.asList(a)); 2011 } 2012 2013 @Override 2014 public boolean retainAll(Collection<?> c) { 2015 return backingSet.retainAll(c); 2016 } 2017 2018 @Override 2019 public boolean removeAll(Collection<?> c) { 2020 return backingSet.removeAll(c); 2021 } 2022 2023 @Override 2024 public void clear() { 2025 backingSet.clear(); 2026 } 2027 2028 @Override 2029 public boolean equals(Object o) { 2030 return o == this || backingSet.equals(o); 2031 } 2032 2033 @Override 2034 public int hashCode() { 2035 return backingSet.hashCode(); 2036 } 2037 2038 @Override 2039 public Iterator<E> iterator() { 2040 final Iterator<E> it = backingSet.iterator(); 2041 2042 return new Iterator<E>() { 2043 @Override 2044 public boolean hasNext() { 2045 return it.hasNext(); 2046 } 2047 2048 @Override 2049 public E next() { 2050 return it.next(); 2051 } 2052 2053 @Override 2054 public void remove() { 2055 it.remove(); 2056 } 2057 }; 2058 } 2059 2060 } 2061 2062 private static class EmptyObservableMap<K, V> extends AbstractMap<K, V> implements ObservableMap<K, V> { 2063 2064 public EmptyObservableMap() { 2065 } 2066 2067 @Override 2068 public void addListener(InvalidationListener listener) { 2069 } 2070 2071 @Override 2072 public void removeListener(InvalidationListener listener) { 2073 } 2074 2075 @Override 2076 public void addListener(MapChangeListener<? super K, ? super V> listener) { 2077 } 2078 2079 @Override 2080 public void removeListener(MapChangeListener<? super K, ? super V> listener) { 2081 } 2082 2083 @Override 2084 public int size() { 2085 return 0; 2086 } 2087 2088 @Override 2089 public boolean isEmpty() { 2090 return true; 2091 } 2092 2093 @Override 2094 public boolean containsKey(Object key) { 2095 return false; 2096 } 2097 2098 @Override 2099 public boolean containsValue(Object value) { 2100 return false; 2101 } 2102 2103 @Override 2104 public V get(Object key) { 2105 return null; 2106 } 2107 2108 @Override 2109 public Set<K> keySet() { 2110 return emptyObservableSet(); 2111 } 2112 2113 @Override 2114 public Collection<V> values() { 2115 return emptyObservableSet(); 2116 } 2117 2118 @Override 2119 public Set<Map.Entry<K,V>> entrySet() { 2120 return emptyObservableSet(); 2121 } 2122 2123 @Override 2124 public boolean equals(Object o) { 2125 return (o instanceof Map) && ((Map<?,?>)o).isEmpty(); 2126 } 2127 2128 @Override 2129 public int hashCode() { 2130 return 0; 2131 } 2132 } 2133 2134 private static class CheckedObservableMap<K, V> extends AbstractMap<K, V> implements ObservableMap<K, V> { 2135 2136 private final ObservableMap<K, V> backingMap; 2137 private final Class<K> keyType; 2138 private final Class<V> valueType; 2139 private MapListenerHelper listenerHelper; 2140 private final MapChangeListener<K, V> listener; 2141 2142 CheckedObservableMap(ObservableMap<K, V> map, Class<K> keyType, Class<V> valueType) { 2143 backingMap = map; 2144 this.keyType = keyType; 2145 this.valueType = valueType; 2146 listener = c -> { 2147 callObservers(new MapAdapterChange<K, V>(CheckedObservableMap.this, c)); 2148 }; 2149 backingMap.addListener(new WeakMapChangeListener<K, V>(listener)); 2150 } 2151 2152 private void callObservers(MapChangeListener.Change<? extends K, ? extends V> c) { 2153 MapListenerHelper.fireValueChangedEvent(listenerHelper, c); 2154 } 2155 2156 void typeCheck(Object key, Object value) { 2157 if (key != null && !keyType.isInstance(key)) { 2158 throw new ClassCastException("Attempt to insert " 2159 + key.getClass() + " key into map with key type " 2160 + keyType); 2161 } 2162 2163 if (value != null && !valueType.isInstance(value)) { 2164 throw new ClassCastException("Attempt to insert " 2165 + value.getClass() + " value into map with value type " 2166 + valueType); 2167 } 2168 } 2169 2170 @Override 2171 public void addListener(InvalidationListener listener) { 2172 listenerHelper = MapListenerHelper.addListener(listenerHelper, listener); 2173 } 2174 2175 @Override 2176 public void removeListener(InvalidationListener listener) { 2177 listenerHelper = MapListenerHelper.removeListener(listenerHelper, listener); 2178 } 2179 2180 @Override 2181 public void addListener(MapChangeListener<? super K, ? super V> listener) { 2182 listenerHelper = MapListenerHelper.addListener(listenerHelper, listener); 2183 } 2184 2185 @Override 2186 public void removeListener(MapChangeListener<? super K, ? super V> listener) { 2187 listenerHelper = MapListenerHelper.removeListener(listenerHelper, listener); 2188 } 2189 2190 @Override 2191 public int size() { 2192 return backingMap.size(); 2193 } 2194 2195 @Override 2196 public boolean isEmpty() { 2197 return backingMap.isEmpty(); 2198 } 2199 2200 @Override 2201 public boolean containsKey(Object key) { 2202 return backingMap.containsKey(key); 2203 } 2204 2205 @Override 2206 public boolean containsValue(Object value) { 2207 return backingMap.containsValue(value); 2208 } 2209 2210 @Override 2211 public V get(Object key) { 2212 return backingMap.get(key); 2213 } 2214 2215 @Override 2216 public V put(K key, V value) { 2217 typeCheck(key, value); 2218 return backingMap.put(key, value); 2219 } 2220 2221 @Override 2222 public V remove(Object key) { 2223 return backingMap.remove(key); 2224 } 2225 2226 @Override 2227 @SuppressWarnings("unchecked") 2228 public void putAll(Map t) { 2229 // Satisfy the following goals: 2230 // - good diagnostics in case of type mismatch 2231 // - all-or-nothing semantics 2232 // - protection from malicious t 2233 // - correct behavior if t is a concurrent map 2234 Object[] entries = t.entrySet().toArray(); 2235 List<Map.Entry<K,V>> checked = 2236 new ArrayList<Map.Entry<K,V>>(entries.length); 2237 for (Object o : entries) { 2238 Map.Entry<?,?> e = (Map.Entry<?,?>) o; 2239 Object k = e.getKey(); 2240 Object v = e.getValue(); 2241 typeCheck(k, v); 2242 checked.add( 2243 new AbstractMap.SimpleImmutableEntry<K,V>((K) k, (V) v)); 2244 } 2245 for (Map.Entry<K,V> e : checked) 2246 backingMap.put(e.getKey(), e.getValue()); 2247 } 2248 2249 @Override 2250 public void clear() { 2251 backingMap.clear(); 2252 } 2253 2254 @Override 2255 public Set<K> keySet() { 2256 return backingMap.keySet(); 2257 } 2258 2259 @Override 2260 public Collection<V> values() { 2261 return backingMap.values(); 2262 } 2263 2264 private transient Set<Map.Entry<K,V>> entrySet = null; 2265 2266 @Override 2267 public Set entrySet() { 2268 if (entrySet==null) 2269 entrySet = new CheckedEntrySet<K,V>(backingMap.entrySet(), valueType); 2270 return entrySet; 2271 } 2272 2273 @Override 2274 public boolean equals(Object o) { 2275 return o == this || backingMap.equals(o); 2276 } 2277 2278 @Override 2279 public int hashCode() { 2280 return backingMap.hashCode(); 2281 } 2282 2283 static class CheckedEntrySet<K,V> implements Set<Map.Entry<K,V>> { 2284 private final Set<Map.Entry<K,V>> s; 2285 private final Class<V> valueType; 2286 2287 CheckedEntrySet(Set<Map.Entry<K, V>> s, Class<V> valueType) { 2288 this.s = s; 2289 this.valueType = valueType; 2290 } 2291 2292 @Override 2293 public int size() { 2294 return s.size(); 2295 } 2296 2297 @Override 2298 public boolean isEmpty() { 2299 return s.isEmpty(); 2300 } 2301 2302 @Override 2303 public String toString() { 2304 return s.toString(); 2305 } 2306 2307 @Override 2308 public int hashCode() { 2309 return s.hashCode(); 2310 } 2311 2312 @Override 2313 public void clear() { 2314 s.clear(); 2315 } 2316 2317 @Override 2318 public boolean add(Map.Entry<K, V> e) { 2319 throw new UnsupportedOperationException(); 2320 } 2321 2322 @Override 2323 public boolean addAll(Collection<? extends Map.Entry<K, V>> coll) { 2324 throw new UnsupportedOperationException(); 2325 } 2326 2327 @Override 2328 public Iterator<Map.Entry<K,V>> iterator() { 2329 final Iterator<Map.Entry<K, V>> i = s.iterator(); 2330 final Class<V> valueType = this.valueType; 2331 2332 return new Iterator<Map.Entry<K,V>>() { 2333 @Override 2334 public boolean hasNext() { 2335 return i.hasNext(); 2336 } 2337 2338 @Override 2339 public void remove() { 2340 i.remove(); 2341 } 2342 2343 @Override 2344 public Map.Entry<K,V> next() { 2345 return checkedEntry(i.next(), valueType); 2346 } 2347 }; 2348 } 2349 2350 @Override 2351 @SuppressWarnings("unchecked") 2352 public Object[] toArray() { 2353 Object[] source = s.toArray(); 2354 2355 /* 2356 * Ensure that we don't get an ArrayStoreException even if 2357 * s.toArray returns an array of something other than Object 2358 */ 2359 Object[] dest = (CheckedEntry.class.isInstance( 2360 source.getClass().getComponentType()) ? source : 2361 new Object[source.length]); 2362 2363 for (int i = 0; i < source.length; i++) 2364 dest[i] = checkedEntry((Map.Entry<K,V>)source[i], 2365 valueType); 2366 return dest; 2367 } 2368 2369 @Override 2370 @SuppressWarnings("unchecked") 2371 public <T> T[] toArray(T[] a) { 2372 // We don't pass a to s.toArray, to avoid window of 2373 // vulnerability wherein an unscrupulous multithreaded client 2374 // could get his hands on raw (unwrapped) Entries from s. 2375 T[] arr = s.toArray(a.length==0 ? a : Arrays.copyOf(a, 0)); 2376 2377 for (int i=0; i<arr.length; i++) 2378 arr[i] = (T) checkedEntry((Map.Entry<K,V>)arr[i], 2379 valueType); 2380 if (arr.length > a.length) 2381 return arr; 2382 2383 System.arraycopy(arr, 0, a, 0, arr.length); 2384 if (a.length > arr.length) 2385 a[arr.length] = null; 2386 return a; 2387 } 2388 2389 /** 2390 * This method is overridden to protect the backing set against 2391 * an object with a nefarious equals function that senses 2392 * that the equality-candidate is Map.Entry and calls its 2393 * setValue method. 2394 */ 2395 @Override 2396 public boolean contains(Object o) { 2397 if (!(o instanceof Map.Entry)) 2398 return false; 2399 Map.Entry<?,?> e = (Map.Entry<?,?>) o; 2400 return s.contains( 2401 (e instanceof CheckedEntry) ? e : checkedEntry(e, valueType)); 2402 } 2403 2404 /** 2405 * The bulk collection methods are overridden to protect 2406 * against an unscrupulous collection whose contains(Object o) 2407 * method senses when o is a Map.Entry, and calls o.setValue. 2408 */ 2409 @Override 2410 public boolean containsAll(Collection<?> c) { 2411 for (Object o : c) 2412 if (!contains(o)) // Invokes safe contains() above 2413 return false; 2414 return true; 2415 } 2416 2417 @Override 2418 public boolean remove(Object o) { 2419 if (!(o instanceof Map.Entry)) 2420 return false; 2421 return s.remove(new AbstractMap.SimpleImmutableEntry 2422 <Object, Object>((Map.Entry<?,?>)o)); 2423 } 2424 2425 @Override 2426 public boolean removeAll(Collection<?> c) { 2427 return batchRemove(c, false); 2428 } 2429 2430 @Override 2431 public boolean retainAll(Collection<?> c) { 2432 return batchRemove(c, true); 2433 } 2434 2435 private boolean batchRemove(Collection<?> c, boolean complement) { 2436 boolean modified = false; 2437 Iterator<Map.Entry<K,V>> it = iterator(); 2438 while (it.hasNext()) { 2439 if (c.contains(it.next()) != complement) { 2440 it.remove(); 2441 modified = true; 2442 } 2443 } 2444 return modified; 2445 } 2446 2447 @Override 2448 public boolean equals(Object o) { 2449 if (o == this) 2450 return true; 2451 if (!(o instanceof Set)) 2452 return false; 2453 Set<?> that = (Set<?>) o; 2454 return that.size() == s.size() 2455 && containsAll(that); // Invokes safe containsAll() above 2456 } 2457 2458 static <K,V,T> CheckedEntry<K,V,T> checkedEntry(Map.Entry<K,V> e, 2459 Class<T> valueType) { 2460 return new CheckedEntry<K,V,T>(e, valueType); 2461 } 2462 2463 /** 2464 * This "wrapper class" serves two purposes: it prevents 2465 * the client from modifying the backing Map, by short-circuiting 2466 * the setValue method, and it protects the backing Map against 2467 * an ill-behaved Map.Entry that attempts to modify another 2468 * Map.Entry when asked to perform an equality check. 2469 */ 2470 private static class CheckedEntry<K,V,T> implements Map.Entry<K,V> { 2471 private final Map.Entry<K, V> e; 2472 private final Class<T> valueType; 2473 2474 CheckedEntry(Map.Entry<K, V> e, Class<T> valueType) { 2475 this.e = e; 2476 this.valueType = valueType; 2477 } 2478 2479 @Override 2480 public K getKey() { 2481 return e.getKey(); 2482 } 2483 2484 @Override 2485 public V getValue() { 2486 return e.getValue(); 2487 } 2488 2489 @Override 2490 public int hashCode() { 2491 return e.hashCode(); 2492 } 2493 2494 @Override 2495 public String toString() { 2496 return e.toString(); 2497 } 2498 2499 @Override 2500 public V setValue(V value) { 2501 if (value != null && !valueType.isInstance(value)) 2502 throw new ClassCastException(badValueMsg(value)); 2503 return e.setValue(value); 2504 } 2505 2506 private String badValueMsg(Object value) { 2507 return "Attempt to insert " + value.getClass() + 2508 " value into map with value type " + valueType; 2509 } 2510 2511 @Override 2512 public boolean equals(Object o) { 2513 if (o == this) 2514 return true; 2515 if (!(o instanceof Map.Entry)) 2516 return false; 2517 return e.equals(new AbstractMap.SimpleImmutableEntry 2518 <Object, Object>((Map.Entry<?,?>)o)); 2519 } 2520 } 2521 } 2522 2523 } 2524 2525 private static class SynchronizedMap<K, V> implements Map<K, V> { 2526 final Object mutex; 2527 private final Map<K, V> backingMap; 2528 2529 SynchronizedMap(Map<K, V> map, Object mutex) { 2530 backingMap = map; 2531 this.mutex = mutex; 2532 } 2533 2534 SynchronizedMap(Map<K, V> map) { 2535 this(map, new Object()); 2536 } 2537 2538 @Override 2539 public int size() { 2540 synchronized (mutex) { 2541 return backingMap.size(); 2542 } 2543 } 2544 2545 @Override 2546 public boolean isEmpty() { 2547 synchronized (mutex) { 2548 return backingMap.isEmpty(); 2549 } 2550 } 2551 2552 @Override 2553 public boolean containsKey(Object key) { 2554 synchronized (mutex) { 2555 return backingMap.containsKey(key); 2556 } 2557 } 2558 2559 @Override 2560 public boolean containsValue(Object value) { 2561 synchronized (mutex) { 2562 return backingMap.containsValue(value); 2563 } 2564 } 2565 2566 @Override 2567 public V get(Object key) { 2568 synchronized (mutex) { 2569 return backingMap.get(key); 2570 } 2571 } 2572 2573 @Override 2574 public V put(K key, V value) { 2575 synchronized (mutex) { 2576 return backingMap.put(key, value); 2577 } 2578 } 2579 2580 @Override 2581 public V remove(Object key) { 2582 synchronized (mutex) { 2583 return backingMap.remove(key); 2584 } 2585 } 2586 2587 @Override 2588 public void putAll(Map<? extends K, ? extends V> m) { 2589 synchronized (mutex) { 2590 backingMap.putAll(m); 2591 } 2592 } 2593 2594 @Override 2595 public void clear() { 2596 synchronized (mutex) { 2597 backingMap.clear(); 2598 } 2599 } 2600 2601 private transient Set<K> keySet = null; 2602 private transient Set<Map.Entry<K,V>> entrySet = null; 2603 private transient Collection<V> values = null; 2604 2605 @Override 2606 public Set<K> keySet() { 2607 synchronized(mutex) { 2608 if (keySet==null) 2609 keySet = new SynchronizedSet<K>(backingMap.keySet(), mutex); 2610 return keySet; 2611 } 2612 } 2613 2614 @Override 2615 public Collection<V> values() { 2616 synchronized(mutex) { 2617 if (values==null) 2618 values = new SynchronizedCollection<V>(backingMap.values(), mutex); 2619 return values; 2620 } 2621 } 2622 2623 @Override 2624 public Set<Entry<K, V>> entrySet() { 2625 synchronized(mutex) { 2626 if (entrySet==null) 2627 entrySet = new SynchronizedSet<Map.Entry<K,V>>(backingMap.entrySet(), mutex); 2628 return entrySet; 2629 } 2630 } 2631 2632 @Override 2633 public boolean equals(Object o) { 2634 if (o == this) { 2635 return true; 2636 } 2637 synchronized(mutex) { 2638 return backingMap.equals(o); 2639 } 2640 } 2641 2642 @Override 2643 public int hashCode() { 2644 synchronized(mutex) { 2645 return backingMap.hashCode(); 2646 } 2647 } 2648 2649 } 2650 2651 private static class SynchronizedCollection<E> implements Collection<E> { 2652 2653 private final Collection<E> backingCollection; 2654 final Object mutex; 2655 2656 SynchronizedCollection(Collection<E> c, Object mutex) { 2657 backingCollection = c; 2658 this.mutex = mutex; 2659 } 2660 2661 SynchronizedCollection(Collection<E> c) { 2662 this(c, new Object()); 2663 } 2664 2665 @Override 2666 public int size() { 2667 synchronized (mutex) { 2668 return backingCollection.size(); 2669 } 2670 } 2671 2672 @Override 2673 public boolean isEmpty() { 2674 synchronized (mutex) { 2675 return backingCollection.isEmpty(); 2676 } 2677 } 2678 2679 @Override 2680 public boolean contains(Object o) { 2681 synchronized (mutex) { 2682 return backingCollection.contains(o); 2683 } 2684 } 2685 2686 @Override 2687 public Iterator<E> iterator() { 2688 return backingCollection.iterator(); 2689 } 2690 2691 @Override 2692 public Object[] toArray() { 2693 synchronized (mutex) { 2694 return backingCollection.toArray(); 2695 } 2696 } 2697 2698 @Override 2699 public <T> T[] toArray(T[] a) { 2700 synchronized (mutex) { 2701 return backingCollection.toArray(a); 2702 } 2703 } 2704 2705 @Override 2706 public boolean add(E e) { 2707 synchronized (mutex) { 2708 return backingCollection.add(e); 2709 } 2710 } 2711 2712 @Override 2713 public boolean remove(Object o) { 2714 synchronized (mutex) { 2715 return backingCollection.remove(o); 2716 } 2717 } 2718 2719 @Override 2720 public boolean containsAll(Collection<?> c) { 2721 synchronized (mutex) { 2722 return backingCollection.containsAll(c); 2723 } 2724 } 2725 2726 @Override 2727 public boolean addAll(Collection<? extends E> c) { 2728 synchronized (mutex) { 2729 return backingCollection.addAll(c); 2730 } 2731 } 2732 2733 @Override 2734 public boolean removeAll(Collection<?> c) { 2735 synchronized (mutex) { 2736 return backingCollection.removeAll(c); 2737 } 2738 } 2739 2740 @Override 2741 public boolean retainAll(Collection<?> c) { 2742 synchronized (mutex) { 2743 return backingCollection.retainAll(c); 2744 } 2745 } 2746 2747 @Override 2748 public void clear() { 2749 synchronized (mutex) { 2750 backingCollection.clear(); 2751 } 2752 } 2753 } 2754 2755 private static class SynchronizedObservableMap<K, V> extends SynchronizedMap<K, V> implements ObservableMap<K, V> { 2756 2757 private final ObservableMap<K, V> backingMap; 2758 private MapListenerHelper listenerHelper; 2759 private final MapChangeListener<K, V> listener; 2760 2761 SynchronizedObservableMap(ObservableMap<K, V> map, Object mutex) { 2762 super(map, mutex); 2763 backingMap = map; 2764 listener = c -> { 2765 MapListenerHelper.fireValueChangedEvent(listenerHelper, new MapAdapterChange<K, V>(SynchronizedObservableMap.this, c)); 2766 }; 2767 backingMap.addListener(new WeakMapChangeListener<K, V>(listener)); 2768 } 2769 2770 SynchronizedObservableMap(ObservableMap<K, V> map) { 2771 this(map, new Object()); 2772 } 2773 2774 @Override 2775 public void addListener(InvalidationListener listener) { 2776 synchronized (mutex) { 2777 listenerHelper = MapListenerHelper.addListener(listenerHelper, listener); 2778 } 2779 } 2780 2781 @Override 2782 public void removeListener(InvalidationListener listener) { 2783 synchronized (mutex) { 2784 listenerHelper = MapListenerHelper.removeListener(listenerHelper, listener); 2785 } 2786 } 2787 2788 @Override 2789 public void addListener(MapChangeListener<? super K, ? super V> listener) { 2790 synchronized (mutex) { 2791 listenerHelper = MapListenerHelper.addListener(listenerHelper, listener); 2792 } 2793 } 2794 2795 @Override 2796 public void removeListener(MapChangeListener<? super K, ? super V> listener) { 2797 synchronized (mutex) { 2798 listenerHelper = MapListenerHelper.removeListener(listenerHelper, listener); 2799 } 2800 } 2801 2802 } 2803 2804 }