| 1 | // License: GPL. For details, see LICENSE file. |
|---|
| 2 | package org.openstreetmap.josm.tools; |
|---|
| 3 | |
|---|
| 4 | import java.awt.Color; |
|---|
| 5 | import java.awt.Toolkit; |
|---|
| 6 | import java.awt.datatransfer.Clipboard; |
|---|
| 7 | import java.awt.datatransfer.ClipboardOwner; |
|---|
| 8 | import java.awt.datatransfer.DataFlavor; |
|---|
| 9 | import java.awt.datatransfer.StringSelection; |
|---|
| 10 | import java.awt.datatransfer.Transferable; |
|---|
| 11 | import java.awt.datatransfer.UnsupportedFlavorException; |
|---|
| 12 | import java.io.File; |
|---|
| 13 | import java.io.IOException; |
|---|
| 14 | import java.io.InputStream; |
|---|
| 15 | import java.io.OutputStream; |
|---|
| 16 | import java.io.Reader; |
|---|
| 17 | import java.io.UnsupportedEncodingException; |
|---|
| 18 | import java.security.MessageDigest; |
|---|
| 19 | import java.security.NoSuchAlgorithmException; |
|---|
| 20 | import java.text.MessageFormat; |
|---|
| 21 | import java.util.ArrayList; |
|---|
| 22 | import java.util.Collection; |
|---|
| 23 | import java.util.Iterator; |
|---|
| 24 | import java.util.List; |
|---|
| 25 | |
|---|
| 26 | /** |
|---|
| 27 | * Basic utils, that can be useful in different parts of the program. |
|---|
| 28 | */ |
|---|
| 29 | public class Utils { |
|---|
| 30 | |
|---|
| 31 | public static <T> boolean exists(Iterable<? extends T> collection, Predicate<? super T> predicate) { |
|---|
| 32 | for (T item : collection) { |
|---|
| 33 | if (predicate.evaluate(item)) |
|---|
| 34 | return true; |
|---|
| 35 | } |
|---|
| 36 | return false; |
|---|
| 37 | } |
|---|
| 38 | |
|---|
| 39 | public static <T> boolean exists(Iterable<T> collection, Class<? extends T> klass) { |
|---|
| 40 | for (Object item : collection) { |
|---|
| 41 | if (klass.isInstance(item)) |
|---|
| 42 | return true; |
|---|
| 43 | } |
|---|
| 44 | return false; |
|---|
| 45 | } |
|---|
| 46 | |
|---|
| 47 | public static <T> T find(Iterable<? extends T> collection, Predicate<? super T> predicate) { |
|---|
| 48 | for (T item : collection) { |
|---|
| 49 | if (predicate.evaluate(item)) |
|---|
| 50 | return item; |
|---|
| 51 | } |
|---|
| 52 | return null; |
|---|
| 53 | } |
|---|
| 54 | |
|---|
| 55 | @SuppressWarnings("unchecked") |
|---|
| 56 | public static <T> T find(Iterable<? super T> collection, Class<? extends T> klass) { |
|---|
| 57 | for (Object item : collection) { |
|---|
| 58 | if (klass.isInstance(item)) |
|---|
| 59 | return (T) item; |
|---|
| 60 | } |
|---|
| 61 | return null; |
|---|
| 62 | } |
|---|
| 63 | |
|---|
| 64 | public static <T> Collection<T> filter(Collection<? extends T> collection, Predicate<? super T> predicate) { |
|---|
| 65 | return new FilteredCollection<T>(collection, predicate); |
|---|
| 66 | } |
|---|
| 67 | |
|---|
| 68 | public static <T> T firstNonNull(T... items) { |
|---|
| 69 | for (T i : items) { |
|---|
| 70 | if (i != null) { |
|---|
| 71 | return i; |
|---|
| 72 | } |
|---|
| 73 | } |
|---|
| 74 | return null; |
|---|
| 75 | } |
|---|
| 76 | |
|---|
| 77 | /** |
|---|
| 78 | * Filter a collection by (sub)class. |
|---|
| 79 | * This is an efficient read-only implementation. |
|---|
| 80 | */ |
|---|
| 81 | public static <S, T extends S> SubclassFilteredCollection<S, T> filteredCollection(Collection<S> collection, final Class<T> klass) { |
|---|
| 82 | return new SubclassFilteredCollection<S, T>(collection, new Predicate<S>() { |
|---|
| 83 | @Override |
|---|
| 84 | public boolean evaluate(S o) { |
|---|
| 85 | return klass.isInstance(o); |
|---|
| 86 | } |
|---|
| 87 | }); |
|---|
| 88 | } |
|---|
| 89 | |
|---|
| 90 | public static <T> int indexOf(Iterable<? extends T> collection, Predicate<? super T> predicate) { |
|---|
| 91 | int i = 0; |
|---|
| 92 | for (T item : collection) { |
|---|
| 93 | if (predicate.evaluate(item)) |
|---|
| 94 | return i; |
|---|
| 95 | i++; |
|---|
| 96 | } |
|---|
| 97 | return -1; |
|---|
| 98 | } |
|---|
| 99 | |
|---|
| 100 | /** |
|---|
| 101 | * Get minimum of 3 values |
|---|
| 102 | */ |
|---|
| 103 | public static int min(int a, int b, int c) { |
|---|
| 104 | if (b < c) { |
|---|
| 105 | if (a < b) |
|---|
| 106 | return a; |
|---|
| 107 | return b; |
|---|
| 108 | } else { |
|---|
| 109 | if (a < c) |
|---|
| 110 | return a; |
|---|
| 111 | return c; |
|---|
| 112 | } |
|---|
| 113 | } |
|---|
| 114 | |
|---|
| 115 | public static int max(int a, int b, int c, int d) { |
|---|
| 116 | return Math.max(Math.max(a, b), Math.max(c, d)); |
|---|
| 117 | } |
|---|
| 118 | |
|---|
| 119 | /** |
|---|
| 120 | * for convenience: test whether 2 objects are either both null or a.equals(b) |
|---|
| 121 | */ |
|---|
| 122 | public static <T> boolean equal(T a, T b) { |
|---|
| 123 | if (a == b) |
|---|
| 124 | return true; |
|---|
| 125 | return (a != null && a.equals(b)); |
|---|
| 126 | } |
|---|
| 127 | |
|---|
| 128 | public static void ensure(boolean condition, String message, Object...data) { |
|---|
| 129 | if (!condition) |
|---|
| 130 | throw new AssertionError( |
|---|
| 131 | MessageFormat.format(message,data) |
|---|
| 132 | ); |
|---|
| 133 | } |
|---|
| 134 | |
|---|
| 135 | /** |
|---|
| 136 | * return the modulus in the range [0, n) |
|---|
| 137 | */ |
|---|
| 138 | public static int mod(int a, int n) { |
|---|
| 139 | if (n <= 0) |
|---|
| 140 | throw new IllegalArgumentException(); |
|---|
| 141 | int res = a % n; |
|---|
| 142 | if (res < 0) { |
|---|
| 143 | res += n; |
|---|
| 144 | } |
|---|
| 145 | return res; |
|---|
| 146 | } |
|---|
| 147 | |
|---|
| 148 | /** |
|---|
| 149 | * Joins a list of strings (or objects that can be converted to string via |
|---|
| 150 | * Object.toString()) into a single string with fields separated by sep. |
|---|
| 151 | * @param sep the separator |
|---|
| 152 | * @param values collection of objects, null is converted to the |
|---|
| 153 | * empty string |
|---|
| 154 | * @return null if values is null. The joined string otherwise. |
|---|
| 155 | */ |
|---|
| 156 | public static String join(String sep, Collection<?> values) { |
|---|
| 157 | if (sep == null) |
|---|
| 158 | throw new IllegalArgumentException(); |
|---|
| 159 | if (values == null) |
|---|
| 160 | return null; |
|---|
| 161 | if (values.isEmpty()) |
|---|
| 162 | return ""; |
|---|
| 163 | StringBuilder s = null; |
|---|
| 164 | for (Object a : values) { |
|---|
| 165 | if (a == null) { |
|---|
| 166 | a = ""; |
|---|
| 167 | } |
|---|
| 168 | if (s != null) { |
|---|
| 169 | s.append(sep).append(a.toString()); |
|---|
| 170 | } else { |
|---|
| 171 | s = new StringBuilder(a.toString()); |
|---|
| 172 | } |
|---|
| 173 | } |
|---|
| 174 | return s.toString(); |
|---|
| 175 | } |
|---|
| 176 | |
|---|
| 177 | public static String joinAsHtmlUnorderedList(Collection<?> values) { |
|---|
| 178 | StringBuilder sb = new StringBuilder(1024); |
|---|
| 179 | sb.append("<ul>"); |
|---|
| 180 | for (Object i : values) { |
|---|
| 181 | sb.append("<li>").append(i).append("</li>"); |
|---|
| 182 | } |
|---|
| 183 | sb.append("</ul>"); |
|---|
| 184 | return sb.toString(); |
|---|
| 185 | } |
|---|
| 186 | |
|---|
| 187 | /** |
|---|
| 188 | * convert Color to String |
|---|
| 189 | * (Color.toString() omits alpha value) |
|---|
| 190 | */ |
|---|
| 191 | public static String toString(Color c) { |
|---|
| 192 | if (c == null) |
|---|
| 193 | return "null"; |
|---|
| 194 | if (c.getAlpha() == 255) |
|---|
| 195 | return String.format("#%06x", c.getRGB() & 0x00ffffff); |
|---|
| 196 | else |
|---|
| 197 | return String.format("#%06x(alpha=%d)", c.getRGB() & 0x00ffffff, c.getAlpha()); |
|---|
| 198 | } |
|---|
| 199 | |
|---|
| 200 | /** |
|---|
| 201 | * convert float range 0 <= x <= 1 to integer range 0..255 |
|---|
| 202 | * when dealing with colors and color alpha value |
|---|
| 203 | * @return null if val is null, the corresponding int if val is in the |
|---|
| 204 | * range 0...1. If val is outside that range, return 255 |
|---|
| 205 | */ |
|---|
| 206 | public static Integer color_float2int(Float val) { |
|---|
| 207 | if (val == null) |
|---|
| 208 | return null; |
|---|
| 209 | if (val < 0 || val > 1) |
|---|
| 210 | return 255; |
|---|
| 211 | return (int) (255f * val + 0.5f); |
|---|
| 212 | } |
|---|
| 213 | |
|---|
| 214 | /** |
|---|
| 215 | * convert back |
|---|
| 216 | */ |
|---|
| 217 | public static Float color_int2float(Integer val) { |
|---|
| 218 | if (val == null) |
|---|
| 219 | return null; |
|---|
| 220 | if (val < 0 || val > 255) |
|---|
| 221 | return 1f; |
|---|
| 222 | return ((float) val) / 255f; |
|---|
| 223 | } |
|---|
| 224 | |
|---|
| 225 | public static Color complement(Color clr) { |
|---|
| 226 | return new Color(255 - clr.getRed(), 255 - clr.getGreen(), 255 - clr.getBlue(), clr.getAlpha()); |
|---|
| 227 | } |
|---|
| 228 | |
|---|
| 229 | public static int copyStream(InputStream source, OutputStream destination) throws IOException { |
|---|
| 230 | int count = 0; |
|---|
| 231 | byte[] b = new byte[512]; |
|---|
| 232 | int read; |
|---|
| 233 | while ((read = source.read(b)) != -1) { |
|---|
| 234 | count += read; |
|---|
| 235 | destination.write(b, 0, read); |
|---|
| 236 | } |
|---|
| 237 | return count; |
|---|
| 238 | } |
|---|
| 239 | |
|---|
| 240 | public static boolean deleteDirectory(File path) { |
|---|
| 241 | if( path.exists() ) { |
|---|
| 242 | File[] files = path.listFiles(); |
|---|
| 243 | for(int i=0; i<files.length; i++) { |
|---|
| 244 | if(files[i].isDirectory()) { |
|---|
| 245 | deleteDirectory(files[i]); |
|---|
| 246 | } |
|---|
| 247 | else { |
|---|
| 248 | files[i].delete(); |
|---|
| 249 | } |
|---|
| 250 | } |
|---|
| 251 | } |
|---|
| 252 | return( path.delete() ); |
|---|
| 253 | } |
|---|
| 254 | |
|---|
| 255 | /** |
|---|
| 256 | * <p>Utility method for closing an input stream.</p> |
|---|
| 257 | * |
|---|
| 258 | * @param is the input stream. May be null. |
|---|
| 259 | */ |
|---|
| 260 | public static void close(InputStream is){ |
|---|
| 261 | if (is == null) return; |
|---|
| 262 | try { |
|---|
| 263 | is.close(); |
|---|
| 264 | } catch(IOException e){ |
|---|
| 265 | // ignore |
|---|
| 266 | } |
|---|
| 267 | } |
|---|
| 268 | |
|---|
| 269 | /** |
|---|
| 270 | * <p>Utility method for closing an output stream.</p> |
|---|
| 271 | * |
|---|
| 272 | * @param os the output stream. May be null. |
|---|
| 273 | */ |
|---|
| 274 | public static void close(OutputStream os){ |
|---|
| 275 | if (os == null) return; |
|---|
| 276 | try { |
|---|
| 277 | os.close(); |
|---|
| 278 | } catch(IOException e){ |
|---|
| 279 | // ignore |
|---|
| 280 | } |
|---|
| 281 | } |
|---|
| 282 | |
|---|
| 283 | /** |
|---|
| 284 | * <p>Utility method for closing a reader.</p> |
|---|
| 285 | * |
|---|
| 286 | * @param reader the reader. May be null. |
|---|
| 287 | */ |
|---|
| 288 | public static void close(Reader reader){ |
|---|
| 289 | if (reader == null) return; |
|---|
| 290 | try { |
|---|
| 291 | reader.close(); |
|---|
| 292 | } catch(IOException e){ |
|---|
| 293 | // ignore |
|---|
| 294 | } |
|---|
| 295 | } |
|---|
| 296 | |
|---|
| 297 | private final static double EPSILION = 1e-11; |
|---|
| 298 | |
|---|
| 299 | public static boolean equalsEpsilon(double a, double b) { |
|---|
| 300 | return Math.abs(a - b) <= EPSILION; |
|---|
| 301 | } |
|---|
| 302 | |
|---|
| 303 | /** |
|---|
| 304 | * Copies the string {@code s} to system clipboard. |
|---|
| 305 | * @param s string to be copied to clipboard. |
|---|
| 306 | * @return true if succeeded, false otherwise. |
|---|
| 307 | */ |
|---|
| 308 | public static boolean copyToClipboard(String s) { |
|---|
| 309 | try { |
|---|
| 310 | Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(s), new ClipboardOwner() { |
|---|
| 311 | |
|---|
| 312 | @Override |
|---|
| 313 | public void lostOwnership(Clipboard clpbrd, Transferable t) { |
|---|
| 314 | } |
|---|
| 315 | }); |
|---|
| 316 | return true; |
|---|
| 317 | } catch (IllegalStateException ex) { |
|---|
| 318 | ex.printStackTrace(); |
|---|
| 319 | return false; |
|---|
| 320 | } |
|---|
| 321 | } |
|---|
| 322 | |
|---|
| 323 | /** |
|---|
| 324 | * Extracts clipboard content as string. |
|---|
| 325 | * @return string clipboard contents if available, {@code null} otherwise. |
|---|
| 326 | */ |
|---|
| 327 | public static String getClipboardContent() { |
|---|
| 328 | Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); |
|---|
| 329 | Transferable t = null; |
|---|
| 330 | for (int tries = 0; t == null && tries < 10; tries++) { |
|---|
| 331 | try { |
|---|
| 332 | t = clipboard.getContents(null); |
|---|
| 333 | } catch (IllegalStateException e) { |
|---|
| 334 | // Clipboard currently unavailable. On some platforms, the system clipboard is unavailable while it is accessed by another application. |
|---|
| 335 | try { |
|---|
| 336 | Thread.sleep(1); |
|---|
| 337 | } catch (InterruptedException ex) { |
|---|
| 338 | } |
|---|
| 339 | } |
|---|
| 340 | } |
|---|
| 341 | try { |
|---|
| 342 | if (t != null && t.isDataFlavorSupported(DataFlavor.stringFlavor)) { |
|---|
| 343 | String text = (String) t.getTransferData(DataFlavor.stringFlavor); |
|---|
| 344 | return text; |
|---|
| 345 | } |
|---|
| 346 | } catch (UnsupportedFlavorException ex) { |
|---|
| 347 | ex.printStackTrace(); |
|---|
| 348 | return null; |
|---|
| 349 | } catch (IOException ex) { |
|---|
| 350 | ex.printStackTrace(); |
|---|
| 351 | return null; |
|---|
| 352 | } |
|---|
| 353 | return null; |
|---|
| 354 | } |
|---|
| 355 | |
|---|
| 356 | /** |
|---|
| 357 | * Calculate MD5 hash of a string and output in hexadecimal format. |
|---|
| 358 | * Output has length 32 with characters in range [0-9a-f] |
|---|
| 359 | */ |
|---|
| 360 | public static String md5Hex(String data) { |
|---|
| 361 | byte[] byteData = null; |
|---|
| 362 | try { |
|---|
| 363 | byteData = data.getBytes("UTF-8"); |
|---|
| 364 | } catch (UnsupportedEncodingException e) { |
|---|
| 365 | throw new RuntimeException(); |
|---|
| 366 | } |
|---|
| 367 | MessageDigest md = null; |
|---|
| 368 | try { |
|---|
| 369 | md = MessageDigest.getInstance("MD5"); |
|---|
| 370 | } catch (NoSuchAlgorithmException e) { |
|---|
| 371 | throw new RuntimeException(); |
|---|
| 372 | } |
|---|
| 373 | byte[] byteDigest = md.digest(byteData); |
|---|
| 374 | return toHexString(byteDigest); |
|---|
| 375 | } |
|---|
| 376 | |
|---|
| 377 | /** |
|---|
| 378 | * Converts a byte array to a string of hexadecimal characters. Preserves leading zeros, so the |
|---|
| 379 | * size of the output string is always twice the number of input bytes. |
|---|
| 380 | */ |
|---|
| 381 | public static String toHexString(byte[] bytes) { |
|---|
| 382 | char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; |
|---|
| 383 | char[] hexChars = new char[bytes.length * 2]; |
|---|
| 384 | for (int j=0; j<bytes.length; j++) { |
|---|
| 385 | int v = bytes[j] & 0xFF; |
|---|
| 386 | hexChars[j*2] = hexArray[v/16]; |
|---|
| 387 | hexChars[j*2 + 1] = hexArray[v%16]; |
|---|
| 388 | } |
|---|
| 389 | return new String(hexChars); |
|---|
| 390 | } |
|---|
| 391 | |
|---|
| 392 | /** |
|---|
| 393 | * Topological sort. |
|---|
| 394 | * |
|---|
| 395 | * @param dependencies contains mappings (key -> value). In the final list of sorted objects, the key will come |
|---|
| 396 | * after the value. (In other words, the key depends on the value(s).) |
|---|
| 397 | * There must not be cyclic dependencies. |
|---|
| 398 | * @return the list of sorted objects |
|---|
| 399 | */ |
|---|
| 400 | public static <T> List<T> topologicalSort(final MultiMap<T,T> dependencies) { |
|---|
| 401 | MultiMap<T,T> deps = new MultiMap<T,T>(); |
|---|
| 402 | for (T key : dependencies.keySet()) { |
|---|
| 403 | deps.putVoid(key); |
|---|
| 404 | for (T val : dependencies.get(key)) { |
|---|
| 405 | deps.putVoid(val); |
|---|
| 406 | deps.put(key, val); |
|---|
| 407 | } |
|---|
| 408 | } |
|---|
| 409 | |
|---|
| 410 | int size = deps.size(); |
|---|
| 411 | List<T> sorted = new ArrayList<T>(); |
|---|
| 412 | for (int i=0; i<size; ++i) { |
|---|
| 413 | T parentless = null; |
|---|
| 414 | for (T key : deps.keySet()) { |
|---|
| 415 | if (deps.get(key).size() == 0) { |
|---|
| 416 | parentless = key; |
|---|
| 417 | break; |
|---|
| 418 | } |
|---|
| 419 | } |
|---|
| 420 | if (parentless == null) throw new RuntimeException(); |
|---|
| 421 | sorted.add(parentless); |
|---|
| 422 | deps.remove(parentless); |
|---|
| 423 | for (T key : deps.keySet()) { |
|---|
| 424 | deps.remove(key, parentless); |
|---|
| 425 | } |
|---|
| 426 | } |
|---|
| 427 | if (sorted.size() != size) throw new RuntimeException(); |
|---|
| 428 | return sorted; |
|---|
| 429 | } |
|---|
| 430 | |
|---|
| 431 | /** |
|---|
| 432 | * Represents a function that can be applied to objects of {@code A} and |
|---|
| 433 | * returns objects of {@code B}. |
|---|
| 434 | * @param <A> class of input objects |
|---|
| 435 | * @param <B> class of transformed objects |
|---|
| 436 | */ |
|---|
| 437 | public static interface Function<A, B> { |
|---|
| 438 | |
|---|
| 439 | /** |
|---|
| 440 | * Applies the function on {@code x}. |
|---|
| 441 | * @param x an object of |
|---|
| 442 | * @return the transformed object |
|---|
| 443 | */ |
|---|
| 444 | B apply(A x); |
|---|
| 445 | } |
|---|
| 446 | |
|---|
| 447 | /** |
|---|
| 448 | * Transforms the collection {@code c} into an unmodifiable collection and |
|---|
| 449 | * applies the {@link Function} {@code f} on each element upon access. |
|---|
| 450 | * @param <A> class of input collection |
|---|
| 451 | * @param <B> class of transformed collection |
|---|
| 452 | * @param c a collection |
|---|
| 453 | * @param f a function that transforms objects of {@code A} to objects of {@code B} |
|---|
| 454 | * @return the transformed unmodifiable collection |
|---|
| 455 | */ |
|---|
| 456 | public static <A, B> Collection<B> transform(final Collection<? extends A> c, final Function<A, B> f) { |
|---|
| 457 | return new Collection<B>() { |
|---|
| 458 | |
|---|
| 459 | @Override |
|---|
| 460 | public int size() { |
|---|
| 461 | return c.size(); |
|---|
| 462 | } |
|---|
| 463 | |
|---|
| 464 | @Override |
|---|
| 465 | public boolean isEmpty() { |
|---|
| 466 | return c.isEmpty(); |
|---|
| 467 | } |
|---|
| 468 | |
|---|
| 469 | @Override |
|---|
| 470 | public boolean contains(Object o) { |
|---|
| 471 | return c.contains(o); |
|---|
| 472 | } |
|---|
| 473 | |
|---|
| 474 | @Override |
|---|
| 475 | public Object[] toArray() { |
|---|
| 476 | return c.toArray(); |
|---|
| 477 | } |
|---|
| 478 | |
|---|
| 479 | @Override |
|---|
| 480 | public <T> T[] toArray(T[] a) { |
|---|
| 481 | return c.toArray(a); |
|---|
| 482 | } |
|---|
| 483 | |
|---|
| 484 | @Override |
|---|
| 485 | public String toString() { |
|---|
| 486 | return c.toString(); |
|---|
| 487 | } |
|---|
| 488 | |
|---|
| 489 | @Override |
|---|
| 490 | public Iterator<B> iterator() { |
|---|
| 491 | return new Iterator<B>() { |
|---|
| 492 | |
|---|
| 493 | private Iterator<? extends A> it = c.iterator(); |
|---|
| 494 | |
|---|
| 495 | @Override |
|---|
| 496 | public boolean hasNext() { |
|---|
| 497 | return it.hasNext(); |
|---|
| 498 | } |
|---|
| 499 | |
|---|
| 500 | @Override |
|---|
| 501 | public B next() { |
|---|
| 502 | return f.apply(it.next()); |
|---|
| 503 | } |
|---|
| 504 | |
|---|
| 505 | @Override |
|---|
| 506 | public void remove() { |
|---|
| 507 | throw new UnsupportedOperationException(); |
|---|
| 508 | } |
|---|
| 509 | }; |
|---|
| 510 | } |
|---|
| 511 | |
|---|
| 512 | @Override |
|---|
| 513 | public boolean add(B e) { |
|---|
| 514 | throw new UnsupportedOperationException(); |
|---|
| 515 | } |
|---|
| 516 | |
|---|
| 517 | @Override |
|---|
| 518 | public boolean remove(Object o) { |
|---|
| 519 | throw new UnsupportedOperationException(); |
|---|
| 520 | } |
|---|
| 521 | |
|---|
| 522 | @Override |
|---|
| 523 | public boolean containsAll(Collection<?> c) { |
|---|
| 524 | throw new UnsupportedOperationException(); |
|---|
| 525 | } |
|---|
| 526 | |
|---|
| 527 | @Override |
|---|
| 528 | public boolean addAll(Collection<? extends B> c) { |
|---|
| 529 | throw new UnsupportedOperationException(); |
|---|
| 530 | } |
|---|
| 531 | |
|---|
| 532 | @Override |
|---|
| 533 | public boolean removeAll(Collection<?> c) { |
|---|
| 534 | throw new UnsupportedOperationException(); |
|---|
| 535 | } |
|---|
| 536 | |
|---|
| 537 | @Override |
|---|
| 538 | public boolean retainAll(Collection<?> c) { |
|---|
| 539 | throw new UnsupportedOperationException(); |
|---|
| 540 | } |
|---|
| 541 | |
|---|
| 542 | @Override |
|---|
| 543 | public void clear() { |
|---|
| 544 | throw new UnsupportedOperationException(); |
|---|
| 545 | } |
|---|
| 546 | }; |
|---|
| 547 | } |
|---|
| 548 | } |
|---|