diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/util/BidiUtils.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/util/BidiUtils.java index 0cdd02f..5c2338e 100644 --- a/bundles/org.eclipse.jface/src/org/eclipse/jface/util/BidiUtils.java +++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/util/BidiUtils.java @@ -12,10 +12,13 @@ package org.eclipse.jface.util; import java.util.HashMap; +import java.util.Locale; import java.util.Map; +import org.eclipse.equinox.bidi.StructuredTextProcessor; import org.eclipse.equinox.bidi.StructuredTextTypeHandlerFactory; import org.eclipse.jface.internal.InternalPolicy; +import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.BidiSegmentEvent; import org.eclipse.swt.custom.BidiSegmentListener; @@ -90,6 +93,27 @@ public static final String VISUAL_RIGHT_TO_LEFT = "visualrtl";//$NON-NLS-1$ /** + * For applying bidi processing for formatting messages. + * + * @see #applyBidiProcessing(PROCESSING_TYPE, Object...) + */ + public enum PROCESSING_TYPE { + /** + * For applying bidi processing on message placeholders. + * + * @see #applyBidiProcessing(PROCESSING_TYPE, Object...) + */ + MESSAGEWITHPLACEHOLDERS, /** + * For applying bidi processing on + * concatenation of strings. + * + * @see #applyBidiProcessing(PROCESSING_TYPE, + * Object...) + */ + CONCATENATION + } + + /** * Segment listener for LTR Base Text Direction */ private static final SegmentListener BASE_TEXT_DIRECTION_LTR = new BaseTextDirectionSegmentListener(LEFT_TO_RIGHT); @@ -142,6 +166,11 @@ * The RLE char */ static final char RLE = 0x202B; + + /** + * The RLM char + */ + static final char RLM = 0x200F; /** * The LRO char @@ -538,4 +567,199 @@ control.setTextDirection(textDir); } } -} + + /** + * Applies bidi processing to the given string. + * + *
+ * Possible values for handlingType
are:
+ *
String
constants in
+ * {@link StructuredTextTypeHandlerFactory}org.eclipse.equinox.bidi.bidiTypes
extension point.+ * The 3 values {@link #LEFT_TO_RIGHT}, {@link #RIGHT_TO_LEFT}, and + * {@link #AUTO} are usable whether {@link #getBidiSupport() bidi support} + * is enabled or disabled. + *
+ * The remaining values only have an effect if bidi support is enabled. + *
+ * The 4 first values {@link #LEFT_TO_RIGHT}, {@link #RIGHT_TO_LEFT}, + * {@link #AUTO}, and {@link #BTD_DEFAULT} are for Base Text Direction (BTD) + * handling. The remaining values are for Structured Text handling. + *
+ * Note: The Structured Text handling only works if the
+ * org.eclipse.equinox.bidi
bundle is on the classpath!
+ *
+ * Note: To deprocess the string you must use + * {@link BidiUtils#deprocessBidi(String)} for the 6 first values or + * {@link StructuredTextProcessor#deprocessTyped(String, String)} for the + * remaining values. + *
+ * + * @param string + * the string + * @param handlingType + * the type of handling + * @return the bidi processed string + * @throws IllegalArgumentException + * ifhandlingType
is not a known type identifier
+ */
+ public static String applyBidiProcessing(String string, String handlingType) {
+ if (LEFT_TO_RIGHT.equals(handlingType)) {
+ return addUCC(string, false, handlingType);
+ } else if (RIGHT_TO_LEFT.equals(handlingType)) {
+ return addUCC(string, true, handlingType);
+ } else if (AUTO.equals(handlingType)) {
+ return addUCC(string, isRTLValue(string), handlingType);
+
+ } else if (getBidiSupport()) {
+ if (BTD_DEFAULT.equals(handlingType)) {
+ if (LEFT_TO_RIGHT.equals(getTextDirection())) {
+ return addUCC(string, false, handlingType);
+ } else if (RIGHT_TO_LEFT.equals(getTextDirection())) {
+ return addUCC(string, true, handlingType);
+ } else if (AUTO.equals(getTextDirection())) {
+ return addUCC(string, isRTLValue(string), handlingType);
+ }
+ } else if (VISUAL_LEFT_TO_RIGHT.equals(handlingType)) {
+ return (InternalPolicy.DEBUG_BIDI_UTILS ? handlingType : "") + LRO + string + PDF; //$NON-NLS-1$
+ } else if (VISUAL_RIGHT_TO_LEFT.equals(handlingType)) {
+ return (InternalPolicy.DEBUG_BIDI_UTILS ? handlingType : "") + RLO + string + PDF; //$NON-NLS-1$
+ } else {
+ return StructuredTextProcessor.processTyped(string, handlingType);
+ }
+ }
+ return string;
+ }
+
+ /**
+ * Strips off Unicode control characters from the given string.
+ *
+ *
+ * @param string
+ * the string
+ * @return the bidi deprocessed string
+ */
+ public static String deprocessBidi(String string) {
+ String header1 = "" + LRM + LRE, header2 = "" + RLM + RLE; //$NON-NLS-1$ //$NON-NLS-2$
+ String tailer1 = "" + LRM + PDF, tailer2 = "" + RLM + PDF; //$NON-NLS-1$ //$NON-NLS-2$
+
+ if (InternalPolicy.DEBUG_BIDI_UTILS) {
+ string = string.replaceFirst(LEFT_TO_RIGHT, "").replaceFirst(RIGHT_TO_LEFT, "").replaceFirst(AUTO, "") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ .replaceFirst(BTD_DEFAULT, "").replaceFirst(VISUAL_LEFT_TO_RIGHT, "") //$NON-NLS-1$ //$NON-NLS-2$
+ .replaceFirst(VISUAL_RIGHT_TO_LEFT, ""); //$NON-NLS-1$
+ }
+ if ((string.startsWith(header1) && string.endsWith(tailer1))
+ || (string.startsWith(header2) && string.endsWith(tailer2))) {
+ return string.substring(2, string.length() - 2);
+ } else if ((string.charAt(0) == LRO || string.charAt(0) == RLO) && string.charAt(string.length() - 1) == PDF) {
+ return string.substring(1, string.length() - 1);
+ }
+ return string;
+ }
+
+ /**
+ * Applies bidi processing for formatting messages. Note:
+ * The number of arguments in params
should always be even and
+ * greater than 0. Each pair is composed of the string to bidi process and
+ * the type of handling as specified in
+ * {@link #applyBidiProcessing(Text, String)}. If the number of arguments is
+ * odd no bidi processing will occur.
+ *
+ *
+ * @param typeOfContext
+ * message with placeholders or concatenation ?
+ * @param params
+ * unlimited number of arguments associated with either
+ * placeholders or concatenated strings. It is always even number
+ * since for each placeholder / piece of text, we need to specify
+ * which type of handling is required (i.e. text direction
+ * enforcement, structured text, no handling).
+ * @return the bidi processed placeholders or the concatenated string.
+ */
+ public static Object[] applyBidiProcessing(PROCESSING_TYPE typeOfContext, Object... params) {
+ if (typeOfContext == PROCESSING_TYPE.MESSAGEWITHPLACEHOLDERS) {
+ char prefix = isBidiLocale() ? RLM : LRM;
+ return applyBidiProcessing(prefix, params);
+ } else if (typeOfContext == PROCESSING_TYPE.CONCATENATION) {
+ char prefix = Window.getDefaultOrientation() == SWT.RIGHT_TO_LEFT ? RLM : LRM;
+ Object[] results = applyBidiProcessing(prefix, params);
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < results.length; i++) {
+ sb.append(results[i]);
+ }
+ String[] result = new String[1];
+ result[0] = sb.toString();
+ return result;
+ }
+ return params;
+ }
+
+ private static Object[] applyBidiProcessing(char prefix, Object... params) {
+
+ if (params.length == 0 || params.length % 2 == 1) {
+ return params;
+ }
+ int numPlaceHolders = params.length / 2;
+ Object[] results = new Object[numPlaceHolders];
+ for (int i = 0; i < numPlaceHolders; i++) {
+ results[i] = prefix + applyBidiProcessing(params[2 * i].toString(), params[2 * i + 1].toString());
+ }
+ return results;
+ }
+
+ private static String addUCC(String string, boolean isRTL, String handlingType) {
+ StringBuffer sb = new StringBuffer();
+ if (InternalPolicy.DEBUG_BIDI_UTILS) {
+ sb.append(handlingType);
+ }
+ if (isRTL) {
+ sb.append(RLM).append(RLE);
+ } else {
+ sb.append(LRM).append(LRE);
+ }
+ sb.append(string);
+ if (isRTL) {
+ sb.append(RLM);
+ } else {
+ sb.append(LRM);
+ }
+ sb.append(PDF);
+ return sb.toString();
+ }
+
+ private static boolean isRTLValue(String stringValue) {
+ for (int i = 0; i < stringValue.length(); i++) {
+ if (Character.getDirectionality(stringValue.charAt(i)) == Character.DIRECTIONALITY_RIGHT_TO_LEFT
+ || Character
+ .getDirectionality(stringValue.charAt(i)) == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC
+ || Character.getDirectionality(stringValue.charAt(i)) == Character.DIRECTIONALITY_ARABIC_NUMBER)
+ return true;
+ else if (Character.getDirectionality(stringValue.charAt(i)) == Character.DIRECTIONALITY_LEFT_TO_RIGHT) {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ private static boolean isBidiLocale() {
+ Locale defaultLocale = Locale.getDefault();
+ String language = defaultLocale.getLanguage();
+ boolean isBidi = "iw".equals(language) || //$NON-NLS-1$
+ "he".equals(language) || //$NON-NLS-1$
+ "ar".equals(language) || //$NON-NLS-1$
+ "fa".equals(language) || //$NON-NLS-1$
+ "ur".equals(language); //$NON-NLS-1$
+ return isBidi;
+ }
+
+}
\ No newline at end of file