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