org.eclipse.jface.util.BidiUtils Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2012, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
******************************************************************************/
package org.eclipse.jface.util;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.equinox.bidi.StructuredTextTypeHandlerFactory;
import org.eclipse.jface.internal.InternalPolicy;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.SegmentListener;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Text;
/**
* This class provides API to handle Base Text Direction (BTD) and
* Structured Text support for SWT Text widgets.
*
* @since 3.9
*/
public final class BidiUtils {
/**
* Left-To-Right Base Text Direction.
* @see #getTextDirection()
*/
public static final String LEFT_TO_RIGHT = "ltr"; //$NON-NLS-1$
/**
* Right-To-Left Base Text Direction.
* @see #getTextDirection()
*/
public static final String RIGHT_TO_LEFT = "rtl";//$NON-NLS-1$
/**
* Auto (contextual) Base Text Direction.
* @see #getTextDirection()
*/
public static final String AUTO = "auto";//$NON-NLS-1$
/**
* Base Text Direction defined in {@link BidiUtils#getTextDirection()}
* @see #getSegmentListener(String)
* @see #applyBidiProcessing(Text, String)
*/
public static final String BTD_DEFAULT = "default";//$NON-NLS-1$
/**
* Visual Left-To-Right Text Direction.
*
* Note: This handling type is deprecated and should only be used
* when interfacing with legacy systems that store data in visual order.
*
* @see http://www.w3.org/International/questions/qa-visual-vs-logical
* @see #getSegmentListener(String)
* @see #applyBidiProcessing(Text, String)
*
* @since 3.11
*/
public static final String VISUAL_LEFT_TO_RIGHT = "visualltr"; //$NON-NLS-1$
/**
* Visual Right-To-Left Text Direction
*
* Note: This handling type is deprecated and should only be used
* when interfacing with legacy systems that store data in visual order.
*
* @see http://www.w3.org/International/questions/qa-visual-vs-logical
* @see #getSegmentListener(String)
* @see #applyBidiProcessing(Text, String)
*
* @since 3.11
*/
public static final String VISUAL_RIGHT_TO_LEFT = "visualrtl";//$NON-NLS-1$
/**
* Segment listener for LTR Base Text Direction
*/
private static final SegmentListener BASE_TEXT_DIRECTION_LTR = new BaseTextDirectionSegmentListener(LEFT_TO_RIGHT);
/**
* Segment listener for RTL Base Text Direction
*/
private static final SegmentListener BASE_TEXT_DIRECTION_RTL = new BaseTextDirectionSegmentListener(RIGHT_TO_LEFT);
/**
* Segment listener for Auto (Contextual) Base Text Direction
*/
private static final SegmentListener BASE_TEXT_DIRECTION_AUTO = new BaseTextDirectionSegmentListener(AUTO);
/**
* Segment listener for LTR Visual Text Direction
*/
private static final SegmentListener VISUAL_TEXT_DIRECTION_LTR = new VisualTextDirectionSegmentListener(
VISUAL_LEFT_TO_RIGHT);
/**
* Segment listener for RTL Visual Text Direction
*/
private static final SegmentListener VISUAL_TEXT_DIRECTION_RTL = new VisualTextDirectionSegmentListener(
VISUAL_RIGHT_TO_LEFT);
/**
* Listener cache. Map from structured text type id ({@link String}) to
* structured text segment listener ({@link SegmentListener}).
*/
private static final Map structuredTextSegmentListeners = new HashMap<>();
/**
* The LRE char
*/
static final char LRE = 0x202A;
/**
* The LRM char
*/
static final char LRM = 0x200E;
/**
* The PDF char
*/
static final char PDF = 0x202C;
/**
* The RLE char
*/
static final char RLE = 0x202B;
/**
* The LRO char
*/
static final char LRO = 0x202D;
/**
* The RLO char
*/
static final char RLO = 0x202E;
private static boolean bidiSupport = false;
private static String textDirection = "";//$NON-NLS-1$
private BidiUtils() {
// no instances
}
/**
* Returns the Base Text Direction. Possible values are:
*
* - {@link BidiUtils#LEFT_TO_RIGHT}
* - {@link BidiUtils#RIGHT_TO_LEFT}
* - {@link BidiUtils#AUTO}
* null
(no direction set)
*
*
* @return the base text direction
*/
public static String getTextDirection() {
return textDirection;
}
/**
* Sets the Base Text Direction. Possible values are:
*
* - {@link BidiUtils#LEFT_TO_RIGHT}
* - {@link BidiUtils#RIGHT_TO_LEFT}
* - {@link BidiUtils#AUTO}
* null
(no default direction)
*
*
* @param direction the text direction to set
* @throws IllegalArgumentException if direction
is not legal
*/
public static void setTextDirection(String direction) {
if (direction == null || LEFT_TO_RIGHT.equals(direction) || RIGHT_TO_LEFT.equals(direction) || AUTO.equals(direction)) {
textDirection = direction;
} else {
throw new IllegalArgumentException(direction);
}
}
/**
* Returns whether bidi support is enabled.
*
* @return true
iff bidi support is enabled
*/
public static boolean getBidiSupport() {
return bidiSupport;
}
/**
* Enables or disables bidi support.
*
* @param bidi true
to enable bidi support, false
to disable
*/
public static void setBidiSupport(boolean bidi) {
bidiSupport = bidi;
}
/**
* Applies bidi processing to the given text field.
*
*
* Possible values for handlingType
are:
*
* - {@link BidiUtils#LEFT_TO_RIGHT}
* - {@link BidiUtils#RIGHT_TO_LEFT}
* - {@link BidiUtils#AUTO}
* - {@link BidiUtils#BTD_DEFAULT}
* - {@link BidiUtils#VISUAL_LEFT_TO_RIGHT}
* - {@link BidiUtils#VISUAL_RIGHT_TO_LEFT}
* - the
String
constants in
* {@link StructuredTextTypeHandlerFactory}
* - if OSGi is running, the types that have been contributed to the
*
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: If this method is called on a text control, then
* {@link #applyTextDirection(Control, String)} must not be called on the
* same control.
*
* Note: The Structured Text handling only works if the
* org.eclipse.equinox.bidi
bundle is on the classpath!
*
*
*
* Note:
* {@link org.eclipse.swt.widgets.Text#addSegmentListener(SegmentListener)}
* is currently only implemented on Windows and GTK, so this method won't
* have an effect on Cocoa.
*
* @param field
* the text field
* @param handlingType
* the type of handling
* @throws IllegalArgumentException
* if handlingType
is not a known type identifier
*/
public static void applyBidiProcessing(Text field, String handlingType) {
SegmentListener listener = getSegmentListener(handlingType);
if (listener != null) {
field.addSegmentListener(listener);
if (InternalPolicy.DEBUG_BIDI_UTILS) {
int color = 0;
if (LEFT_TO_RIGHT.equals(handlingType)) {
color = SWT.COLOR_RED;
} else if (RIGHT_TO_LEFT.equals(handlingType)) {
color = SWT.COLOR_GREEN;
} else if (BTD_DEFAULT.equals(handlingType)) {
color = SWT.COLOR_YELLOW;
} else if (AUTO.equals(handlingType)) {
color = SWT.COLOR_MAGENTA;
} else {
color = SWT.COLOR_CYAN;
}
field.setBackground(field.getDisplay().getSystemColor(color));
if (field.getMessage().isEmpty()) {
field.setMessage('<' + handlingType + '>');
}
if (field.getToolTipText() == null) {
field.setToolTipText('<' + handlingType + '>');
}
}
}
}
/**
* Applies bidi processing to the given styled text field.
*
*
* Possible values for handlingType
are:
*
* - {@link BidiUtils#LEFT_TO_RIGHT}
* - {@link BidiUtils#RIGHT_TO_LEFT}
* - {@link BidiUtils#AUTO}
* - {@link BidiUtils#BTD_DEFAULT}
* - {@link BidiUtils#VISUAL_LEFT_TO_RIGHT}
* - {@link BidiUtils#VISUAL_RIGHT_TO_LEFT}
* - the
String
constants in
* {@link StructuredTextTypeHandlerFactory}
* - if OSGi is running, the types that have been contributed to the
*
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: If this method is called on a text control, then
* {@link #applyTextDirection(Control, String)} must not be called on the
* same control.
*
* Note: The Structured Text handling only works if the
* org.eclipse.equinox.bidi
bundle is on the classpath!
*
*
* @param field
* the styled text field
* @param handlingType
* the type of handling
* @throws IllegalArgumentException
* if handlingType
is not a known type identifier
*/
public static void applyBidiProcessing(StyledText field, String handlingType) {
final SegmentListener listener = getSegmentListener(handlingType);
if (listener != null) {
field.addBidiSegmentListener(listener::getSegments);
}
}
/**
* Applies bidi processing to the given combo.
*
*
* Possible values for handlingType
are:
*
* - {@link BidiUtils#LEFT_TO_RIGHT}
* - {@link BidiUtils#RIGHT_TO_LEFT}
* - {@link BidiUtils#AUTO}
* - {@link BidiUtils#BTD_DEFAULT}
* - {@link BidiUtils#VISUAL_LEFT_TO_RIGHT}
* - {@link BidiUtils#VISUAL_RIGHT_TO_LEFT}
* - the
String
constants in
* {@link StructuredTextTypeHandlerFactory}
* - if OSGi is running, the types that have been contributed to the
*
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: If this method is called on a combo control, then
* {@link #applyTextDirection(Control, String)} must not be called on the
* same control.
*
* Note: The Structured Text handling only works if the
* org.eclipse.equinox.bidi
bundle is on the classpath!
*
*
*
* Note:
* {@link org.eclipse.swt.widgets.Combo#addSegmentListener(SegmentListener)}
* is currently only implemented on Windows so this method won't have an
* effect on Cocoa and GTK.
*
* @param combo
* the combo field
* @param handlingType
* the type of handling
* @throws IllegalArgumentException
* if handlingType
is not a known type identifier
* @since 3.10
*/
public static void applyBidiProcessing(Combo combo, String handlingType) {
SegmentListener listener = getSegmentListener(handlingType);
if (listener != null) {
combo.addSegmentListener(listener);
if (InternalPolicy.DEBUG_BIDI_UTILS) {
int color = 0;
if (LEFT_TO_RIGHT.equals(handlingType)) {
color = SWT.COLOR_RED;
} else if (RIGHT_TO_LEFT.equals(handlingType)) {
color = SWT.COLOR_GREEN;
} else if (BTD_DEFAULT.equals(handlingType)) {
color = SWT.COLOR_YELLOW;
} else if (AUTO.equals(handlingType)) {
color = SWT.COLOR_MAGENTA;
} else {
color = SWT.COLOR_CYAN;
}
combo.setBackground(combo.getDisplay().getSystemColor(color));
if (combo.getToolTipText() == null) {
combo.setToolTipText('<' + handlingType + '>');
}
}
}
}
/**
* Returns a segment listener for the given handlingType
that
* can e.g. be passed to {@link Text#addSegmentListener(SegmentListener)}.
*
*
* Note: The Structured Text handling only works if the
* org.eclipse.equinox.bidi
bundle is on the classpath!
*
*
* @param handlingType
* the handling type as specified in
* {@link #applyBidiProcessing(Text, String)}
* @return the segment listener, or null
if no handling is
* required
* @throws IllegalArgumentException
* if handlingType
is not a known type identifier
* @see #applyBidiProcessing(Text, String)
*/
public static SegmentListener getSegmentListener(String handlingType) {
SegmentListener listener = null;
if (LEFT_TO_RIGHT.equals(handlingType)) {
listener = BASE_TEXT_DIRECTION_LTR;
} else if (RIGHT_TO_LEFT.equals(handlingType)) {
listener = BASE_TEXT_DIRECTION_RTL;
} else if (AUTO.equals(handlingType)) {
listener = BASE_TEXT_DIRECTION_AUTO;
} else if (getBidiSupport()) {
if (BTD_DEFAULT.equals(handlingType)) {
if (LEFT_TO_RIGHT.equals(getTextDirection())) {
listener = BASE_TEXT_DIRECTION_LTR;
} else if (RIGHT_TO_LEFT.equals(getTextDirection())) {
listener = BASE_TEXT_DIRECTION_RTL;
} else if (AUTO.equals(getTextDirection())) {
listener = BASE_TEXT_DIRECTION_AUTO;
}
} else if (VISUAL_LEFT_TO_RIGHT.equals(handlingType)) {
listener = VISUAL_TEXT_DIRECTION_LTR;
} else if (VISUAL_RIGHT_TO_LEFT.equals(handlingType)) {
listener = VISUAL_TEXT_DIRECTION_RTL;
} else {
Object handler = structuredTextSegmentListeners.get(handlingType);
if (handler != null) {
listener = (SegmentListener) handler;
} else {
listener = new StructuredTextSegmentListener(handlingType);
structuredTextSegmentListeners.put(handlingType, listener);
}
}
}
return listener;
}
/**
* Applies a Base Text Direction to the given control (and its descendants, if
* it's a {@link Composite}).
*
*
* Possible values for textDirection
are:
*
*
* - {@link BidiUtils#LEFT_TO_RIGHT}
* - {@link BidiUtils#RIGHT_TO_LEFT}
* - {@link BidiUtils#AUTO}
* - {@link BidiUtils#BTD_DEFAULT}
*
*
* The 3 values {@link #LEFT_TO_RIGHT}, {@link #RIGHT_TO_LEFT}, and
* {@link BidiUtils#AUTO} are usable whether {@link #getBidiSupport() bidi
* support} is enabled or disabled.
*
*
* The remaining value {@link BidiUtils#BTD_DEFAULT} only has an effect if bidi
* support is enabled.
*
*
*
* Note: If this method is called on a control, then no
* applyBidiProcessing
method must be called on the same control.
*
*
* Note:
* {@link org.eclipse.swt.widgets.Control#setTextDirection(int)} is currently
* only implemented on Windows, so the direction won't be inherited by
* descendants on GTK and Cocoa.
*
*
* @param control the control
* @param textDirection the text direction
*/
public static void applyTextDirection(Control control, String textDirection) {
int textDir = 0;
if (LEFT_TO_RIGHT.equals(textDirection)) {
textDir = SWT.LEFT_TO_RIGHT;
} else if (RIGHT_TO_LEFT.equals(textDirection)) {
textDir = SWT.RIGHT_TO_LEFT;
} else if (AUTO.equals(textDirection)) {
textDir = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
} else if (getBidiSupport() && BTD_DEFAULT.equals(textDirection)) {
if (LEFT_TO_RIGHT.equals(getTextDirection())) {
textDir = SWT.LEFT_TO_RIGHT;
} else if (RIGHT_TO_LEFT.equals(getTextDirection())) {
textDir = SWT.RIGHT_TO_LEFT;
} else if (AUTO.equals(getTextDirection())) {
textDir = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
}
}
if (control instanceof Text && textDir != 0) {
applyBidiProcessing((Text) control, textDirection);
} else if (control instanceof StyledText && textDir != 0) {
applyBidiProcessing((StyledText) control, textDirection);
} else if (control instanceof Combo && textDir != 0) {
applyBidiProcessing((Combo) control, textDirection);
} else if (textDir != 0) {
control.setTextDirection(textDir);
}
}
}