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