1 /******************************************************************************* 2 * Copyright (c) 2000, 2015 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 15 package org.eclipse.jface.util; 16 17 import java.util.Arrays; 18 import java.util.Collections; 19 import java.util.List; 20 import java.util.MissingResourceException; 21 import java.util.Objects; 22 import java.util.ResourceBundle; 23 import java.util.SortedSet; 24 import java.util.TreeSet; 25 26 import org.eclipse.swt.SWT; 27 import org.eclipse.swt.graphics.Point; 28 import org.eclipse.swt.graphics.Rectangle; 29 import org.eclipse.swt.widgets.Display; 30 import org.eclipse.swt.widgets.Monitor; 31 32 /** 33 * <p> 34 * A static class providing utility methods to all of JFace. 35 * </p> 36 * 37 * @since 3.1 38 */ 39 public final class Util { 40 41 /** 42 * An unmodifiable, empty, sorted set. This value is guaranteed to never 43 * change and never be <code>null</code>. 44 */ 45 public static final SortedSet<?> EMPTY_SORTED_SET = Collections 46 .unmodifiableSortedSet(new TreeSet<>()); 47 48 /** 49 * A common zero-length string. It avoids needing write <code>NON-NLS</code> 50 * next to code fragments. It's also a bit clearer to read. 51 */ 52 public static final String ZERO_LENGTH_STRING = ""; //$NON-NLS-1$ 53 54 /** 55 * Verifies that the given object is an instance of the given class. 56 * 57 * @param object 58 * The object to check; may be <code>null</code>. 59 * @param c 60 * The class which the object should be; must not be 61 * <code>null</code>. 62 */ assertInstance(final Object object, final Class<?> c)63 public static void assertInstance(final Object object, final Class<?> c) { 64 assertInstance(object, c, false); 65 } 66 67 /** 68 * Verifies the given object is an instance of the given class. It is 69 * possible to specify whether the object is permitted to be 70 * <code>null</code>. 71 * 72 * @param object 73 * The object to check; may be <code>null</code>. 74 * @param c 75 * The class which the object should be; must not be 76 * <code>null</code>. 77 * @param allowNull 78 * Whether the object is allowed to be <code>null</code>. 79 */ assertInstance(final Object object, final Class<?> c, final boolean allowNull)80 private static void assertInstance(final Object object, 81 final Class<?> c, final boolean allowNull) { 82 if (object == null && allowNull) { 83 return; 84 } 85 86 if (object == null || c == null) { 87 throw new NullPointerException(); 88 } else if (!c.isInstance(object)) { 89 throw new IllegalArgumentException(); 90 } 91 } 92 93 /** 94 * Compares two boolean values. <code>false</code> is considered to be 95 * "less than" <code>true</code>. 96 * 97 * @param left 98 * The left value to compare 99 * @param right 100 * The right value to compare 101 * @return <code>-1</code> if the left is <code>false</code> and the 102 * right is <code>true</code>. <code>1</code> if the opposite 103 * is true. If they are equal, then it returns <code>0</code>. 104 */ compare(final boolean left, final boolean right)105 public static int compare(final boolean left, final boolean right) { 106 return left == false ? (right == true ? -1 : 0) : 1; 107 } 108 109 /** 110 * Compares two integer values. 111 * 112 * @param left 113 * The left value to compare 114 * @param right 115 * The right value to compare 116 * @return <code>left - right</code> 117 */ compare(final int left, final int right)118 public static int compare(final int left, final int right) { 119 return left - right; 120 } 121 122 /** 123 * Compares to comparable objects -- defending against <code>null</code>. 124 * 125 * @param left 126 * The left object to compare; may be <code>null</code>. 127 * @param right 128 * The right object to compare; may be <code>null</code>. 129 * @return The result of the comparison. <code>null</code> is considered 130 * to be the least possible value. 131 */ compare(final T left, final T right)132 public static <T extends Comparable<? super T>> int compare(final T left, 133 final T right) { 134 if (left == null && right == null) { 135 return 0; 136 } else if (left == null) { 137 return -1; 138 } else if (right == null) { 139 return 1; 140 } else { 141 return left.compareTo(right); 142 } 143 } 144 145 /** 146 * Compares two arrays of comparable objects -- accounting for 147 * <code>null</code>. 148 * 149 * @param left 150 * The left array to be compared; may be <code>null</code>. 151 * @param right 152 * The right array to be compared; may be <code>null</code>. 153 * @return The result of the comparison. <code>null</code> is considered 154 * to be the least possible value. A shorter array is considered 155 * less than a longer array. 156 */ compare(final T[] left, final T[] right)157 public static <T extends Comparable<? super T>> int compare(final T[] left, 158 final T[] right) { 159 if (left == null && right == null) { 160 return 0; 161 } else if (left == null) { 162 return -1; 163 } else if (right == null) { 164 return 1; 165 } else { 166 int l = left.length; 167 int r = right.length; 168 169 if (l != r) { 170 return l - r; 171 } 172 173 for (int i = 0; i < l; i++) { 174 int compareTo = compare(left[i], right[i]); 175 176 if (compareTo != 0) { 177 return compareTo; 178 } 179 } 180 181 return 0; 182 } 183 } 184 185 /** 186 * Compares two lists -- account for <code>null</code>. The lists must 187 * contain comparable objects. 188 * 189 * @param left 190 * The left list to compare; may be <code>null</code>. This 191 * list must only contain instances of <code>Comparable</code>. 192 * @param right 193 * The right list to compare; may be <code>null</code>. This 194 * list must only contain instances of <code>Comparable</code>. 195 * @return The result of the comparison. <code>null</code> is considered 196 * to be the least possible value. A shorter list is considered less 197 * than a longer list. 198 */ compare(final List<T> left, final List<T> right)199 public static <T extends Comparable<? super T>> int compare(final List<T> left, final List<T> right) { 200 if (left == null && right == null) { 201 return 0; 202 } else if (left == null) { 203 return -1; 204 } else if (right == null) { 205 return 1; 206 } else { 207 int l = left.size(); 208 int r = right.size(); 209 210 if (l != r) { 211 return l - r; 212 } 213 214 for (int i = 0; i < l; i++) { 215 int compareTo = compare(left.get(i), right.get(i)); 216 217 if (compareTo != 0) { 218 return compareTo; 219 } 220 } 221 222 return 0; 223 } 224 } 225 226 /** 227 * Tests whether the first array ends with the second array. 228 * 229 * @param left 230 * The array to check (larger); may be <code>null</code>. 231 * @param right 232 * The array that should be a subsequence (smaller); may be 233 * <code>null</code>. 234 * @param equals 235 * Whether the two array are allowed to be equal. 236 * @return <code>true</code> if the second array is a subsequence of the 237 * array list, and they share end elements. 238 */ endsWith(final Object[] left, final Object[] right, final boolean equals)239 public static boolean endsWith(final Object[] left, 240 final Object[] right, final boolean equals) { 241 if (left == null || right == null) { 242 return false; 243 } 244 245 int l = left.length; 246 int r = right.length; 247 248 if (r > l || !equals && r == l) { 249 return false; 250 } 251 252 for (int i = 0; i < r; i++) { 253 if (!Objects.equals(left[l - i - 1], right[r - i - 1])) { 254 return false; 255 } 256 } 257 258 return true; 259 } 260 261 /** 262 * Checks whether the two objects are <code>null</code> -- allowing for 263 * <code>null</code>. 264 * 265 * @param left 266 * The left object to compare; may be <code>null</code>. 267 * @param right 268 * The right object to compare; may be <code>null</code>. 269 * @return <code>true</code> if the two objects are equivalent; 270 * <code>false</code> otherwise. 271 * @deprecated Use {@link Objects#equals(Object, Object)} 272 */ 273 @Deprecated equals(final Object left, final Object right)274 public static boolean equals(final Object left, final Object right) { 275 return Objects.equals(left, right); 276 } 277 278 /** 279 * Tests whether two arrays of objects are equal to each other. The arrays must 280 * not be <code>null</code>, but their elements may be <code>null</code>. 281 * 282 * @param leftArray 283 * The left array to compare; may be <code>null</code>, and may be 284 * empty and may contain <code>null</code> elements. 285 * @param rightArray 286 * The right array to compare; may be <code>null</code>, and may be 287 * empty and may contain <code>null</code> elements. 288 * @return <code>true</code> if the arrays are equal length and the elements at 289 * the same position are equal; <code>false</code> otherwise. 290 * @deprecated Use {@link Arrays#equals(Object[], Object[])} 291 */ 292 @Deprecated equals(final Object[] leftArray, final Object[] rightArray)293 public static boolean equals(final Object[] leftArray, 294 final Object[] rightArray) { 295 return Arrays.equals(leftArray, rightArray); 296 } 297 298 /** 299 * Provides a hash code based on the given integer value. 300 * 301 * @param i The integer value 302 * @return <code>i</code> 303 * @deprecated return directly value, or use {@link Integer#hashCode(int)} 304 */ 305 @Deprecated hashCode(final int i)306 public static int hashCode(final int i) { 307 return i; 308 } 309 310 /** 311 * Provides a hash code for the object -- defending against <code>null</code>. 312 * 313 * @param object The object for which a hash code is required. 314 * @return <code>object.hashCode</code> or <code>0</code> if <code>object</code> 315 * if <code>null</code>. 316 * @deprecated use {@link Objects#hashCode(Object)} 317 */ 318 @Deprecated hashCode(final Object object)319 public static int hashCode(final Object object) { 320 return object != null ? object.hashCode() : 0; 321 } 322 323 /** 324 * Computes the hash code for an array of objects, but with defense against 325 * <code>null</code>. 326 * 327 * @param objects The array of objects for which a hash code is needed; may be 328 * <code>null</code>. 329 * @return The hash code for <code>objects</code>; or <code>0</code> if 330 * <code>objects</code> is <code>null</code>. 331 * @deprecated use {@link Arrays#hashCode(Object[])} 332 */ 333 @Deprecated hashCode(final Object[] objects)334 public static int hashCode(final Object[] objects) { 335 if (objects == null) { 336 return 0; 337 } 338 339 int hashCode = 89; 340 for (final Object object : objects) { 341 if (object != null) { 342 hashCode = hashCode * 31 + object.hashCode(); 343 } 344 } 345 346 return hashCode; 347 } 348 349 /** 350 * Checks whether the second array is a subsequence of the first array, and 351 * that they share common starting elements. 352 * 353 * @param left 354 * The first array to compare (large); may be <code>null</code>. 355 * @param right 356 * The second array to compare (small); may be <code>null</code>. 357 * @param equals 358 * Whether it is allowed for the two arrays to be equivalent. 359 * @return <code>true</code> if the first arrays starts with the second 360 * list; <code>false</code> otherwise. 361 */ startsWith(final Object[] left, final Object[] right, final boolean equals)362 public static boolean startsWith(final Object[] left, 363 final Object[] right, final boolean equals) { 364 if (left == null || right == null) { 365 return false; 366 } 367 368 int l = left.length; 369 int r = right.length; 370 371 if (r > l || !equals && r == l) { 372 return false; 373 } 374 375 for (int i = 0; i < r; i++) { 376 if (!Objects.equals(left[i], right[i])) { 377 return false; 378 } 379 } 380 381 return true; 382 } 383 384 /** 385 * Converts an array into a string representation that is suitable for 386 * debugging. 387 * 388 * @param array 389 * The array to convert; may be <code>null</code>. 390 * @return The string representation of the array; never <code>null</code>. 391 */ toString(final Object[] array)392 public static String toString(final Object[] array) { 393 if (array == null) { 394 return "null"; //$NON-NLS-1$ 395 } 396 397 final StringBuilder buffer = new StringBuilder(); 398 buffer.append('['); 399 400 final int length = array.length; 401 for (int i = 0; i < length; i++) { 402 if (i != 0) { 403 buffer.append(','); 404 } 405 final Object object = array[i]; 406 final String element = String.valueOf(object); 407 buffer.append(element); 408 } 409 buffer.append(']'); 410 411 return buffer.toString(); 412 } 413 414 /** 415 * Provides a translation of a particular key from the resource bundle. 416 * 417 * @param resourceBundle 418 * The key to look up in the resource bundle; should not be 419 * <code>null</code>. 420 * @param key 421 * The key to look up in the resource bundle; should not be 422 * <code>null</code>. 423 * @param defaultString 424 * The value to return if the resource cannot be found; may be 425 * <code>null</code>. 426 * @return The value of the translated resource at <code>key</code>. If 427 * the key cannot be found, then it is simply the 428 * <code>defaultString</code>. 429 */ translateString( final ResourceBundle resourceBundle, final String key, final String defaultString)430 public static String translateString( 431 final ResourceBundle resourceBundle, final String key, 432 final String defaultString) { 433 if (resourceBundle != null && key != null) { 434 try { 435 final String translatedString = resourceBundle.getString(key); 436 437 if (translatedString != null) { 438 return translatedString; 439 } 440 } catch (MissingResourceException eMissingResource) { 441 // Such is life. We'll return the key 442 } 443 } 444 445 return defaultString; 446 } 447 448 /** 449 * Foundation replacement for <code>String#replaceAll(String, 450 * String)</code>, but <strong>without support for regular 451 * expressions</strong>. 452 * 453 * @param src the original string 454 * @param find the string to find 455 * @param replacement the replacement string 456 * @return the new string, with all occurrences of <code>find</code> 457 * replaced by <code>replacement</code> (not using regular 458 * expressions) 459 * @since 3.4 460 */ replaceAll(String src, String find, String replacement)461 public static String replaceAll(String src, String find, String replacement) { 462 final int len = src.length(); 463 final int findLen = find.length(); 464 465 int idx = src.indexOf(find); 466 if (idx < 0) { 467 return src; 468 } 469 470 StringBuilder buf = new StringBuilder(); 471 int beginIndex = 0; 472 while (idx != -1 && idx < len) { 473 buf.append(src.substring(beginIndex, idx)); 474 buf.append(replacement); 475 476 beginIndex = idx + findLen; 477 if (beginIndex < len) { 478 idx = src.indexOf(find, beginIndex); 479 } else { 480 idx = -1; 481 } 482 } 483 if (beginIndex<len) { 484 buf.append(src.substring(beginIndex, (idx==-1?len:idx))); 485 } 486 return buf.toString(); 487 } 488 489 // 490 // Methods for working with the windowing system 491 // 492 493 /** 494 * Windowing system constant. 495 * @since 3.5 496 */ 497 public static final String WS_WIN32 = "win32";//$NON-NLS-1$ 498 499 /** 500 * Windowing system constant. 501 * @since 3.5 502 */ 503 @Deprecated 504 public static final String WS_MOTIF = "motif";//$NON-NLS-1$ 505 506 /** 507 * Windowing system constant. 508 * @since 3.5 509 */ 510 public static final String WS_GTK = "gtk";//$NON-NLS-1$ 511 512 /** 513 * Windowing system constant. 514 * @since 3.5 515 */ 516 @Deprecated 517 public static final String WS_PHOTON = "photon";//$NON-NLS-1$ 518 519 /** 520 * Windowing system constant. 521 * @since 3.5 522 */ 523 @Deprecated 524 public static final String WS_CARBON = "carbon";//$NON-NLS-1$ 525 526 /** 527 * Windowing system constant. 528 * @since 3.5 529 */ 530 public static final String WS_COCOA = "cocoa";//$NON-NLS-1$ 531 532 /** 533 * Windowing system constant. 534 * @since 3.5 535 */ 536 public static final String WS_WPF = "wpf";//$NON-NLS-1$ 537 538 /** 539 * Windowing system constant. 540 * @since 3.5 541 */ 542 public static final String WS_UNKNOWN = "unknown";//$NON-NLS-1$ 543 544 /** 545 * Common WS query helper method. 546 * @return <code>true</code> for windows platforms 547 * @since 3.5 548 */ isWindows()549 public static boolean isWindows() { 550 final String ws = SWT.getPlatform(); 551 return WS_WIN32.equals(ws) || WS_WPF.equals(ws); 552 } 553 554 /** 555 * Common WS query helper method. 556 * @return <code>true</code> for mac platforms 557 * @since 3.5 558 */ isMac()559 public static boolean isMac() { 560 final String ws = SWT.getPlatform(); 561 return WS_CARBON.equals(ws) || WS_COCOA.equals(ws); 562 } 563 564 /** 565 * Common WS query helper method. 566 * @return <code>true</code> for linux platform 567 * @since 3.5 568 */ isLinux()569 public static boolean isLinux() { 570 final String ws = SWT.getPlatform(); 571 return WS_GTK.equals(ws); 572 } 573 574 /** 575 * Common WS query helper method. 576 * @return <code>true</code> for gtk platforms 577 * @since 3.5 578 */ isGtk()579 public static boolean isGtk() { 580 final String ws = SWT.getPlatform(); 581 return WS_GTK.equals(ws); 582 } 583 584 /** 585 * Common WS query helper method. 586 * @return <code>true</code> for motif platforms 587 * @since 3.5 588 */ 589 @Deprecated isMotif()590 public static boolean isMotif() { 591 final String ws = SWT.getPlatform(); 592 return WS_MOTIF.equals(ws); 593 } 594 595 /** 596 * Common WS query helper method. 597 * @return <code>true</code> for photon platforms 598 * @since 3.5 599 */ 600 @Deprecated isPhoton()601 public static boolean isPhoton() { 602 final String ws = SWT.getPlatform(); 603 return WS_PHOTON.equals(ws); 604 } 605 606 /** 607 * Common WS query helper method. 608 * @return <code>true</code> for carbon platforms 609 * @since 3.5 610 */ 611 @Deprecated isCarbon()612 public static boolean isCarbon() { 613 final String ws = SWT.getPlatform(); 614 return WS_CARBON.equals(ws); 615 } 616 617 /** 618 * Common WS query helper method. 619 * @return <code>true</code> for the cocoa platform. 620 * @since 3.5 621 */ isCocoa()622 public static boolean isCocoa() { 623 final String ws = SWT.getPlatform(); 624 return WS_COCOA.equals(ws); 625 } 626 627 /** 628 * Common WS query helper method. 629 * @return <code>true</code> for WPF 630 * @since 3.5 631 */ isWpf()632 public static boolean isWpf() { 633 final String ws = SWT.getPlatform(); 634 return WS_WPF.equals(ws); 635 } 636 637 /** 638 * Common WS query helper method. 639 * @return <code>true</code> for win32 640 * @since 3.5 641 */ isWin32()642 public static boolean isWin32() { 643 final String ws = SWT.getPlatform(); 644 return WS_WIN32.equals(ws); 645 } 646 647 /** 648 * Common WS query helper method. 649 * @return the SWT windowing platform string. 650 * @see SWT#getPlatform() 651 * @since 3.5 652 */ getWS()653 public static String getWS() { 654 return SWT.getPlatform(); 655 } 656 657 /** 658 * This class should never be constructed. 659 */ Util()660 private Util() { 661 // Not allowed. 662 } 663 664 /** 665 * Returns the monitor whose client area contains the given point. If no monitor 666 * contains the point, returns the monitor that is closest to the point. If this 667 * is ever made public, it should be moved into a separate utility class. 668 * 669 * @param toSearch point to find (display coordinates) 670 * @param toFind point to find (display coordinates) 671 * @return the monitor closest to the given point 672 * @since 3.15 673 */ getClosestMonitor(Display toSearch, Point toFind)674 public static Monitor getClosestMonitor(Display toSearch, Point toFind) { 675 int closest = Integer.MAX_VALUE; 676 677 Monitor[] monitors = toSearch.getMonitors(); 678 Monitor result = monitors[0]; 679 680 for (Monitor current : monitors) { 681 Rectangle clientArea = current.getClientArea(); 682 683 if (clientArea.contains(toFind)) { 684 return current; 685 } 686 687 int distance = Geometry.distanceSquared(Geometry.centerPoint(clientArea), toFind); 688 if (distance < closest) { 689 closest = distance; 690 result = current; 691 } 692 } 693 694 return result; 695 } 696 } 697