View | Details | Raw Unified | Return to bug 183164 | Differences between
and this patch

Collapse All | Expand All

(-).settings/org.eclipse.jdt.core.prefs (-17 / +3 lines)
Lines 1-4 Link Here
1
#Mon Feb 22 08:40:30 CST 2010
1
#Thu Aug 16 11:00:59 EDT 2007
2
eclipse.preferences.version=1
2
eclipse.preferences.version=1
3
org.eclipse.jdt.core.builder.cleanOutputFolder=clean
3
org.eclipse.jdt.core.builder.cleanOutputFolder=clean
4
org.eclipse.jdt.core.builder.duplicateResourceTask=warning
4
org.eclipse.jdt.core.builder.duplicateResourceTask=warning
Lines 19-33 Link Here
19
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
19
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
20
org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning
20
org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning
21
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
21
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
22
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
23
org.eclipse.jdt.core.compiler.problem.deprecation=warning
22
org.eclipse.jdt.core.compiler.problem.deprecation=warning
24
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
23
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
25
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled
24
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled
26
org.eclipse.jdt.core.compiler.problem.discouragedReference=error
25
org.eclipse.jdt.core.compiler.problem.discouragedReference=error
27
org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
26
org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
28
org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
27
org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
29
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
30
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
31
org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
28
org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
32
org.eclipse.jdt.core.compiler.problem.finalParameterBound=ignore
29
org.eclipse.jdt.core.compiler.problem.finalParameterBound=ignore
33
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
30
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
Lines 41-47 Link Here
41
org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
38
org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
42
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
39
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
43
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
40
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
44
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=error
45
org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore
41
org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore
46
org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=enabled
42
org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=enabled
47
org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public
43
org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public
Lines 50-67 Link Here
50
org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=public
46
org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=public
51
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
47
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
52
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
48
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
53
org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
54
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
49
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
55
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
50
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
56
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=warning
51
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=warning
57
org.eclipse.jdt.core.compiler.problem.nullReference=warning
58
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
52
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
59
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
60
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
53
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
61
org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
62
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
63
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
64
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
65
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
54
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
66
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
55
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
67
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
56
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
Lines 73-91 Link Here
73
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning
62
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning
74
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
63
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
75
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
64
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
65
org.eclipse.jdt.core.compiler.problem.unsafeTypeOperation=warning
76
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
66
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
77
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
78
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
79
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled
67
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled
80
org.eclipse.jdt.core.compiler.problem.unusedImport=error
68
org.eclipse.jdt.core.compiler.problem.unusedImport=error
81
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
82
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
69
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
83
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
70
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
84
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
85
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled
71
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled
86
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled
72
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled
87
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error
73
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error
88
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
89
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
74
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
90
org.eclipse.jdt.core.compiler.source=1.3
75
org.eclipse.jdt.core.compiler.source=1.3
91
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
76
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
Lines 159-164 Link Here
159
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
144
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
160
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
145
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
161
org.eclipse.jdt.core.formatter.indentation.size=4
146
org.eclipse.jdt.core.formatter.indentation.size=4
147
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert
162
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
148
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
163
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
149
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
164
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
150
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
(-)META-INF/MANIFEST.MF (-4 / +6 lines)
Lines 7-19 Link Here
7
Bundle-Localization: plugin
7
Bundle-Localization: plugin
8
Bundle-RequiredExecutionEnvironment: OSGi/Minimum-1.2
8
Bundle-RequiredExecutionEnvironment: OSGi/Minimum-1.2
9
Bundle-ActivationPolicy: lazy
9
Bundle-ActivationPolicy: lazy
10
Export-Package: org.eclipse.equinox.bidi.complexp,
10
Export-Package: org.eclipse.equinox.bidi,
11
 org.eclipse.equinox.bidi.internal.complexp;x-internal:=true,
11
 org.eclipse.equinox.bidi.custom,
12
 org.eclipse.equinox.bidi.internal.complexp.consumable;x-internal:=true
12
 org.eclipse.equinox.bidi.internal;x-internal:=true,
13
 org.eclipse.equinox.bidi.internal.consumable;x-internal:=true
13
Require-Bundle: org.eclipse.equinox.common;bundle-version="3.6.0",
14
Require-Bundle: org.eclipse.equinox.common;bundle-version="3.6.0",
14
 org.eclipse.equinox.registry;bundle-version="3.5.0"
15
 org.eclipse.equinox.registry;bundle-version="3.5.0"
15
Import-Package: org.eclipse.osgi.framework.log;version="1.0.0",
16
Import-Package: org.eclipse.osgi.framework.log;version="1.0.0",
17
 org.eclipse.osgi.service.localization;version="1.1.0",
16
 org.eclipse.osgi.util;version="1.1.0",
18
 org.eclipse.osgi.util;version="1.1.0",
17
 org.osgi.framework;version="1.5.0",
19
 org.osgi.framework;version="1.5.0",
18
 org.osgi.util.tracker;version="1.4.0"
20
 org.osgi.util.tracker;version="1.4.0"
19
Bundle-Activator: org.eclipse.equinox.bidi.internal.complexp.BiDiActivator
21
Bundle-Activator: org.eclipse.equinox.bidi.internal.BidiComplexActivator
(-)plugin.xml (-12 / +12 lines)
Lines 8-68 Link Here
8
         point="org.eclipse.equinox.bidi.bidiTypes">
8
         point="org.eclipse.equinox.bidi.bidiTypes">
9
      <typeDescription
9
      <typeDescription
10
            description="%sqlProcessorName"
10
            description="%sqlProcessorName"
11
            class="org.eclipse.equinox.bidi.internal.complexp.consumable.ComplExpSql"
11
            class="org.eclipse.equinox.bidi.internal.consumable.BidiComplexSql"
12
            type="sql">
12
            type="sql">
13
      </typeDescription>
13
      </typeDescription>
14
      <typeDescription
14
      <typeDescription
15
            description="%regexProcessorName"
15
            description="%regexProcessorName"
16
            class="org.eclipse.equinox.bidi.internal.complexp.consumable.ComplExpRegex"
16
            class="org.eclipse.equinox.bidi.internal.consumable.BidiComplexRegex"
17
            type="regex">
17
            type="regex">
18
      </typeDescription>
18
      </typeDescription>
19
      <typeDescription
19
      <typeDescription
20
            description="%javaProcessorName"
20
            description="%javaProcessorName"
21
            class="org.eclipse.equinox.bidi.internal.complexp.consumable.ComplExpJava"
21
            class="org.eclipse.equinox.bidi.internal.consumable.BidiComplexJava"
22
            type="java">
22
            type="java">
23
      </typeDescription>
23
      </typeDescription>
24
      <typeDescription
24
      <typeDescription
25
            class="org.eclipse.equinox.bidi.internal.complexp.consumable.ComplExpComma"
25
            class="org.eclipse.equinox.bidi.internal.consumable.BidiComplexComma"
26
            description="%commaProcessorName"
26
            description="%commaProcessorName"
27
            type="comma">
27
            type="comma">
28
      </typeDescription>
28
      </typeDescription>
29
      <typeDescription
29
      <typeDescription
30
            class="org.eclipse.equinox.bidi.internal.complexp.consumable.ComplExpEmail"
30
            class="org.eclipse.equinox.bidi.internal.consumable.BidiComplexEmail"
31
            description="%emailProcessorName"
31
            description="%emailProcessorName"
32
            type="email">
32
            type="email">
33
      </typeDescription>
33
      </typeDescription>
34
      <typeDescription
34
      <typeDescription
35
            class="org.eclipse.equinox.bidi.internal.complexp.consumable.ComplExpFile"
35
            class="org.eclipse.equinox.bidi.internal.consumable.BidiComplexFile"
36
            description="%fileProcessorName"
36
            description="%fileProcessorName"
37
            type="file">
37
            type="file">
38
      </typeDescription>
38
      </typeDescription>
39
      <typeDescription
39
      <typeDescription
40
            class="org.eclipse.equinox.bidi.internal.complexp.consumable.ComplExpMath"
40
            class="org.eclipse.equinox.bidi.internal.consumable.BidiComplexMath"
41
            description="%mathProcessorName"
41
            description="%mathProcessorName"
42
            type="math">
42
            type="math">
43
      </typeDescription>
43
      </typeDescription>
44
      <typeDescription
44
      <typeDescription
45
            class="org.eclipse.equinox.bidi.internal.complexp.consumable.ComplExpProperty"
45
            class="org.eclipse.equinox.bidi.internal.consumable.BidiComplexProperty"
46
            description="%propertyProcessorName"
46
            description="%propertyProcessorName"
47
            type="property">
47
            type="property">
48
      </typeDescription>
48
      </typeDescription>
49
      <typeDescription
49
      <typeDescription
50
            class="org.eclipse.equinox.bidi.internal.complexp.consumable.ComplExpSystem"
50
            class="org.eclipse.equinox.bidi.internal.consumable.BidiComplexSystem"
51
            description="%systemProcessorName"
51
            description="%systemProcessorName"
52
            type="system">
52
            type="system">
53
      </typeDescription>
53
      </typeDescription>
54
      <typeDescription
54
      <typeDescription
55
            class="org.eclipse.equinox.bidi.internal.complexp.consumable.ComplExpUnderscore"
55
            class="org.eclipse.equinox.bidi.internal.consumable.BidiComplexUnderscore"
56
            description="%underscoreProcessorName"
56
            description="%underscoreProcessorName"
57
            type="underscore">
57
            type="underscore">
58
      </typeDescription>
58
      </typeDescription>
59
      <typeDescription
59
      <typeDescription
60
            class="org.eclipse.equinox.bidi.internal.complexp.consumable.ComplExpURL"
60
            class="org.eclipse.equinox.bidi.internal.consumable.BidiComplexURL"
61
            description="%urlProcessorName"
61
            description="%urlProcessorName"
62
            type="url">
62
            type="url">
63
      </typeDescription>
63
      </typeDescription>
64
      <typeDescription
64
      <typeDescription
65
            class="org.eclipse.equinox.bidi.internal.complexp.consumable.ComplExpXPath"
65
            class="org.eclipse.equinox.bidi.internal.consumable.BidiComplexXPath"
66
            description="%xpathProcessorName"
66
            description="%xpathProcessorName"
67
            type="xpath">
67
            type="xpath">
68
      </typeDescription>
68
      </typeDescription>
(-)schema/BiDiExpressionType.exsd (-1 / +1 lines)
Lines 63-69 Link Here
63
                  The processor that provides specialized bi-directional handling for this type of strings.
63
                  The processor that provides specialized bi-directional handling for this type of strings.
64
               </documentation>
64
               </documentation>
65
               <appInfo>
65
               <appInfo>
66
                  <meta.attribute kind="java" basedOn=":org.eclipse.equinox.bidi.complexp.IComplExpProcessor"/>
66
                  <meta.attribute kind="java" basedOn=":org.eclipse.equinox.bidi.IComplExpProcessor"/>
67
               </appInfo>
67
               </appInfo>
68
            </annotation>
68
            </annotation>
69
         </attribute>
69
         </attribute>
(-)src/org/eclipse/equinox/bidi/BidiComplexEnvironment.java (+318 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi;
12
13
import org.eclipse.equinox.bidi.custom.IBidiComplexProcessor;
14
15
import org.eclipse.equinox.bidi.internal.BidiComplexActivator;
16
17
import java.util.Locale;
18
19
/**
20
 *  This class defines certain details of the environment within which
21
 *  complex expressions are processed.
22
 *  <p>
23
 *  All public fields in this class are <code>final</code>, i.e. cannot be
24
 *  changed after creating an instance.
25
 *  <p>
26
 *  A <code>BidiComplexEnvironment</code> instance can be associated with a <code>BidiComplexHelper</code>
27
 *  instance either when creating the
28
 * {@link BidiComplexHelper#BidiComplexHelper(java.lang.String, BidiComplexEnvironment) BidiComplexHelper} instance
29
 *  or using the {@link BidiComplexHelper#setEnvironment setEnvironment} method.
30
 *
31
 *  <h2>Code Samples</h2>
32
 *  <p>Example 1 (set all environment parameters)
33
 *  <pre>
34
 *
35
 *    BidiComplexEnvironment myEnv = new BidiComplexEnvironment("he_IL", true, BidiComplexEnvironment.ORIENT_RTL);
36
 *    BidiComplexHelper myHelper = new BidiComplexHelper(IBidiComplexExpressionTypes.FILE, myEnv);
37
 *
38
 *  </pre>
39
 *  <p>Example 2 (change only the orientation)
40
 *  <pre>
41
 *
42
 *    BidiComplexEnvironment env1 = myHelper.getEnvironment();
43
 *    BidiComplexEnvironment env2 = new BidiComplexEnvironment(env1.language, env1.mirrored, BidiComplexEnvironment.ORIENT_UNKNOWN);
44
 *    myHelper.setEnvironment(env2);
45
 *
46
 *  </pre>
47
 *  <p>
48
 *  This class also provides a number of convenience methods related to the environment.
49
 *  <p>&nbsp;</p>
50
 *  @see BidiComplexHelper#BidiComplexHelper(String, BidiComplexEnvironment)
51
 *  @see BidiComplexHelper#BidiComplexHelper(IBidiComplexProcessor, BidiComplexEnvironment)
52
 *  @see BidiComplexHelper#getEnvironment BidiComplexHelper.getEnvironment
53
 *  @see BidiComplexHelper#setEnvironment BidiComplexHelper.setEnvironment
54
 *  @see IBidiComplexProcessor#init IBidiComplexProcessor.init
55
 *  @see IBidiComplexProcessor#updateEnvironment IBidiComplexProcessor.updateEnvironment
56
 *
57
 *  @author Matitiahu Allouche
58
 */
59
public class BidiComplexEnvironment {
60
61
	/**
62
	 *  Constant specifying that the orientation of the GUI component
63
	 *  where a complex expression will be displayed is LTR.
64
	 *  It can appear as <code>orientation</code> argument for
65
	 *  {@link BidiComplexEnvironment#BidiComplexEnvironment BidiComplexEnvironment constructor} and as value for the
66
	 *  {@link BidiComplexEnvironment#orientation} member of <code>BidiComplexEnvironment</code>.
67
	 */
68
	public static final int ORIENT_LTR = 0;
69
70
	/**
71
	 *  Constant specifying that the orientation of the GUI component
72
	 *  where a complex expression will be displayed is RTL.
73
	 *  It can appear as <code>orientation</code> argument for
74
	 *  {@link BidiComplexEnvironment#BidiComplexEnvironment BidiComplexEnvironment constructor} and as value for the
75
	 *  {@link BidiComplexEnvironment#orientation} member of <code>BidiComplexEnvironment</code>.
76
	 */
77
	public static final int ORIENT_RTL = 1;
78
79
	/**
80
	 *  Constant specifying that the orientation of the GUI component
81
	 *  where a complex expression will be displayed is contextual with
82
	 *  a default of LTR (if no strong character appears in the text).
83
	 *  It can appear as <code>orientation</code> argument for
84
	 *  {@link BidiComplexEnvironment#BidiComplexEnvironment BidiComplexEnvironment constructor} and as value for the
85
	 *  {@link BidiComplexEnvironment#orientation} member of <code>BidiComplexEnvironment</code>.
86
	 */
87
	public static final int ORIENT_CONTEXTUAL_LTR = 2;
88
89
	/**
90
	 *  Constant specifying that the orientation of the GUI component
91
	 *  where a complex expression will be displayed is contextual with
92
	 *  a default of RTL (if no strong character appears in the text).
93
	 *  It can appear as <code>orientation</code> argument for
94
	 *  {@link BidiComplexEnvironment#BidiComplexEnvironment BidiComplexEnvironment constructor} and as value for the
95
	 *  {@link BidiComplexEnvironment#orientation} member of <code>BidiComplexEnvironment</code>.
96
	 */
97
	public static final int ORIENT_CONTEXTUAL_RTL = 3;
98
99
	/**
100
	 *  Constant specifying that the orientation of the GUI component
101
	 *  where a complex expression will be displayed is not known.
102
	 *  Directional formatting characters must be added as prefix and
103
	 *  suffix whenever a <i>full</i> text is generated using
104
	 *  {@link BidiComplexHelper#leanToFullText leanToFullText}.
105
	 *  It can appear as <code>orientation</code> argument for
106
	 *  {@link BidiComplexEnvironment#BidiComplexEnvironment BidiComplexEnvironment constructor} and as value for the
107
	 *  {@link BidiComplexEnvironment#orientation} member of <code>BidiComplexEnvironment</code>.
108
	 */
109
	public static final int ORIENT_UNKNOWN = 4;
110
111
	/**
112
	 *  Constant specifying that whatever the orientation of the
113
	 *  GUI component where a complex expression will be displayed, no
114
	 *  directional formatting characters must be added as prefix or
115
	 *  suffix when a <i>full</i> text is generated using
116
	 *  {@link BidiComplexHelper#leanToFullText leanToFullText}.
117
	 *  It can appear as <code>orientation</code> argument for
118
	 *  {@link BidiComplexEnvironment#BidiComplexEnvironment BidiComplexEnvironment constructor} and as value for the
119
	 *  {@link BidiComplexEnvironment#orientation} member of <code>BidiComplexEnvironment</code>.
120
	 */
121
	public static final int ORIENT_IGNORE = 5;
122
123
	/**
124
	 *  Pre-defined <code>BidiComplexEnvironment</code> instance with values for a non-mirrored GUI
125
	 *  and a Left-to-Right presentation component.<br>
126
	 *  The language is set to <code>null</code>, which defaults to the language
127
	 *  of the current default locale.
128
	 */
129
	public static final BidiComplexEnvironment DEFAULT = new BidiComplexEnvironment(null, false, ORIENT_LTR);
130
131
	/**
132
	 *  This string is a 2-letters code representing a language as defined by
133
	 *  ISO-639. If left as <code>null</code>, it defaults to the language
134
	 *  of the current default locale.
135
	 */
136
	public final String language;
137
138
	/**
139
	 *  Flag specifying that complex expressions processed under this environment
140
	 *  should assume that the GUI is mirrored (globally going from right to left).
141
	 */
142
	public final boolean mirrored;
143
144
	/** Specify the orientation (a.k.a. base direction) of the GUI
145
	 *  component in which the <i>full</i> text of the complex expression will
146
	 *  be displayed.<br>
147
	 *  The orientation must have one of the values
148
	 *  {@link #ORIENT_LTR ORIENT_LTR},
149
	 *  {@link #ORIENT_LTR ORIENT_RTL},
150
	 *  {@link #ORIENT_CONTEXTUAL_LTR ORIENT_CONTEXTUAL_LTR},
151
	 *  {@link #ORIENT_CONTEXTUAL_RTL ORIENT_CONTEXTUAL_RTL},
152
	 *  {@link #ORIENT_UNKNOWN ORIENT_UNKNOWN} or
153
	 *  {@link #ORIENT_IGNORE ORIENT_IGNORE}.
154
	  *  <p>
155
	 *  When the orientation is <code>ORIENT_LTR</code> and the complex
156
	 *  expression has a RTL base direction,
157
	 *  {@link BidiComplexHelper#leanToFullText leanToFullText}
158
	 *  adds RLE+RLM at the head of the <i>full</i> text and RLM+PDF at its
159
	 *  end.
160
	 *  <p>
161
	 *  When the orientation is <code>ORIENT_RTL</code> and the complex
162
	 *  expression has a LTR base direction,
163
	 *  {@link BidiComplexHelper#leanToFullText leanToFullText}
164
	 *  adds LRE+LRM at the head of the <i>full</i> text and LRM+PDF at its
165
	 *  end.
166
	 *  <p>
167
	 *  When the orientation is <code>ORIENT_CONTEXTUAL_LTR</code> or
168
	 *  <code>ORIENT_CONTEXTUAL_RTL</code> and the data content would resolve
169
	 *  to a RTL orientation while the complex expression has a LTR base
170
	 *  direction, {@link BidiComplexHelper#leanToFullText leanToFullText}
171
	 *  adds LRM at the head of the <i>full</i> text.
172
	 *  <p>
173
	 *  When the orientation is <code>ORIENT_CONTEXTUAL_LTR</code> or
174
	 *  <code>ORIENT_CONTEXTUAL_RTL</code> and the data content would resolve
175
	 *  to a LTR orientation while the complex expression has a RTL base
176
	 *  direction, {@link BidiComplexHelper#leanToFullText leanToFullText}
177
	 *  adds RLM at the head of the <i>full</i> text.
178
	 *  <p>
179
	 *  When the orientation is <code>ORIENT_UNKNOWN</code> and the complex
180
	 *  expression has a LTR base direction,
181
	 *  {@link BidiComplexHelper#leanToFullText leanToFullText}
182
	 *  adds LRE+LRM at the head of the <i>full</i> text and LRM+PDF at its
183
	 *  end.
184
	 *  <p>
185
	 *  When the orientation is <code>ORIENT_UNKNOWN</code> and the complex
186
	 *  expression has a RTL base direction,
187
	 *  {@link BidiComplexHelper#leanToFullText leanToFullText}
188
	 *  adds RLE+RLM at the head of the <i>full</i> text and RLM+PDF at its
189
	 *  end.
190
	 *  <p>
191
	 *  When the orientation is <code>ORIENT_IGNORE</code>,
192
	 *  {@link BidiComplexHelper#leanToFullText leanToFullText} does not add any directional
193
	 *  formatting characters as either prefix or suffix of the <i>full</i> text.
194
	 *  <p>
195
	 */
196
	public final int orientation;
197
198
	static Locale defaultLocale;
199
	static String defaultLanguage;
200
	static boolean defaultBidi;
201
	boolean bidiFlag;
202
203
	/**
204
	 *  Constructor
205
	 *
206
	 *  @param lang represents the language to be used in this environment.
207
	 *          It should be specified as a 2-letters code as defined by
208
	 *          ISO-639.<br>
209
	 *          If longer than 2 letters, the extra letters are ignored.<br>
210
	 *          If set to <code>null</code>, it defaults to the language
211
	 *          of the default locale.
212
	 *  @see #language
213
	 *
214
	 *  @param mirrored specifies if the GUI is mirrored.
215
	 *  @see #mirrored
216
	 *
217
	 *  @param orientation specifies the orientation of the component
218
	 *          which is to display the complex expression. It must be
219
	 *          one of the values
220
	 *          {@link #ORIENT_LTR ORIENT_LTR},
221
	 *          {@link #ORIENT_LTR ORIENT_RTL},
222
	 *          {@link #ORIENT_CONTEXTUAL_LTR ORIENT_CONTEXTUAL_LTR},
223
	 *          {@link #ORIENT_CONTEXTUAL_RTL ORIENT_CONTEXTUAL_RTL},
224
	 *          {@link #ORIENT_UNKNOWN ORIENT_UNKNOWN} or
225
	 *          {@link #ORIENT_IGNORE ORIENT_IGNORE}.<br>
226
	 *          If different, it defaults to {@link #ORIENT_UNKNOWN ORIENT_UNKNOWN}.
227
	 *  @see #orientation
228
	 */
229
	public BidiComplexEnvironment(String lang, boolean mirrored, int orientation) {
230
		if (lang == null) {
231
			language = null;
232
		} else {
233
			if (lang.length() > 2) {
234
				language = lang.substring(0, 2);
235
			} else {
236
				language = lang;
237
			}
238
			bidiFlag = isBidiLanguage(language);
239
		}
240
		this.mirrored = mirrored;
241
		this.orientation = orientation >= ORIENT_LTR && orientation <= ORIENT_IGNORE ? orientation : ORIENT_UNKNOWN;
242
	}
243
244
	/**
245
	 *  Check whether the current language uses a
246
	 *  bidi script (Arabic, Hebrew, Farsi or Urdu).
247
	 *
248
	 *  @return <code>true</code> if the current language uses a bidi script.
249
	 *          The language may have been set explicitly when creating the
250
	 *          <code>BidiComplexEnvironment</code> instance, or it may have defaulted to
251
	 *          the language of the current default locale.
252
	 *  @see #BidiComplexEnvironment BidiComplexEnvironment
253
	 */
254
	public boolean isBidi() {
255
		if (defaultLanguage != null && defaultLocale.equals(getDefaultLocale()))
256
			return defaultBidi;
257
258
		if (language == null) {
259
			defaultLocale = getDefaultLocale();
260
			defaultLanguage = defaultLocale.getLanguage();
261
			defaultBidi = isBidiLanguage(defaultLanguage);
262
			return defaultBidi;
263
		}
264
265
		return bidiFlag;
266
	}
267
268
	static boolean isBidiLanguage(String lang) {
269
		return "iw".equals(lang) || "he".equals(lang) || "ar".equals(lang) || "fa".equals(lang) || "ur".equals(lang); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
270
	}
271
272
	static String lineSep;
273
274
	/**
275
	 *  Retrieve the string which represents a line separator in this environment.
276
	 *
277
	 *  @return the string which is used as line separator (e.g. CRLF).
278
	 */
279
	public static String getLineSep() {
280
		// use bundle properties
281
		if (lineSep == null) {
282
			//          lineSep = System.getProperty("line.separator", "\n"); //$NON-NLS-1$//$NON-NLS-2$
283
			lineSep = getProperty("line.separator"); //$NON-NLS-1$/
284
		}
285
		return lineSep;
286
	}
287
288
	static String osName;
289
	static boolean flagOS;
290
291
	private static String getProperty(String key) {
292
		// use bundle properties
293
		//      osName = System.getProperty("os.name").toLowerCase(); //$NON-NLS-1$
294
		BidiComplexActivator bidiComplexActivator = BidiComplexActivator.getInstance();
295
		return bidiComplexActivator.getProperty(key);
296
	}
297
298
	private Locale getDefaultLocale() {
299
		BidiComplexActivator bidiComplexActivator = BidiComplexActivator.getInstance();
300
		return bidiComplexActivator.getDefaultLocale();
301
	}
302
303
	/**
304
	 *  Check if the current OS is supported by the complex expression packages.
305
	 *
306
	 *  @return <code>true</code> if the current OS is supported.
307
	 */
308
	public static boolean isSupportedOS() {
309
		if (osName == null) {
310
			// use bundle properties
311
			// osName = System.getProperty("os.name").toLowerCase(); //$NON-NLS-1$
312
			osName = getProperty("os.name").toLowerCase(); //$NON-NLS-1$/
313
			flagOS = osName.startsWith("windows") || osName.startsWith("linux"); //$NON-NLS-1$ //$NON-NLS-2$
314
		}
315
		return flagOS;
316
	}
317
318
}
(-)src/org/eclipse/equinox/bidi/BidiComplexFeatures.java (+190 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi;
12
13
import org.eclipse.equinox.bidi.custom.IBidiComplexProcessor;
14
15
/**
16
 *  This class defines features of a complex expression processor.
17
 *  <p>
18
 *  All public fields in this class are <code>final</code>, i.e. cannot be
19
 *  changed after creating an instance.
20
 *  <p>
21
 *  A <code>BidiComplexFeatures</code> instance can be associated with a
22
 *  <code>BidiComplexHelper</code> instance using
23
 *  the {@link BidiComplexHelper#setFeatures setFeatures} method.
24
 *
25
 *  <h2>Code Samples</h2>
26
 *  <p>Example 1 (set all features)
27
 *  <pre>
28
 *
29
 *    BidiComplexFeatures myFeatures = new BidiComplexFeatures("+-=", 0, -1, -1, false, false);
30
 *    BidiComplexHelper myHelper = new BidiComplexHelper(IBidiComplexExpressionTypes.FILE, myEnv);
31
 *    myHelper.setFeatures(myFeatures);
32
 *
33
 *  </pre>
34
 *  <p>Example 2 (change only the operators)
35
 *  <pre>
36
 *
37
 *    BidiComplexFeatures f1 = myHelper.getFeatures();
38
 *    BidiComplexFeatures f2 = new BidiComplexFeatures("[]|()", f1.specialsCount,
39
 *                                     f1.dirArabic, f1.dirHebrew,
40
 *                                     f1.ignoreArabic, f1.ignoreHebrew);
41
 *    myHelper.setFeatures(f2);
42
 *
43
 *  </pre>
44
 *
45
 *  @see BidiComplexHelper#getFeatures BidiComplexHelper.getFeatures
46
 *  @see BidiComplexHelper#setFeatures BidiComplexHelper.setFeatures
47
 *  @see IBidiComplexProcessor#init IBidiComplexProcessor.init
48
 *  @see IBidiComplexProcessor#updateEnvironment IBidiComplexProcessor.updateEnvironment
49
 *
50
 *  @author Matitiahu Allouche
51
 */
52
public class BidiComplexFeatures {
53
54
	/**
55
	 *  Constant specifying that the base direction of a complex expression is LTR.
56
	 *  The base direction may depend on whether the GUI is
57
	 *  {@link BidiComplexEnvironment#mirrored mirrored} and may
58
	 *  may be different for Arabic and for Hebrew.
59
	 *  This constant can appear as <code>dirArabic</code>
60
	 *  or <code>dirHebrew</code> argument for
61
	 *  {@link BidiComplexFeatures#BidiComplexFeatures BidiComplexFeatures constructor} and as value
62
	 *  for the {@link #dirArabic} or {@link #dirHebrew} members of
63
	 *  <code>BidiComplexFeatures</code>.
64
	 */
65
	public static final int DIR_LTR = 0;
66
67
	/**
68
	 *  Constant specifying that the base direction of a complex expression is RTL.
69
	 *  The base direction may depend on whether the GUI is
70
	 *  {@link BidiComplexEnvironment#mirrored mirrored} and may
71
	 *  may be different for Arabic and for Hebrew.
72
	 *  This constant can appear as <code>dirArabic</code>
73
	 *  or <code>dirHebrew</code> argument for
74
	 *  {@link BidiComplexFeatures#BidiComplexFeatures BidiComplexFeatures constructor} and as value
75
	 *  for the {@link #dirArabic} or {@link #dirHebrew} members of
76
	 *  <code>BidiComplexFeatures</code>.
77
	 */
78
	public static final int DIR_RTL = 1;
79
80
	/**
81
	 *  Pre-defined <code>BidiComplexFeatures</code> instance with values for no
82
	 *  operators, no special processing, all directions LTR
83
	 *  and support for neither Arabic nor Hebrew.<br>
84
	 *  Since there are no operators and no special processing, a complex
85
	 *  expression processor with such features would do nothing.<br>
86
	 *  It is more efficient to do nothing with a
87
	 *  {@link BidiComplexHelper#BidiComplexHelper() BidiComplexHelper}
88
	 *  instantiated with no arguments.
89
	 */
90
	public static final BidiComplexFeatures DEFAULT = new BidiComplexFeatures(null, 0, -1, -1, true, true);
91
92
	/**
93
	 *  String grouping one-character operators which
94
	 *  separate the text of the complex expression into tokens.
95
	 */
96
	public final String operators;
97
98
	/**
99
	 *  Number of special cases for the associated processor.
100
	 *  Special cases exist for some types of complex expression processors.
101
	 *  They are implemented by overriding methods
102
	 *  {@link IBidiComplexProcessor#indexOfSpecial indexOfSpecial} and
103
	 *  {@link IBidiComplexProcessor#processSpecial processSpecial}.
104
	 *  Examples of special cases are comments, literals, or anything which
105
	 *  is not identified by a one-character operator.
106
	 */
107
	public final int specialsCount;
108
109
	/**
110
	 *  Base direction of the complex expression for Arabic.
111
	 *  If a complex expression contains both Arabic and
112
	 *  Hebrew words, the first Arabic or Hebrew letter in the
113
	 *  expression determines which is the governing script).<br>
114
	 *  The value of this field must be one of
115
	 *  {@link #DIR_LTR} or {@link #DIR_RTL}.
116
	 *
117
	 *  @see #dirHebrew
118
	 */
119
	public final int dirArabic;
120
121
	/**
122
	 *  Base direction of the complex expression for Hebrew.
123
	 *  If a complex expression contains both Arabic and
124
	 *  Hebrew words, the first Arabic or Hebrew letter in the
125
	 *  expression determines which is the governing script).<br>
126
	 *  The value of this field must be one of
127
	 *  {@link #DIR_LTR} or {@link #DIR_RTL}.
128
	 *
129
	 *  @see #dirArabic
130
	 */
131
	public final int dirHebrew;
132
133
	/**
134
	 *  Flag indicating that Arabic letters will not be considered for
135
	 *  processing complex expressions. If both this flag and
136
	 *  {@link #ignoreHebrew} are set to <code>true</code>, the
137
	 *  processor will do nothing (but some overhead can be expected).
138
	 */
139
	public final boolean ignoreArabic;
140
141
	/**
142
	 *  Flag indicating that Hebrew letters will not be considered for
143
	 *  processing complex expressions. If both this flag and
144
	 *  {@link #ignoreArabic} are set to <code>true</code>, the
145
	 *  processor will do nothing (but some overhead can be expected).
146
	 */
147
	public final boolean ignoreHebrew;
148
149
	/**
150
	 *  Constructor
151
	 *
152
	 *  @param operators is a string where each character is a delimiter
153
	 *          which separates the complex expression into tokens.
154
	 *  @see #operators
155
	 *
156
	 *  @param specialsCount specifies the number of special cases handled
157
	 *          by the processor.
158
	 *  @see #specialsCount
159
	 *
160
	 *  @param dirArabic specifies the base direction of the complex expression
161
	 *          for Arabic. It must be {@link #DIR_LTR} or {@link #DIR_RTL}.
162
	 *          If it is not (for instance if it is a negative value), it
163
	 *          defaults to <code>DIR_LTR</code>.
164
	 *  @see #dirArabic
165
	 *
166
	 *  @param dirHebrew specifies the base direction of the complex expression
167
	 *          for Hebrew. It must be {@link #DIR_LTR} or {@link #DIR_RTL}.
168
	 *          If it is not (for instance if it is a negative value), it
169
	 *          defaults to <code>DIR_LTR</code>.
170
	 *  @see #dirHebrew
171
	 *
172
	 *  @param ignoreArabic indicates that Arabic letters will not be
173
	 *          considered for processing complex expressions.
174
	 *  @see #ignoreArabic
175
	 *
176
	 *  @param ignoreHebrew indicates that Hebrew letters will not be
177
	 *          considered for processing complex expressions.
178
	 *  @see #ignoreHebrew
179
	 */
180
	public BidiComplexFeatures(String operators, int specialsCount, int dirArabic, int dirHebrew, boolean ignoreArabic, boolean ignoreHebrew) {
181
182
		this.operators = operators == null ? "" : operators; //$NON-NLS-1$
183
		this.specialsCount = specialsCount;
184
		this.dirArabic = dirArabic == DIR_LTR || dirArabic == DIR_RTL ? dirArabic : DIR_LTR;
185
		this.dirHebrew = dirHebrew == DIR_LTR || dirHebrew == DIR_RTL ? dirHebrew : DIR_LTR;
186
		this.ignoreArabic = ignoreArabic;
187
		this.ignoreHebrew = ignoreHebrew;
188
	}
189
190
}
(-)src/org/eclipse/equinox/bidi/BidiComplexHelper.java (+574 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi;
12
13
import org.eclipse.equinox.bidi.custom.IBidiComplexProcessor;
14
15
import org.eclipse.equinox.bidi.custom.BidiComplexStringProcessor;
16
17
import org.eclipse.equinox.bidi.internal.BidiComplexImpl;
18
19
/**
20
 *  This class acts as a mediator between applications and complex
21
 *  expression processors.
22
 *  The purpose of complex expression processors is to add directional
23
 *  formatting characters to ensure correct display.
24
 *  This class shields applications from the
25
 *  intricacies of complex expression processors.
26
 *  <p>
27
 *  For a general introduction to complex expressions, see
28
 *  {@link <a href="package-summary.html">
29
 *  the package documentation</a>}.
30
 *
31
 *  <h2>Code Sample</h2>
32
 *
33
 *  <p>The following code shows how to instantiate a BidiComplexHelper adapted for a
34
 *  certain type of complex expression (directory and file paths), and how
35
 *  to obtain the <i>full</i> text corresponding to the <i>lean</i> text
36
 *  of such an expression.
37
 *
38
 *  <pre>
39
 *
40
 *    BidiComplexHelper helper = new BidiComplexHelper(IBidiComplexExpressionTypes.FILE);
41
 *    String leanText = "D:\\\u05d0\u05d1\\\u05d2\\\u05d3.ext";
42
 *    String fullText = helper.leanToFullText(leanText);
43
 *    System.out.println("full text = " + fullText);
44
 *
45
 *  </pre>
46
 *  This class provides a user-oriented API but does not provides
47
 *  an actual implementation. The real work is done by the class
48
 *  {@link BidiComplexImpl}. Users of the API need not be concerned by, and
49
 *  should not depend upon, details of the implementation by
50
 *  <code>BidiComplexImpl</code>.
51
 *
52
 *  @author Matitiahu Allouche
53
 *
54
 */
55
public class BidiComplexHelper {
56
	/**
57
	 *  Constant to use as <code>initState</code> argument when calling
58
	 *  {@link #leanToFullText(java.lang.String, int) leanToFullText} or
59
	 *  {@link #fullToLeanText(java.lang.String, int) fullToLeanText}
60
	 *  to indicate that there is no context of previous lines which
61
	 *  should be initialized before performing the operation.
62
	 */
63
	public static final int STATE_NOTHING_GOING = -1;
64
65
	private static final int[] EMPTY_INT_ARRAY = new int[0];
66
67
	/**
68
	 *  Reference to the {@link BidiComplexImpl} instance which accomplishes
69
	 *  most of the work. This member should be accessed only by
70
	 *  complex expression processors (implementing {@link IBidiComplexProcessor}).
71
	 */
72
	public BidiComplexImpl impl;
73
74
	/**
75
	 *  Create a <code>BidiComplexHelper</code> instance which does nothing tangible
76
	 *  but does it quickly. We will call it a <i>no-op helper</i>.
77
	 *  The {@link #BidiComplexHelper() no-op helper} does not modify text submitted to it, and can be
78
	 *  used when it is known that no complex expression processing
79
	 *  is needed, for instance because no bidi text is expected. With this
80
	 *  helper, the cost of invoking the complex expression API is minimal.
81
	 */
82
	public BidiComplexHelper() {
83
		// let impl stay null
84
	}
85
86
	/**
87
	 *  Create a <code>BidiComplexHelper</code> instance to process expressions
88
	 *  of type <code>type</code> with a
89
	 *  {@link BidiComplexEnvironment#DEFAULT DEFAULT} environment.
90
	 *
91
	 *  @param type represents the type of the complex expression. It must
92
	 *          be one of the values in {@link IBidiComplexExpressionTypes}, or a type
93
	 *          added in a plug-in extension.
94
	 *
95
	 *  @throws IllegalArgumentException if the <code>type</code> is not
96
	 *          supported.
97
	 */
98
	public BidiComplexHelper(String type) {
99
		this(type, null);
100
	}
101
102
	/**
103
	 *  Create a <code>BidiComplexHelper</code> instance to process expressions
104
	 *  of type <code>type</code> operating under the environment
105
	 *  {@link BidiComplexEnvironment environment}.
106
	 *
107
	 *  @param type represents the type of the complex expression. It must
108
	 *          be one of the values in {@link IBidiComplexExpressionTypes}, or a type
109
	 *          added in a plug-in extension.
110
	 *
111
	 *  @param environment represents the environment where the complex expression
112
	 *          will be displayed. It is better to specify the environment
113
	 *          when instantiating a <code>BidiComplexHelper</code> than to specify
114
	 *          it later using {@link #setEnvironment setEnvironment}.<br>
115
	 *          <code>null</code> can be specified here for a
116
	 *          {@link BidiComplexEnvironment#DEFAULT DEFAULT} environment.
117
	 *
118
	 *  @throws IllegalArgumentException if the <code>type</code> is not
119
	 *          supported.
120
	 */
121
	public BidiComplexHelper(String type, BidiComplexEnvironment environment) {
122
		IBidiComplexProcessor processor = BidiComplexStringProcessor.getProcessor(type);
123
		if (processor == null) {
124
			throw new IllegalArgumentException("Invalid processor type!"); //$NON-NLS-1$
125
		}
126
		impl = new BidiComplexImpl(this, processor, environment);
127
	}
128
129
	/**
130
	 *  Create a <code>BidiComplexHelper</code> instance to process complex
131
	 *  expressions by means of a given processor <code>myProcessor</code>,
132
	 *  operating under the environment {@link BidiComplexEnvironment environment}.
133
	 *
134
	 *  @param myProcessor is a complex expression processor.
135
	 *
136
	 *  @param environment represents the environment where the complex expression
137
	 *          will be displayed. It is better to specify the environment
138
	 *          when instantiating a <code>BidiComplexHelper</code> than to specify
139
	 *          it later using {@link #setEnvironment setEnvironment}.<br>
140
	 *          <code>null</code> can be specified here for a
141
	 *          {@link BidiComplexEnvironment#DEFAULT DEFAULT} environment.
142
	 */
143
	public BidiComplexHelper(IBidiComplexProcessor myProcessor, BidiComplexEnvironment environment) {
144
		impl = new BidiComplexImpl(this, myProcessor, environment);
145
	}
146
147
	/** Add directional formatting characters to a complex expression
148
	 *  to ensure correct presentation.
149
	 *
150
	 *  @param text is the text of the complex expression.
151
	 *
152
	 *  @return the complex expression with directional formatting
153
	 *          characters added at proper locations to ensure correct
154
	 *          presentation.<br>
155
	 *          The {@link #BidiComplexHelper() no-op helper} returns <code>text</code>.
156
	 */
157
	public String leanToFullText(String text) {
158
		return leanToFullText(text, STATE_NOTHING_GOING);
159
	}
160
161
	/**
162
	 *  Add directional formatting characters to a complex expression
163
	 *  to ensure correct presentation.
164
	 *
165
	 *  @param  text is the text of the complex expression.
166
	 *
167
	 *  @param  initState specifies that the first parameter is the
168
	 *          continuation of text submitted in a previous call.
169
	 *          The <code>initState</code> of the present call must be
170
	 *          the final state obtained by calling
171
	 *          {@link #getFinalState() getFinalState}
172
	 *          after the previous call.
173
	 *          <br>If the present call is not a continuation of
174
	 *          text submitted in a previous call, the value
175
	 *          {@link #STATE_NOTHING_GOING} should be used as argument.
176
	 *
177
	 *  @return the complex expression with directional formatting
178
	 *          characters added at proper locations to ensure correct
179
	 *          presentation.<br>
180
	 *          The {@link #BidiComplexHelper() no-op helper} returns <code>text</code>.
181
	 *
182
	 *  @see #getFinalState getFinalState
183
	 */
184
	public String leanToFullText(String text, int initState) {
185
		if (impl == null)
186
			return text;
187
		return impl.leanToFullText(text, initState);
188
	}
189
190
	/**
191
	 *  Given a complex expression, get the offsets of characters before
192
	 *  which directional formatting characters must be added in order to
193
	 *  ensure correct presentation.
194
	 *  Only LRMs (for an expression with LTR base direction) and RLMs (for
195
	 *  an expression with RTL base direction) are considered. Leading and
196
	 *  trailing LRE, RLE and PDF which might be prefixed or suffixed
197
	 *  depending on the {@link BidiComplexEnvironment#orientation orientation} of the
198
	 *  GUI component used for display are not reflected in this method.
199
	 *  <p>
200
	 *  This method assumes that a successful call to
201
	 *  {@link #leanToFullText leanToFullText} has been performed, and it
202
	 *  returns the offsets relevant for the last text submitted.
203
	 *
204
	 *  @return an array of offsets to the characters in the last submitted
205
	 *          complex expression before which directional marks must be
206
	 *          added to ensure correct presentation.
207
	 *          The offsets are sorted in ascending order.<br>
208
	 *          The {@link #BidiComplexHelper() no-op helper} returns an array of 0 elements.
209
	 */
210
	public int[] leanBidiCharOffsets() {
211
		if (impl == null)
212
			return EMPTY_INT_ARRAY;
213
		return impl.leanBidiCharOffsets();
214
	}
215
216
	/**
217
	 *  Get the offsets of characters in the <i>full</i> text of a
218
	 *  complex expression corresponding to directional formatting
219
	 *  characters which have been added in order to ensure correct presentation.
220
	 *  LRMs (for an expression with LTR base direction), RLMs (for
221
	 *  an expression with RTL base direction) are considered as well as
222
	 *  leading and trailing LRE, RLE and PDF which might be prefixed or suffixed
223
	 *  depending on the {@link BidiComplexEnvironment#orientation orientation} of the
224
	 *  GUI component used for display.
225
	 *  <p>
226
	 *  This method assumes that a successful call to
227
	 *  {@link #leanToFullText leanToFullText} has been performed, and it
228
	 *  returns the offsets relevant for the last text submitted.
229
	 *
230
	 *  @return an array of offsets to the characters in the <i>full</i>
231
	 *          text of the last submitted complex expression which are
232
	 *          directional formatting characters added to ensure correct
233
	 *          presentation.
234
	 *          The offsets are sorted in ascending order.<br>
235
	 *          The {@link #BidiComplexHelper() no-op helper} returns an array of 0 elements.
236
	 */
237
	public int[] fullBidiCharOffsets() {
238
		if (impl == null)
239
			return EMPTY_INT_ARRAY;
240
		return impl.fullBidiCharOffsets();
241
	}
242
243
	/**
244
	 *  Remove directional formatting characters which were added to a
245
	 *  complex expression to ensure correct presentation.
246
	 *
247
	 *  @param text is the text of the complex expression including
248
	 *         directional formatting characters.
249
	 *
250
	 *  @return the complex expression without directional formatting
251
	 *          characters which might have been added by processing it
252
	 *          with {@link #leanToFullText leanToFullText}.<br>
253
	 *          The {@link #BidiComplexHelper() no-op helper} returns <code>text</code>
254
	 *
255
	 */
256
	public String fullToLeanText(String text) {
257
		return fullToLeanText(text, STATE_NOTHING_GOING);
258
	}
259
260
	/**
261
	 *  Remove directional formatting characters which were added to a
262
	 *  complex expression to ensure correct presentation.
263
	 *
264
	 *  @param text is the text of the complex expression including
265
	 *         directional formatting characters.
266
	 *
267
	 *  @param initState specifies that the first parameter is the
268
	 *         continuation of text submitted in a previous call.
269
	 *         The <code>initState</code> of the present call must be
270
	 *         the final state obtained by calling
271
	 *         {@link #getFinalState getFinalState} after the previous call.
272
	 *          <br>If the present call is not a continuation of
273
	 *          text submitted in a previous call, the value
274
	 *          {@link #STATE_NOTHING_GOING} should be used as argument.
275
	 *
276
	 *  @return the complex expression without directional formatting
277
	 *          characters which might have been added by processing it
278
	 *          with {@link #leanToFullText leanToFullText}.<br>
279
	 *          The {@link #BidiComplexHelper() no-op helper} returns <code>text</code>
280
	 *
281
	 *  @see #getFinalState getFinalState
282
	 */
283
	public String fullToLeanText(String text, int initState) {
284
		if (impl == null)
285
			return text;
286
		return impl.fullToLeanText(text, initState);
287
	}
288
289
	/**
290
	 *  Retrieve the final state achieved in a previous call to
291
	 *  {@link #leanToFullText leanToFullText} or
292
	 *  {@link #fullToLeanText fullToLeanText}.
293
	 *  This state is an opaque value which is meaningful only
294
	 *  within calls to the same complex expression processor.
295
	 *  The only externalized value is
296
	 *  {@link #STATE_NOTHING_GOING} which means that
297
	 *  there is nothing to remember from the last call.
298
	 *  <p>
299
	 *  The state should be used only for complex expressions which come
300
	 *  in parts, like when spanning multiple lines. The user can make
301
	 *  a separate call to
302
	 *  <code>leanToFullText</code> or <code>fullToLeanText</code> for each
303
	 *  line in the expression. The final state value retrieved after the
304
	 *  call for one line should be used as the initial state in the call
305
	 *  which processes the next line.
306
	 *  <p>
307
	 *  If a line within a complex expression has already been processed by
308
	 *  <code>leanToFullText</code> and the <i>lean</i> version of that line has
309
	 *  not changed, and its initial state has not changed either, the user
310
	 *  can be sure that the <i>full</i> version of that line is also
311
	 *  identical to the result of the previous processing.
312
	 *
313
	 *  @see #leanToFullText(String text, int initState)
314
	 *  @see #fullToLeanText(String text, int initState)
315
	 *
316
	 *  @return the last final state.<br>
317
	 *          The {@link #BidiComplexHelper() no-op helper} returns {@link #STATE_NOTHING_GOING}.
318
	 */
319
	public int getFinalState() {
320
		if (impl == null)
321
			return STATE_NOTHING_GOING;
322
		return impl.getFinalState();
323
	}
324
325
	/**
326
	 *  After transforming a <i>lean</i> string into a <i>full</i> string
327
	 *  using {@link #leanToFullText leanToFullText}, compute the index in the
328
	 *  <i>full</i> string of the character corresponding to the
329
	 *  character with the specified position in the <i>lean</i> string.
330
	 *
331
	 *  @param position is the index of a character in the <i>lean</i> string.
332
	 *          It must be a non-negative number smaller than the length
333
	 *          of the <i>lean</i> text.
334
	 *
335
	 *  @return the index of the corresponding character in the
336
	 *          <i>full</i> string.<br>
337
	 *          The {@link #BidiComplexHelper() no-op helper} returns <code>position</code>.
338
	 */
339
	public int leanToFullPos(int position) {
340
		if (impl == null)
341
			return position;
342
		return impl.leanToFullPos(position);
343
	}
344
345
	/**
346
	 *  After transforming a <i>lean</i> string into a <i>full</i> string
347
	 *  using {@link #leanToFullText leanToFullText}, compute the index in the
348
	 *  <i>lean</i> string of the character corresponding to the
349
	 *  character with the specified position in the <i>full</i> string.
350
	 *
351
	 *  @param position is the index of a character in the <i>full</i> string.
352
	 *          It must be a non-negative number smaller than the length
353
	 *          of the <i>full</i> text.
354
	 *
355
	 *  @return the index of the corresponding character in the
356
	 *          <i>lean</i> string. If there is no corresponding
357
	 *          character in the <i>lean</i> string (because the
358
	 *          specified character is a directional formatting character
359
	 *          added when invoking {@link #leanToFullText leanToFullText}),
360
	 *          the value returned will be that corresponding to the
361
	 *          next character which is not a directional formatting
362
	 *          character.<br>
363
	 *          If <code>position</code> corresponds to a directional formatting
364
	 *          character beyond all characters of the original
365
	 *          <i>lean</i> text, the value returned is the length of the
366
	 *          <i>lean</i> text.<br>
367
	 *          The {@link #BidiComplexHelper() no-op helper} returns <code>position</code>.
368
	 */
369
	public int fullToLeanPos(int position) {
370
		if (impl == null)
371
			return position;
372
		return impl.fullToLeanPos(position);
373
	}
374
375
	/**
376
	 *  Get the base direction of the complex expression last
377
	 *  submitted to {@link #leanToFullText leanToFullText}.
378
	 *  This base direction may depend on
379
	 *  whether the expression contains Arabic or Hebrew words
380
	 *  (if it contains both, the first Arabic or Hebrew letter in the
381
	 *  expression determines which is the governing script) and on
382
	 *  whether the GUI is {@link BidiComplexEnvironment#mirrored mirrored}.
383
	 *
384
	 *  @return the base direction of the last submitted complex
385
	 *          expression. It must be one of the values
386
	 *          {@link BidiComplexFeatures#DIR_LTR} or {@link BidiComplexFeatures#DIR_RTL}.<br>
387
	 *          The {@link #BidiComplexHelper() no-op helper} returns <code>DIR_LTR</code>.
388
	 */
389
	public int getCurDirection() {
390
		if (impl == null)
391
			return BidiComplexFeatures.DIR_LTR;
392
		return impl.getCurDirection();
393
	}
394
395
	/**
396
	 *  Get the current environment under which the <code>BidiComplexHelper</code>
397
	 *  operates.
398
	 *  This environment may have been specified in the constructor or
399
	 *  specified later using {@link #setEnvironment setEnvironment}.<br>
400
	 *
401
	 *  @return the current environment.<br>
402
	 *          The {@link #BidiComplexHelper() no-op helper} returns a {@link BidiComplexEnvironment#DEFAULT DEFAULT}
403
	 *          environment.
404
	 *
405
	 *  @see #setEnvironment setEnvironment
406
	 */
407
	public BidiComplexEnvironment getEnvironment() {
408
		if (impl == null)
409
			return BidiComplexEnvironment.DEFAULT;
410
		return impl.getEnvironment();
411
	}
412
413
	/**
414
	 *  Specify the environment under which the <code>BidiComplexHelper</code>
415
	 *  must operate.
416
	 *  <p>
417
	 *  <b>Note</b> that calling this method causes the processor
418
	 *  associated with this instance of <code>BidiComplexHelper</code>
419
	 *  to re-initialize its features. The effect of a previous call
420
	 *  to {@link #setFeatures(BidiComplexFeatures) setFeatures} is lost.<br>
421
	 *  The {@link #BidiComplexHelper() no-op helper} does nothing.
422
	 *
423
	 *  @see #getEnvironment getEnvironment
424
	 *  @see IBidiComplexProcessor#updateEnvironment IBidiComplexProcessor.updateEnvironment
425
	 */
426
	public void setEnvironment(BidiComplexEnvironment environment) {
427
		if (impl == null) {
428
			return; // do nothing
429
		}
430
		impl.setEnvironment(environment);
431
	}
432
433
	/**
434
	 *  Get the current features of the processor associated with this
435
	 *  <code>BidiComplexHelper</code> instance.
436
	 *
437
	 *  @return the current features.<br>
438
	 *          The {@link #BidiComplexHelper() no-op helper} returns {@link BidiComplexFeatures#DEFAULT DEFAULT}
439
	 *          features.
440
	 *
441
	 *  @see #setFeatures setFeatures
442
	 */
443
	public BidiComplexFeatures getFeatures() {
444
		if (impl == null)
445
			return BidiComplexFeatures.DEFAULT;
446
		return impl.getFeatures();
447
	}
448
449
	/**
450
	 *  Specify the features to be applied to the processor associated with this
451
	 *  <code>BidiComplexHelper</code> instance.
452
	 *  Note that the value of {@link BidiComplexFeatures#specialsCount specialsCount}
453
	 *  cannot be changed (the new value will be ignored).<br>
454
	 *  The {@link #BidiComplexHelper() no-op helper} does nothing.
455
	 *
456
	 *  @see #getFeatures getFeatures
457
	 */
458
	public void setFeatures(BidiComplexFeatures features) {
459
		if (impl == null) {
460
			return; // do nothing
461
		}
462
		impl.setFeatures(features);
463
	}
464
465
	/**
466
	 *  This method can be called from within
467
	 *  {@link IBidiComplexProcessor#indexOfSpecial indexOfSpecial} or
468
	 *  {@link IBidiComplexProcessor#processSpecial processSpecial} in implementations
469
	 *  of {@link IBidiComplexProcessor} to retrieve the bidirectional class of
470
	 *  characters in the <i>lean</i> text.
471
	 *
472
	 *  @param index position of the character in the <i>lean</i> text.
473
	 *          It must be a non-negative number smaller than the length
474
	 *          of the <i>lean</i> text.
475
	 *
476
	 *  @return the bidirectional class of the character. It is one of the
477
	 *          values which can be returned by
478
	 *          <code>java.lang.Character#getDirectionality</code>.
479
	 *          However, it is recommended to use <code>getDirProp</code>
480
	 *          rather than <code>java.lang.Character.getDirectionality</code>
481
	 *          since <code>getDirProp</code> manages a cache of character
482
	 *          properties and so can be more efficient than calling the
483
	 *          java.lang.Character method.<br>
484
	 *          The {@link #BidiComplexHelper() no-op helper} returns
485
	 *          <code>Character.DIRECTIONALITY_UNDEFINED</code>.
486
	 */
487
	public byte getDirProp(int index) {
488
		if (impl == null)
489
			return Character.DIRECTIONALITY_UNDEFINED;
490
		return impl.getDirProp(index);
491
	}
492
493
	/**
494
	 *  This method can be called from within
495
	 *  {@link IBidiComplexProcessor#indexOfSpecial indexOfSpecial} or
496
	 *  {@link IBidiComplexProcessor#processSpecial processSpecial} in implementations
497
	 *  of {@link IBidiComplexProcessor} to set or override the bidirectional
498
	 *  class of characters in the <i>lean</i> text.
499
	 *
500
	 *  @param index position of the character in the <i>lean</i> text.
501
	 *          It must be a non-negative number smaller than the length
502
	 *          of the <i>lean</i> text.
503
	 *
504
	 *  @param  dirProp bidirectional class of the character. It is one of the
505
	 *          values which can be returned by
506
	 *          <code>java.lang.Character.getDirectionality</code>.<br>
507
	 *          The {@link #BidiComplexHelper() no-op helper} does nothing.
508
	 */
509
	public void setDirProp(int index, byte dirProp) {
510
		if (impl != null)
511
			impl.getDirProp(index);
512
	}
513
514
	/**
515
	 *  This method can be called from within
516
	 *  {@link IBidiComplexProcessor#indexOfSpecial indexOfSpecial} or
517
	 *  {@link IBidiComplexProcessor#processSpecial processSpecial} in implementations
518
	 *  of {@link IBidiComplexProcessor}
519
	 *  to specify that a mark character must be added before the character
520
	 *  at the specified position of the <i>lean</i> text when generating the
521
	 *  <i>full</i> text. The mark character will be LRM for complex expressions
522
	 *  with a LTR base direction, and RLM for complex expressions with RTL
523
	 *  base direction. The mark character is not added physically by this
524
	 *  method, but its position is noted and will be used when generating
525
	 *  the <i>full</i> text.
526
	 *
527
	 *  @param  offset position of the character in the <i>lean</i> text.
528
	 *          It must be a non-negative number smaller than the length
529
	 *          of the <i>lean</i> text.
530
	 *          For the benefit of efficiency, it is better to insert
531
	 *          multiple marks in ascending order of the offsets.<br>
532
	 *          The {@link #BidiComplexHelper() no-op helper} does nothing.
533
	 */
534
	public void insertMark(int offset) {
535
		if (impl != null)
536
			impl.insertMark(offset);
537
	}
538
539
	/**
540
	 *  This method can be called from within
541
	 *  {@link IBidiComplexProcessor#indexOfSpecial indexOfSpecial} or
542
	 *  {@link IBidiComplexProcessor#processSpecial processSpecial} in
543
	 *  implementations of {@link IBidiComplexProcessor} to add a
544
	 *  directional mark before an
545
	 *  operator if needed for correct display, depending on the
546
	 *  base direction of the expression and on the class of the
547
	 *  characters in the <i>lean</i> text preceding and following
548
	 *  the operator itself.<br>
549
	 *  The {@link #BidiComplexHelper() no-op helper} does nothing.
550
	 *
551
	 *  @param  operLocation offset of the operator in the <i>lean</i> text.
552
	 *          It must be a non-negative number smaller than the length
553
	 *          of the <i>lean</i> text.
554
	 */
555
	public void processOperator(int operLocation) {
556
		if (impl != null)
557
			impl.processOperator(operLocation);
558
	}
559
560
	/**
561
	 *  This method can be called from within
562
	 *  {@link IBidiComplexProcessor#indexOfSpecial indexOfSpecial} or
563
	 *  {@link IBidiComplexProcessor#processSpecial processSpecial} in
564
	 *  implementations of {@link IBidiComplexProcessor} to
565
	 *  set the final state which should be used for the next call to
566
	 *  {@link #leanToFullText(java.lang.String, int)}.<br>
567
	 *  The {@link #BidiComplexHelper() no-op helper} does nothing.
568
	 */
569
	public void setFinalState(int newState) {
570
		if (impl != null)
571
			impl.setFinalState(newState);
572
	}
573
574
}
(-)src/org/eclipse/equinox/bidi/BidiComplexStringRecord.java (+196 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi;
12
13
import org.eclipse.equinox.bidi.custom.BidiComplexStringProcessor;
14
15
import java.lang.ref.SoftReference;
16
17
/**
18
 * This class records strings which are complex expressions. Several static
19
 * methods in this class allow to record such strings in a pool, and to find if
20
 * a given string is member of the pool.
21
 * <p>
22
 * Instances of this class are the records which are members of the pool.
23
 * <p>
24
 * The pool is managed as a cyclic list, each new element overrides the oldest
25
 * element in the list.
26
 */
27
public class BidiComplexStringRecord {
28
	/**
29
	 * Number of entries in the pool of recorded strings
30
	 */
31
	public static final int POOLSIZE = 100;
32
33
	// maximum index allowed
34
	private static final int MAXINDEX = POOLSIZE - 1;
35
36
	// index of the last entered record
37
	private static int last = MAXINDEX;
38
39
	// the pool
40
	private static BidiComplexStringRecord[] records = new BidiComplexStringRecord[POOLSIZE];
41
42
	// complex expression types
43
	private static final String[] types = BidiComplexStringProcessor.getKnownTypes();
44
45
	// maximum type index allowed
46
	private static int MAXTYPE = types.length - 1;
47
48
	// reference to the recorded string
49
	private SoftReference strRef;
50
51
	// hash code of the recorded string
52
	private int hash;
53
54
	// reference to the triplets of the recorded string
55
	private SoftReference triRef;
56
57
	/**
58
	 * Constructor.
59
	 * 
60
	 * @param string
61
	 *            the string to record
62
	 * 
63
	 * @param triplets
64
	 *            array of short integers, the number of elements in the array
65
	 *            must be a multiple of 3, so that the array is made of one or
66
	 *            more triplets of short integers.
67
	 *            <p>
68
	 *            The first element in each triplet is the beginning index of a
69
	 *            susbstring of <code>string</code> which is a complex
70
	 *            expression.
71
	 *            <p>
72
	 *            The second element in each triplet is the ending index of a
73
	 *            susbstring of <code>string</code> which is a complex
74
	 *            expression. This index points to one position beyond the last
75
	 *            character of the substring.
76
	 *            <p>
77
	 *            The third element in each triplet is the numeric type of the
78
	 *            complex expression.<br>
79
	 *            The type of a complex expression must be one of the string
80
	 *            values listed in {@link IBidiComplexExpressionTypes}.<br>
81
	 *            The corresponding numeric type must be obtained using the
82
	 *            method {@link #typeStringToShort typeStringToShort}.
83
	 */
84
	public BidiComplexStringRecord(String string, short[] triplets) {
85
		if (string == null || triplets == null || (triplets.length % 3) != 0)
86
			throw new IllegalArgumentException();
87
		for (int i = 2; i < triplets.length; i += 3)
88
			if (triplets[i] < 0 || triplets[i] > MAXTYPE)
89
				throw new IllegalArgumentException();
90
		strRef = new SoftReference(string);
91
		triRef = new SoftReference(triplets);
92
		hash = string.hashCode();
93
	}
94
95
	/**
96
	 * Get the numeric type of a complex expression given its string type.
97
	 * 
98
	 * @param type
99
	 *            type of complex expression as string. It must be one of the
100
	 *            strings listed in {@link IBidiComplexExpressionTypes}.
101
	 * 
102
	 * @return a value which is the corresponding numeric type. If
103
	 *         <code>type</code> is invalid, the method returns <code>-1</code>.
104
	 */
105
	public static short typeStringToShort(String type) {
106
		for (int i = 0; i < types.length; i++)
107
			if (types[i].equals(type))
108
				return (short) i;
109
		return -1;
110
	}
111
112
	/**
113
	 * Get the string type of a complex expression given its numeric type.
114
	 * 
115
	 * @param shType
116
	 *            the numeric type of a complex expression. It should be a value
117
	 *            obtained using {@link #typeStringToShort typeStringToShort}.
118
	 * 
119
	 * @return the corresponding string type. If <code>shType</code> is invalid,
120
	 *         the method returns <code>null</code>.
121
	 */
122
	public static String typeShortToString(short shType) {
123
		if (shType < 0 || shType > MAXTYPE)
124
			return null;
125
		return types[shType];
126
	}
127
128
	/**
129
	 * /** Add a record to the pool.
130
	 * 
131
	 * @param record
132
	 *            a BidiComplexStringRecord instance
133
	 */
134
	public static synchronized void add(BidiComplexStringRecord record) {
135
		if (last < MAXINDEX)
136
			last++;
137
		else
138
			last = 0;
139
		records[last] = record;
140
	}
141
142
	/**
143
	 * Check if a string is recorded and retrieve its triplets.
144
	 * 
145
	 * @param string
146
	 *            the string to check
147
	 * 
148
	 * @return <code>null</code> if the string is not recorded in the pool;
149
	 *         otherwise, return the triplets associated with this string.
150
	 */
151
	public static short[] getTriplets(String string) {
152
		if (records[0] == null) // no records at all
153
			return null;
154
		if (string == null || string.length() < 1)
155
			return null;
156
		BidiComplexStringRecord rec;
157
		String str;
158
		short[] tri;
159
		int myLast = last;
160
		int hash = string.hashCode();
161
		for (int i = myLast; i >= 0; i--) {
162
			rec = records[i];
163
			if (hash == rec.hash && (tri = (short[]) rec.triRef.get()) != null && (str = (String) rec.strRef.get()) != null && string.equals(str)) {
164
				return tri;
165
			}
166
		}
167
		if (records[MAXINDEX] == null) // never recorded past myLast
168
			return null;
169
		for (int i = MAXINDEX; i > myLast; i--) {
170
			rec = records[i];
171
			if (hash == rec.hash && (tri = (short[]) rec.triRef.get()) != null && (str = (String) rec.strRef.get()) != null && string.equals(str)) {
172
				return tri;
173
			}
174
		}
175
		return null;
176
	}
177
178
	/**
179
	 * Clear the pool. All elements of the pool are erased and any associated
180
	 * memory is freed.
181
	 * 
182
	 */
183
	public static synchronized void clear() {
184
		for (int i = 0; i <= MAXINDEX; i++) {
185
			BidiComplexStringRecord sr = records[i];
186
			if (sr == null)
187
				break;
188
			sr.hash = 0;
189
			sr.strRef.clear();
190
			sr.triRef.clear();
191
			records[i] = null;
192
		}
193
		last = MAXINDEX;
194
	}
195
196
}
(-)src/org/eclipse/equinox/bidi/BidiComplexUtil.java (+315 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi;
12
13
import org.eclipse.equinox.bidi.custom.BidiComplexProcessor;
14
15
/**
16
 *  This class provides a number of convenience functions facilitating the
17
 *  processing of complex expressions.
18
 *
19
 *  @noextend This class is not intended to be subclassed by clients.
20
 *  @noinstantiate This class is not intended to be instantiated by clients.
21
 *
22
 *  @author Matitiahu Allouche
23
 */
24
final public class BidiComplexUtil {
25
26
	/**
27
	 *  prevent instantiation
28
	 */
29
	private BidiComplexUtil() {
30
		// empty
31
	}
32
33
	/** This is a convenience method which can add directional marks in a given
34
	 *  text before the characters specified in the given array of offsets,
35
	 *  and can add a prefix and/or a suffix of directional formatting characters.
36
	 *  This can be used for instance after obtaining offsets by calling
37
	 *  {@link BidiComplexHelper#leanBidiCharOffsets() leanBidiCharOffsets} in order to
38
	 *  produce a <i>full</i> text corresponding to the source text.
39
	 *  The directional formatting characters that will be added at the given
40
	 *  offsets will be LRMs for expressions with LTR base direction and
41
	 *  RLMs for expressions with RTL base direction. Leading and
42
	 *  trailing LRE, RLE and PDF which might be needed as prefix or suffix
43
	 *  depending on the orientation of the GUI component used for display
44
	 *  may be added depending on argument <code>affix</code>.
45
	 *
46
	 *  @param  text is the text of the complex expression.
47
	 *
48
	 *  @param  offsets is an array of offsets to characters in <code>text</code>
49
	 *          before which an LRM or RLM will be inserted.
50
	 *          Members of the array must be non-negative numbers smaller
51
	 *          than the length of <code>text</code>.
52
	 *          The array must be sorted in ascending order without duplicates.
53
	 *          This argument may be null if there are no marks to add.
54
	 *
55
	 *  @param  direction specifies the base direction of the complex expression.
56
	 *          It must be one of the values {@link BidiComplexFeatures#DIR_LTR} or
57
	 *          {@link BidiComplexFeatures#DIR_RTL}.
58
	 *
59
	 *  @param  affix specifies if a prefix and a suffix should be added to
60
	 *          the result to make sure that the <code>direction</code>
61
	 *          specified as third argument is honored even if the expression
62
	 *          is displayed in a GUI component with a different orientation.
63
	 *
64
	 *  @return a string corresponding to the source <code>text</code> with
65
	 *          directional marks (LRMs or RLMs) added at the specified offsets,
66
	 *          and directional formatting characters (LRE, RLE, PDF) added
67
	 *          as prefix and suffix if so required.
68
	 */
69
	public static String insertMarks(String text, int[] offsets, int direction, boolean affix) {
70
		int textLen = text.length();
71
		if (textLen == 0)
72
			return ""; //$NON-NLS-1$
73
74
		String curPrefix, curSuffix, full;
75
		char curMark, c;
76
		char[] fullChars;
77
		if (direction == BidiComplexFeatures.DIR_LTR) {
78
			curMark = LRM;
79
			curPrefix = "\u202a\u200e"; /* LRE+LRM *///$NON-NLS-1$
80
			curSuffix = "\u200e\u202c"; /* LRM+PDF *///$NON-NLS-1$
81
		} else {
82
			curMark = RLM;
83
			curPrefix = "\u202b\u200f"; /* RLE+RLM *///$NON-NLS-1$
84
			curSuffix = "\u200f\u202c"; /* RLM+PDF *///$NON-NLS-1$
85
		}
86
		// add marks at offsets
87
		if ((offsets != null) && (offsets.length > 0)) {
88
			int offLen = offsets.length;
89
			fullChars = new char[textLen + offLen];
90
			int added = 0;
91
			for (int i = 0, j = 0; i < textLen; i++) {
92
				c = text.charAt(i);
93
				if ((j < offLen) && (i == offsets[j])) {
94
					fullChars[i + added] = curMark;
95
					added++;
96
					j++;
97
				}
98
				fullChars[i + added] = c;
99
			}
100
			full = new String(fullChars);
101
		} else {
102
			full = text;
103
		}
104
		if (affix)
105
			return curPrefix + full + curSuffix;
106
		return full;
107
	}
108
109
	/*************************************************************************/
110
	/*                                                                       */
111
	/*  The following code is provided for compatibility with TextProcessor  */
112
	/*                                                                       */
113
	/*************************************************************************/
114
115
	//  The default set of delimiters to use to segment a string.
116
	private static final String defaultDelimiters = ".:/\\"; //$NON-NLS-1$
117
	// left to right mark
118
	private static final char LRM = '\u200e';
119
	// left to right mark
120
	private static final char RLM = '\u200f';
121
	// left to right embedding
122
	private static final char LRE = '\u202a';
123
	// right to left embedding
124
	private static final char RLE = '\u202b';
125
	// pop directional format
126
	private static final char PDF = '\u202c';
127
128
	static boolean isProcessingNeeded() {
129
		if (!BidiComplexEnvironment.isSupportedOS())
130
			return false;
131
		return BidiComplexEnvironment.DEFAULT.isBidi();
132
	}
133
134
	/**
135
	 *  Process the given text and return a string with appropriate
136
	 *  directional formatting characters if the locale is a bidi locale.
137
	 *  This is equivalent to calling
138
	 *  {@link #process(String str, String delimiters)} with the default
139
	 *  set of delimiters (dot, colon, slash, backslash).
140
	 *
141
	 *  @param  str the text to be processed.
142
	 *
143
	 *  @return the processed string.
144
	 */
145
	public static String process(String str) {
146
		return process(str, defaultDelimiters);
147
	}
148
149
	/**
150
	 *  Process a string that has a particular semantic meaning to render
151
	 *  it correctly on bidi locales. This is done by adding directional
152
	 *  formatting characters so that presentation using the Unicode
153
	 *  Bidirectional Algorithm will provide the expected result.
154
	 *  The text is segmented according to the provided delimiters.
155
	 *  Each segment has the Unicode Bidi Algorithm applied to it,
156
	 *  but as a whole, the string is oriented left to right.
157
	 *  <p>
158
	 *  For example, a file path such as <tt>d:\myfolder\FOLDER\MYFILE.java</tt>
159
	 *  (where capital letters indicate RTL text) should render as
160
	 *  <tt>d:\myfolder\REDLOF\ELIFYM.java</tt>.</p>
161
	 *  <p>
162
	 *  NOTE: this method inserts directional formatting characters into the
163
	 *  text. Methods like <code>String.equals(String)</code> and
164
	 *  <code>String.length()</code> called on the resulting string will not
165
	 *  return the same values as would be returned for the original string.</p>
166
	 *
167
	 *  @param  str the text to process.
168
	 *
169
	 *  @param  delimiters delimiters by which the string will be segmented.
170
	 *          If <code>null</code>, the default delimiters are used
171
	 *          (dot, colon, slash, backslash).
172
	 *
173
	 *  @return the processed string.
174
	 *          If <code>str</code> is <code>null</code>,
175
	 *          or of length 0, or if the current locale is not a bidi one,
176
	 *          return the original string.
177
	 */
178
	public static String process(String str, String delimiters) {
179
		if ((str == null) || (str.length() <= 1) || !isProcessingNeeded())
180
			return str;
181
182
		// do not process a string that has already been processed.
183
		if (str.charAt(0) == LRE && str.charAt(str.length() - 1) == PDF)
184
			return str;
185
186
		// do not process a string if all the following conditions are true:
187
		//  a) it has no RTL characters
188
		//  b) it starts with a LTR character
189
		//  c) it ends with a LTR character or a digit
190
		boolean isStringBidi = false;
191
		int strLength = str.length();
192
		char c;
193
		for (int i = 0; i < strLength; i++) {
194
			c = str.charAt(i);
195
			if (((c >= 0x05d0) && (c <= 0x07b1)) || ((c >= 0xfb1d) && (c <= 0xfefc))) {
196
				isStringBidi = true;
197
				break;
198
			}
199
		}
200
		while (!isStringBidi) {
201
			if (!Character.isLetter(str.charAt(0)))
202
				break;
203
			c = str.charAt(strLength - 1);
204
			if (!Character.isDigit(c) && !Character.isLetter(c))
205
				break;
206
			return str;
207
		}
208
209
		if (delimiters == null)
210
			delimiters = defaultDelimiters;
211
212
		// make sure that LRE/PDF are added around the string
213
		BidiComplexEnvironment env = new BidiComplexEnvironment(null, false, BidiComplexEnvironment.ORIENT_UNKNOWN);
214
		BidiComplexHelper helper = new BidiComplexHelper(new BidiComplexProcessor(), env);
215
		helper.setFeatures(new BidiComplexFeatures(delimiters, 0, -1, -1, false, false));
216
		return helper.leanToFullText(str);
217
	}
218
219
	/**
220
	 *  Process a string that has a particular semantic meaning to render
221
	 *  it correctly on bidi locales. This is done by adding directional
222
	 *  formatting characters so that presentation using the Unicode
223
	 *  Bidirectional Algorithm will provide the expected result..
224
	 *  The text is segmented according to the syntax specified in the
225
	 *  <code>type</code> argument.
226
	 *  Each segment has the Unicode Bidi Algorithm applied to it, but the
227
	 *  order of the segments is governed by the type of the complex expression.
228
	 *  <p>
229
	 *  For example, a file path such as <tt>d:\myfolder\FOLDER\MYFILE.java</tt>
230
	 *  (where capital letters indicate RTL text) should render as
231
	 *  <tt>d:\myfolder\REDLOF\ELIFYM.java</tt>.</p>
232
	 *  <p>
233
	 *  NOTE: this method inserts directional formatting characters into the
234
	 *  text. Methods like <code>String.equals(String)</code> and
235
	 *  <code>String.length()</code> called on the resulting string will not
236
	 *  return the same values as would be returned for the original string.</p>
237
	 *
238
	 *  @param  str the text to process.
239
	 *
240
	 *  @param  type specifies the type of the complex expression. It must
241
	 *          be one of the values in {@link IBidiComplexExpressionTypes} or a value.
242
	 *          added by a plug-in extension.
243
	 *
244
	 *  @return the processed string.
245
	 *          If <code>str</code> is <code>null</code>,
246
	 *          or of length 0, or if the current locale is not a bidi one,
247
	 *          return the original string.
248
	 */
249
	public static String processTyped(String str, String type) {
250
		if ((str == null) || (str.length() <= 1) || !isProcessingNeeded())
251
			return str;
252
253
		// do not process a string that has already been processed.
254
		char c = str.charAt(0);
255
		if (((c == LRE) || (c == RLE)) && str.charAt(str.length() - 1) == PDF)
256
			return str;
257
258
		// make sure that LRE/PDF are added around the string
259
		BidiComplexEnvironment env = new BidiComplexEnvironment(null, false, BidiComplexEnvironment.ORIENT_UNKNOWN);
260
		BidiComplexHelper helper = new BidiComplexHelper(type, env);
261
		return helper.leanToFullText(str);
262
	}
263
264
	/**
265
	 *  Remove directional formatting characters in the given string that
266
	 *  were inserted by one of the {@link #process process} methods.
267
	 *
268
	 *  @param  str string with directional characters to remove.
269
	 *
270
	 *  @return string with no directional formatting characters.
271
	 */
272
	public static String deprocess(String str) {
273
		if ((str == null) || (str.length() <= 1) || !isProcessingNeeded())
274
			return str;
275
276
		StringBuffer buf = new StringBuffer();
277
		int strLen = str.length();
278
		for (int i = 0; i < strLen; i++) {
279
			char c = str.charAt(i);
280
			switch (c) {
281
				case LRM :
282
					continue;
283
				case LRE :
284
					continue;
285
				case PDF :
286
					continue;
287
				default :
288
					buf.append(c);
289
			}
290
		}
291
		return buf.toString();
292
	}
293
294
	/**
295
	 *  Remove directional formatting characters in the given string that
296
	 *  were inserted by the {@link #processTyped processTyped} method.
297
	 *
298
	 *  @param  str string with directional characters to remove.
299
	 *
300
	 *  @param  type type of the complex expression as specified when
301
	 *          calling {@link #processTyped processTyped}.
302
	 *
303
	 *  @return string with no directional formatting characters.
304
	 */
305
	public static String deprocess(String str, String type) {
306
		if ((str == null) || (str.length() <= 1) || !isProcessingNeeded())
307
			return str;
308
309
		// make sure that LRE/PDF are added around the string
310
		BidiComplexEnvironment env = new BidiComplexEnvironment(null, false, BidiComplexEnvironment.ORIENT_UNKNOWN);
311
		BidiComplexHelper helper = new BidiComplexHelper(type, env);
312
		return helper.fullToLeanText(str);
313
	}
314
315
}
(-)src/org/eclipse/equinox/bidi/IBidiComplexExpressionTypes.java (+106 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi;
12
13
/**
14
 * Bidirectional processors supplied in this bundle.
15
 *
16
 * @noextend This interface is not intended to be extended by clients.
17
 */
18
public interface IBidiComplexExpressionTypes {
19
20
	/**
21
	 * Constant indicating a type of complex expression processor adapted
22
	 * to processing property file statements. It expects the following
23
	 * string format:
24
	 * <pre>
25
	 *  name=value
26
	 * </pre>
27
	 */
28
	public String PROPERTY = "property"; //$NON-NLS-1$
29
30
	/**
31
	 * Constant indicating a type of complex expression processor adapted
32
	 * to processing compound names.
33
	 * This type covers names made of one or more parts separated by underscores:
34
	 * <pre>
35
	 *  part1_part2_part3
36
	 * </pre>
37
	 */
38
	public String UNDERSCORE = "underscore"; //$NON-NLS-1$
39
40
	/**
41
	 * Constant indicating a type of complex expression processor adapted
42
	 * to processing comma-delimited lists, such as:
43
	 * <pre>
44
	 *  part1,part2,part3
45
	 * </pre>
46
	 */
47
	public String COMMA_DELIMITED = "comma"; //$NON-NLS-1$
48
49
	/**
50
	 * Constant indicating a type of complex expression processor adapted
51
	 * to processing expressions with the following string format:
52
	 * <pre>
53
	 *  system(user)
54
	 * </pre>
55
	 */
56
	public String SYSTEM_USER = "system"; //$NON-NLS-1$
57
58
	/**
59
	 * Constant indicating a type of complex expression processor adapted
60
	 * to processing directory and file paths.
61
	 */
62
	public String FILE = "file"; //$NON-NLS-1$
63
64
	/**
65
	 *  Constant indicating a type of complex expression processor adapted
66
	 *  to processing e-mail addresses.
67
	 */
68
	public String EMAIL = "email"; //$NON-NLS-1$
69
70
	/**
71
	 *  Constant indicating a type of complex expression processor adapted
72
	 *  to processing URLs.
73
	 */
74
	public String URL = "url"; //$NON-NLS-1$
75
76
	/**
77
	 *  Constant indicating a type of complex expression processor adapted
78
	 *  to processing regular expressions, possibly spanning more than one
79
	 *  line.
80
	 */
81
	public String REGEXP = "regex"; //$NON-NLS-1$
82
83
	/**
84
	 *  Constant indicating a type of complex expression processor adapted
85
	 *  to processing XPath expressions.
86
	 */
87
	public String XPATH = "xpath"; //$NON-NLS-1$
88
89
	/**
90
	 *  Constant indicating a type of complex expression processor adapted
91
	 *  to processing Java code, possibly spanning more than one line.
92
	 */
93
	public String JAVA = "java"; //$NON-NLS-1$
94
95
	/**
96
	 *  Constant indicating a type of complex expression processor adapted
97
	 *  to processing SQL statements, possibly spanning more than one line.
98
	 */
99
	public String SQL = "sql"; //$NON-NLS-1$
100
101
	/**
102
	 *  Constant indicating a type of complex expression processor adapted
103
	 *  to processing arithmetic expressions with a RTL base direction.
104
	 */
105
	public String RTL_ARITHMETIC = "math"; //$NON-NLS-1$
106
}
(-)src/org/eclipse/equinox/bidi/complexp/ComplExpFactory.java (-48 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.complexp;
12
13
import org.eclipse.equinox.bidi.internal.complexp.BiDiTypesCollector;
14
15
/**
16
 * @noinstantiate This class is not intended to be instantiated by clients.
17
 */
18
// TBD do we really want to provide individual instances of the text processors?
19
final public class ComplExpFactory implements IBiDiProcessor {
20
21
	/**
22
	 * Factory method to create a new instance of the bi-directional text
23
	 * processor for the specified text type. This method may return <code>null</code> 
24
	 * if it is unable to locate processor for the specified text type. 
25
	 * 
26
	 * @see #PROPERTY
27
	 * @see #UNDERSCORE
28
	 * @see #COMMA_DELIMITED
29
	 * @see #SYSTEM_USER
30
	 * @see #FILE
31
	 * @see #EMAIL
32
	 * @see #URL
33
	 * @see #REGEXP
34
	 * @see #XPATH
35
	 * @see #JAVA
36
	 * @see #SQL
37
	 * @see #RTL_ARITHMETIC
38
	 * 
39
	 * @param type specifies the type of complex expression to process.
40
	 * @return a <code>IComplExpProcessor</code> instance capable of handling 
41
	 * the type of complex expression specified. May return <code>null</code> 
42
	 * if the processor not found. 
43
	 */
44
	public static IComplExpProcessor create(String type) {
45
		return BiDiTypesCollector.getInstance().makeProcessor(type);
46
	}
47
48
}
(-)src/org/eclipse/equinox/bidi/complexp/ComplExpUtil.java (-369 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.complexp;
12
13
import java.util.Locale;
14
import org.eclipse.equinox.bidi.internal.complexp.ComplExpBasic;
15
16
/**
17
 *  This class provides a number of convenience functions facilitating the
18
 *  processing of complex expressions.
19
 *
20
 *  @noextend This class is not intended to be subclassed by clients.
21
 *  @noinstantiate This class is not intended to be instantiated by clients.
22
 *
23
 *  @author Matitiahu Allouche
24
 */
25
final public class ComplExpUtil {
26
27
	/**
28
	 *  Flag specifying that all complex expressions should by default assume
29
	 *  that the GUI is mirrored (globally going from right to left).
30
	 *  The default can be overridden for specific instances of complex
31
	 *  expressions.
32
	 *  @see #assumeMirroredDefault
33
	 *  @see #isMirroredDefault
34
	 */
35
	static boolean mirroredDefault;
36
37
	/**
38
	 *  prevents instantiation
39
	 */
40
	private ComplExpUtil() {
41
		// empty
42
	}
43
44
	/** Specify whether the GUI where the complex expression will be displayed
45
	 *  is mirrored (is laid out from right to left). The value specified in
46
	 *  this method sets a default for all complex expressions to be created
47
	 *  from now on. If no value has been specified ever, the GUI
48
	 *  is assumed not to be mirrored.
49
	 *
50
	 *  @param  mirrored must be specified as <code>false</code> if the GUI
51
	 *          is not mirrored, as <code>true</code> if it is.
52
	 *
53
	 *  @see #isMirroredDefault
54
	 *  @see IComplExpProcessor#assumeMirrored
55
	 */
56
	public static void assumeMirroredDefault(boolean mirrored) {
57
		mirroredDefault = mirrored;
58
	}
59
60
	/** Retrieve the value currently assumed as default for GUI mirroring.
61
	 *
62
	 *  @return the current value assumed by default for GUI mirroring.
63
	 *
64
	 *  @see #assumeMirroredDefault
65
	 */
66
	public static boolean isMirroredDefault() {
67
		return mirroredDefault;
68
	}
69
70
	/** This is a convenience method which can add directional marks in a given
71
	 *  text before the characters specified in the given array of offsets,
72
	 *  and can add a prefix and/or a suffix of directional formatting characters.
73
	 *  This can be used for instance after obtaining offsets by calling
74
	 *  {@link IComplExpProcessor#leanBidiCharOffsets() leanBidiCharOffsets} in order to
75
	 *  produce a <i>full</i> text corresponding to the source text.
76
	 *  The directional formatting characters that will be added at the given
77
	 *  offsets will be LRMs for expressions with LTR base direction and
78
	 *  RLMs for expressions with RTL base direction. Leading and
79
	 *  trailing LRE, RLE and PDF which might be needed as prefix or suffix
80
	 *  depending on the orientation of the GUI component used for display
81
	 *  may be added depending on argument <code>affix</code>.
82
	 *
83
	 *  @param  text is the text of the complex expression.
84
	 *
85
	 *  @param  offsets is an array of offsets to characters in <code>text</code>
86
	 *          before which an LRM or RLM will be inserted.
87
	 *          Members of the array must be non-negative numbers smaller
88
	 *          than the length of <code>text</code>.
89
	 *          The array must be sorted in ascending order without duplicates.
90
	 *          This argument may be null if there are no marks to add.
91
	 *
92
	 *  @param  direction specifies the base direction of the complex expression.
93
	 *          It must be one of the values {@link IComplExpProcessor#DIRECTION_LTR} or
94
	 *          {@link IComplExpProcessor#DIRECTION_RTL}.
95
	 *
96
	 *  @param  affix specifies if a prefix and a suffix should be added to
97
	 *          the result to make sure that the <code>direction</code>
98
	 *          specified as second argument is honored even if the expression
99
	 *          is displayed in a GUI component with a different orientation.
100
	 *
101
	 *  @return a string corresponding to the source <code>text</code> with
102
	 *          directional marks (LRMs or RLMs) added at the specified offsets,
103
	 *          and directional formatting characters (LRE, RLE, PDF) added
104
	 *          as prefix and suffix if so required.
105
	 *
106
	 */
107
	public static String insertMarks(String text, int[] offsets, int direction, boolean affix) {
108
		int textLen = text.length();
109
		if (textLen == 0)
110
			return ""; //$NON-NLS-1$
111
112
		String curPrefix, curSuffix, full;
113
		char curMark, c;
114
		char[] fullChars;
115
		if (direction == IComplExpProcessor.DIRECTION_LTR) {
116
			curMark = LRM;
117
			curPrefix = "\u202a\u200e"; /* LRE+LRM *///$NON-NLS-1$
118
			curSuffix = "\u200e\u202c"; /* LRM+PDF *///$NON-NLS-1$
119
		} else {
120
			curMark = RLM;
121
			curPrefix = "\u202b\u200f"; /* RLE+RLM *///$NON-NLS-1$
122
			curSuffix = "\u200f\u202c"; /* RLM+PDF *///$NON-NLS-1$
123
		}
124
		// add marks at offsets
125
		if ((offsets != null) && (offsets.length > 0)) {
126
			int offLen = offsets.length;
127
			fullChars = new char[textLen + offLen];
128
			int added = 0;
129
			for (int i = 0, j = 0; i < textLen; i++) {
130
				c = text.charAt(i);
131
				if ((j < offLen) && (i == offsets[j])) {
132
					fullChars[i + added] = curMark;
133
					added++;
134
					j++;
135
				}
136
				fullChars[i + added] = c;
137
			}
138
			full = new String(fullChars);
139
		} else {
140
			full = text;
141
		}
142
		if (affix)
143
			return curPrefix + full + curSuffix;
144
		return full;
145
	}
146
147
	/*************************************************************************/
148
	/*                                                                       */
149
	/*  The following code is provided for compatibility with TextProcessor  */
150
	/*                                                                       */
151
	/*************************************************************************/
152
153
	//  The default set of delimiters to use to segment a string.
154
	private static final String defaultDelimiters = ".:/\\"; //$NON-NLS-1$
155
	// left to right mark
156
	private static final char LRM = '\u200e';
157
	// left to right mark
158
	private static final char RLM = '\u200f';
159
	// left to right embedding
160
	private static final char LRE = '\u202a';
161
	// right to left embedding
162
	private static final char RLE = '\u202b';
163
	// pop directional format
164
	private static final char PDF = '\u202c';
165
	// TBD use bundle properties
166
	private static String osName = System.getProperty("os.name").toLowerCase(); //$NON-NLS-1$	private static String
167
	private static boolean flagOS = osName.startsWith("windows") || osName.startsWith("linux"); //$NON-NLS-1$ //$NON-NLS-2$
168
	private static String lastLanguage;
169
	private static boolean lastGoodLang;
170
171
	static boolean isProcessingNeeded() {
172
		if (!flagOS)
173
			return false;
174
		// TBD use OSGi service
175
		String lang = Locale.getDefault().getLanguage();
176
		if (lang.equals(lastLanguage))
177
			return lastGoodLang;
178
		lastLanguage = lang;
179
		lastGoodLang = "iw".equals(lang) || "he".equals(lang) || "ar".equals(lang) || "fa".equals(lang) || "ur".equals(lang); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
180
		return lastGoodLang;
181
	}
182
183
	/**
184
	 *  Process the given text and return a string with appropriate
185
	 *  directional formatting characters if the locale is a Bidi locale.
186
	 *  This is equivalent to calling
187
	 *  {@link #process(String, String)} with the default set of
188
	 *  delimiters (dot, colon, slash, backslash).
189
	 *
190
	 *  @param  str the text to be processed
191
	 *
192
	 *  @return the processed string
193
	 *
194
	 */
195
	public static String process(String str) {
196
		return process(str, defaultDelimiters);
197
	}
198
199
	/**
200
	 *  Process a string that has a particular semantic meaning to render
201
	 *  it correctly on Bidi locales. This is done by adding directional
202
	 *  formatting characters so that presentation using the Unicode Bidi
203
	 *  Algorithm will provide the expected result.
204
	 *  The text is segmented according to the provided delimiters.
205
	 *  Each segment has the Unicode Bidi Algorithm applied to it,
206
	 *  but as a whole, the string is oriented left to right.
207
	 *  <p>
208
	 *  For example, a file path such as <tt>d:\myfolder\FOLDER\MYFILE.java</tt>
209
	 *  (where capital letters indicate RTL text) should render as
210
	 *  <tt>d:\myfolder\REDLOF\ELIFYM.java</tt>.</p>
211
	 *  <p>
212
	 *  NOTE: this method inserts directional formatting characters into the
213
	 *  text. Methods like <code>String.equals(String)</code> and
214
	 *  <code>String.length()</code> called on the resulting string will not
215
	 *  return the same values as would be returned for the original string.</p>
216
	 *
217
	 *  @param  str the text to process. If <code>null</code>, return
218
	 *          the string itself
219
	 *
220
	 *  @param  delimiters delimiters by which the string will be segmented.
221
	 *          If <code>null</code>, the default delimiters are used
222
	 *          (dot, colon, slash, backslash).
223
	 *
224
	 *  @return the processed string
225
	 */
226
	public static String process(String str, String delimiters) {
227
		if ((str == null) || (str.length() <= 1) || !isProcessingNeeded())
228
			return str;
229
230
		// do not process a string that has already been processed.
231
		if (str.charAt(0) == LRE && str.charAt(str.length() - 1) == PDF)
232
			return str;
233
234
		// do not process a string if all the following conditions are true:
235
		//  a) it has no RTL characters
236
		//  b) it starts with a LTR character
237
		//  c) it ends with a LTR character or a digit
238
		boolean isStringBidi = false;
239
		int strLength = str.length();
240
		char c;
241
		for (int i = 0; i < strLength; i++) {
242
			c = str.charAt(i);
243
			if (((c >= 0x05d0) && (c <= 0x07b1)) || ((c >= 0xfb1d) && (c <= 0xfefc))) {
244
				isStringBidi = true;
245
				break;
246
			}
247
		}
248
		while (!isStringBidi) {
249
			if (!Character.isLetter(str.charAt(0)))
250
				break;
251
			c = str.charAt(strLength - 1);
252
			if (!Character.isDigit(c) && !Character.isLetter(c))
253
				break;
254
			return str;
255
		}
256
257
		if (delimiters == null)
258
			delimiters = defaultDelimiters;
259
260
		IComplExpProcessor processor = new ComplExpBasic(delimiters);
261
		// make sure that LRE/PDF are added around the string
262
		processor.assumeOrientation(IComplExpProcessor.ORIENT_UNKNOWN);
263
		return processor.leanToFullText(str);
264
	}
265
266
	/**
267
	 *  Process a string that has a particular semantic meaning to render
268
	 *  it correctly on Bidi locales. This is done by adding directional
269
	 *  formatting characters so that presentation using the Unicode Bidi
270
	 *  Algorithm will provide the expected result..
271
	 *  The text is segmented according to the syntax specified in the
272
	 *  <code>type</code> argument.
273
	 *  Each segment has the Unicode Bidi Algorithm applied to it, but the
274
	 *  order of the segments is governed by the type of the complex expression.
275
	 *  <p>
276
	 *  For example, a file path such as <tt>d:\myfolder\FOLDER\MYFILE.java</tt>
277
	 *  (where capital letters indicate RTL text) should render as
278
	 *  <tt>d:\myfolder\REDLOF\ELIFYM.java</tt>.</p>
279
	 *  <p>
280
	 *  NOTE: this method inserts directional formatting characters into the
281
	 *  text. Methods like <code>String.equals(String)</code> and
282
	 *  <code>String.length()</code> called on the resulting string will not
283
	 *  return the same values as would be returned for the original string.</p>
284
	 *
285
	 *  @param  str the text to process. If <code>null</code>, return
286
	 *          the string itself
287
	 *
288
	 *  @param  type specifies the type of the complex expression. It must
289
	 *          be one of the values allowed as argument for method
290
	 *          {@link ComplExpFactory#create}.
291
	 *
292
	 *  @return the processed string
293
	 */
294
	public static String processTyped(String str, String type) {
295
		if ((str == null) || (str.length() <= 1) || !isProcessingNeeded())
296
			return str;
297
298
		// do not process a string that has already been processed.
299
		char c = str.charAt(0);
300
		if (((c == LRE) || (c == RLE)) && str.charAt(str.length() - 1) == PDF)
301
			return str;
302
303
		IComplExpProcessor processor = ComplExpFactory.create(type);
304
		if (processor == null) // invalid type
305
			return str;
306
307
		// make sure that LRE/PDF are added around the string
308
		processor.assumeOrientation(IComplExpProcessor.ORIENT_UNKNOWN);
309
		return processor.leanToFullText(str);
310
	}
311
312
	/**
313
	 *  Removes directional marker characters in the given string that were inserted
314
	 *  by the {@link #process(String)} or {@link #process(String, String)}
315
	 *  methods.
316
	 *
317
	 *  @param  str string with directional markers to remove
318
	 *
319
	 *  @return string with no directional formatting characters
320
	 *
321
	 */
322
	public static String deprocess(String str) {
323
		if ((str == null) || (str.length() <= 1) || !isProcessingNeeded())
324
			return str;
325
326
		StringBuffer buf = new StringBuffer();
327
		int strLen = str.length();
328
		for (int i = 0; i < strLen; i++) {
329
			char c = str.charAt(i);
330
			switch (c) {
331
				case LRM :
332
					continue;
333
				case LRE :
334
					continue;
335
				case PDF :
336
					continue;
337
				default :
338
					buf.append(c);
339
			}
340
		}
341
		return buf.toString();
342
	}
343
344
	/**
345
	 *  Removes directional marker characters in the given string that were inserted
346
	 *  by the {@link #process(String, String)} method.
347
	 *
348
	 *  @param  str string with directional markers to remove
349
	 *
350
	 *  @param  type type of the complex expression as specified when
351
	 *          calling <code>process(String str, int type)</code>
352
	 *
353
	 *  @return string with no directional formatting characters
354
	 *
355
	 */
356
	public static String deprocess(String str, String type) {
357
		if ((str == null) || (str.length() <= 1) || !isProcessingNeeded())
358
			return str;
359
360
		IComplExpProcessor processor = ComplExpFactory.create(type);
361
		if (processor == null) // invalid type
362
			return str;
363
364
		// make sure that LRE/PDF are added around the string
365
		processor.assumeOrientation(IComplExpProcessor.ORIENT_UNKNOWN);
366
		return processor.fullToLeanText(str);
367
	}
368
369
}
(-)src/org/eclipse/equinox/bidi/complexp/IBiDiProcessor.java (-106 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.complexp;
12
13
/**
14
 * Bi-directional processors supplied in this bundle.
15
 * 
16
 * @noextend This interface is not intended to be extended by clients.
17
 */
18
public interface IBiDiProcessor {
19
20
	/**
21
	 * Constant indicating a type of complex expression processor adapted
22
	 * to processing property file statements. It expects the following 
23
	 * string format:
24
	 * <pre>
25
	 *  name=value
26
	 * </pre>
27
	 */
28
	public String PROPERTY = "property"; //$NON-NLS-1$
29
30
	/**
31
	 * Constant indicating a type of complex expression processor adapted
32
	 * to processing compound names.
33
	 * This type covers names made of one or more parts separated by underscores:
34
	 * <pre>
35
	 *  part1_part2_part3
36
	 * </pre>
37
	 */
38
	public String UNDERSCORE = "underscore"; //$NON-NLS-1$
39
40
	/**
41
	 * Constant indicating a type of complex expression processor adapted
42
	 * to processing comma-delimited lists, such as:
43
	 * <pre>
44
	 *  part1,part2,part3
45
	 * </pre>
46
	 */
47
	public String COMMA_DELIMITED = "comma"; //$NON-NLS-1$
48
49
	/**
50
	 * Constant indicating a type of complex expression processor adapted
51
	 * to processing expressions with the following string format:
52
	 * <pre>
53
	 *  system(user)
54
	 * </pre>
55
	 */
56
	public String SYSTEM_USER = "system"; //$NON-NLS-1$
57
58
	/**
59
	 * Constant indicating a type of complex expression processor adapted
60
	 * to processing directory and file paths.
61
	 */
62
	public String FILE = "file"; //$NON-NLS-1$
63
64
	/**
65
	 *  Constant indicating a type of complex expression processor adapted
66
	 *  to processing e-mail addresses.
67
	 */
68
	public String EMAIL = "email"; //$NON-NLS-1$
69
70
	/**
71
	 *  Constant indicating a type of complex expression processor adapted
72
	 *  to processing URLs.
73
	 */
74
	public String URL = "url"; //$NON-NLS-1$
75
76
	/**
77
	 *  Constant indicating a type of complex expression processor adapted
78
	 *  to processing regular expressions, possibly spanning more than one
79
	 *  line.
80
	 */
81
	public String REGEXP = "regex"; //$NON-NLS-1$
82
83
	/**
84
	 *  Constant indicating a type of complex expression processor adapted
85
	 *  to processing XPath expressions.
86
	 */
87
	public String XPATH = "xpath"; //$NON-NLS-1$
88
89
	/**
90
	 *  Constant indicating a type of complex expression processor adapted
91
	 *  to processing Java code, possibly spanning more than one line.
92
	 */
93
	public String JAVA = "java"; //$NON-NLS-1$
94
95
	/**
96
	 *  Constant indicating a type of complex expression processor adapted
97
	 *  to processing SQL statements, possibly spanning more than one line.
98
	 */
99
	public String SQL = "sql"; //$NON-NLS-1$
100
101
	/**
102
	 *  Constant indicating a type of complex expression processor adapted
103
	 *  to processing arithmetic expressions with a RTL base direction.
104
	 */
105
	public String RTL_ARITHMETIC = "math"; //$NON-NLS-1$
106
}
(-)src/org/eclipse/equinox/bidi/complexp/StringProcessor.java (-31 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.complexp;
12
13
import org.eclipse.equinox.bidi.internal.complexp.BiDiTypesCollector;
14
15
/**
16
 * The API part for the TextProcessor replacement.
17
 */
18
// TBD processors currently are not thread-safe (ComplExpBasic has class variables containing
19
// parsing state). This means that either:
20
// a) a new instance of the processor needs to be created for every call;
21
// b) processors have to be made thread-safe.
22
public class StringProcessor {
23
24
	static public String[] getKnownTypes() {
25
		return BiDiTypesCollector.getInstance().getTypes();
26
	}
27
28
	static public IComplExpProcessor getProcessor(String type) {
29
		return BiDiTypesCollector.getInstance().getProcessor(type);
30
	}
31
}
(-)src/org/eclipse/equinox/bidi/complexp/package.html (-158 lines)
Removed Link Here
1
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
2
<html>
3
<head>
4
<META name="Author" content="Matitiahu Allouche">
5
</head>
6
<body bgcolor="white">
7
8
This package provides an interface and implementing classes for
9
processing complex expressions.
10
11
12
<h2>Introduction to Complex Expressions</h2>
13
<p>
14
Bidirectional text offers interesting challenges to presentation systems.
15
For plain text, the Unicode Bidirectional Algorithm
16
(<a href="http://www.unicode.org/reports/tr9/">UBA</a>)
17
generally specifies satisfactorily how to reorder Bidirectional text for
18
display. This algorithm is implemented in Java's presentation system.</p>
19
<p>
20
However, all Bidirectional text is not necessarily plain text. There
21
are also instances of text structured to follow a given syntax, which
22
should be reflected in the display order. The general algorithm, which
23
has no awareness of these special cases, often gives incorrect results
24
when displaying such structured text.</p>
25
<p>
26
The general idea in handling complex expressions is to add directional
27
formatting characters at proper locations in the text to supplement the
28
standard algorithm, so that the final result is correctly displayed
29
using the UBA.
30
A class which handles complex expressions is thus a transformation
31
engine which receives text without directional formatting characters
32
as input and produces as output the same text with added directional
33
formatting characters, hopefully in the minimum quantity which is
34
sufficient to ensure correct display, considering the type of complex
35
expression involved.</p>
36
<p>
37
In this package, text without directional formatting characters is
38
called <b><i>lean</i></b> text while the text with added directional
39
formatting characters is called <b><i>full</i></b> text.</p>
40
<p>
41
{@link <a href="IComplExpProcessor.html">IComplExpProcessor</a>} provides
42
an interface for processing complex expressions.  This package also
43
includes several classes which implement <code>IComplExpProcessor</code>,
44
all of them based on class
45
{@link <a href="ComplExpBasic.html">ComplExpBasic</a>}.
46
<p>
47
There is also a class named
48
<code>ComplExpDoNothing</code> which actually adds no directional
49
formatting characters. It can be considered as a null processor in
50
relation to complex expressions. This class has a very small overhead and
51
can be used as a low-cost default processor when no complex expression is
52
involved and no processing is needed, but a general framework of
53
handling complex expressions must be preserved.</p>
54
<p>
55
The class {@link <a href="ComplExpBasic.html">ComplExpBasic</a>} can
56
handle several types of relatively simple complex expressions.</p>
57
<p>
58
A number of subclasses of <code>ComplExpBasic</code> are included in this
59
package, each one adapted to handle some type of complex expression.
60
The explicitly supported types are:
61
<ul>
62
  <li>property (name=value)</li>
63
  <li>compound name (xxx_yy_zzzz)</li>
64
  <li>comma delimited list</li>
65
  <li>system(user)</li>
66
  <li>directory and file path</li>
67
  <li>e-mail address</li>
68
  <li>URL</li>
69
  <li>regular expression</li>
70
  <li>Xpath</li>
71
  <li>Java code</li>
72
  <li>SQL statements</li>
73
  <li>RTL arithmetic expressions</li>
74
</ul>
75
<p>
76
More types can be supported using the classes provided in the package.
77
It is also possible to develop new classes to handle types of
78
complex expressions which cannot be supported with the existing classes.
79
Using the framework provided by <code>IComplExpProcessor</code> and
80
<code>ComplExpBasic</code> can facilitate
81
considerably the development of such new support.</p>
82
<p>
83
The class {@link <a href="ComplExpUtil.html">ComplExpUtil</a>} provides
84
a number of convenience methods to process some common types of
85
complex expressions. When using methods in this class, there is no need
86
to refer to members of other classes of this package.
87
However, the other classes allow more precise control and possibly better
88
performance.</p>
89
<p>
90
91
<p>&nbsp;</p>
92
93
<h2>Abbreviations used in the documentation of this package</h2>
94
95
<dl>
96
<dt><b>UBA</b><dd>Unicode Bidirectional Algorithm
97
98
<dt><b>Bidi</b><dd>Bidirectional
99
100
<dt><b>GUI</b><dd>Graphical User Interface
101
102
<dt><b>UI</b><dd>User Interface
103
104
<dt><b>LTR</b><dd>Left to Right
105
106
<dt><b>RTL</b><dd>Right to Left
107
108
<dt><b>LRM</b><dd>Left-to-Right Mark
109
110
<dt><b>RLM</b><dd>Right-to-Left Mark
111
112
<dt><b>LRE</b><dd>Left-to-Right Embedding
113
114
<dt><b>RLE</b><dd>Right-to-Left Embedding
115
116
<dt><b>PDF</b><dd>Pop Directional Formatting
117
</dl>
118
119
<p>&nbsp;</p>
120
121
<h2>Known Limitations</h2>
122
123
<p>The proposed solution is making extensive usage of LRM, RLM, LRE, RLE
124
and PDF directional controls which are invisible but affect the way Bidi
125
text is displayed. The following related two key points merit special
126
attention:</p>
127
128
<ul>
129
<li>Implementations of the UBA on various platforms (e.g., Windows and
130
Linux) are very similar but nevertheless have known differences. Those
131
differences are minor and will not have a visible effect in most cases.
132
However there might be cases in which the same Bidi text on two
133
platforms might look different. These differences will surface in Java
134
applications when they use the platform visual components for their UI
135
(e.g., AWT, SWT).</li>
136
137
<li>It is assumed that the presentation engine supports LRE, RLE and
138
PDF directional formatting characters.</li>
139
140
<li>Because some presentation engines are not strictly conformant to the
141
UBA, the implementation of complex expressions in this package adds LRM
142
or RLM characters in association with LRE, RLE or PDF in cases where
143
this would not be needed if the presentation engine was fully conformant
144
to the UBA. Such added marks will not have harmful effects on
145
conformant presentation engines and will help less conformant engines to
146
achieve the desired presentation.</li>
147
</ul>
148
149
<p>&nbsp;</p>
150
151
<h2>References</h2>
152
153
@see <a href="IComplExpProcessor.html">IComplExpProcessor</a>
154
@see <a href="ComplExpBasic.html">ComplExpBasic</a>
155
@see <a href="ComplExpDoNothing.html">ComplExpDoNothing</a>
156
157
</body>
158
</html>
(-)src/org/eclipse/equinox/bidi/custom/BidiComplexProcessor.java (+99 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.custom;
12
13
import org.eclipse.equinox.bidi.*;
14
15
import org.eclipse.equinox.bidi.internal.BidiComplexImpl;
16
17
/**
18
 *  Generic processor which can be used as superclass (base class)
19
 *  for specific complex expression processors.
20
 *  <p>
21
 *  Here are some guidelines about how to write complex expression
22
 *  processors.
23
 *  <ul>
24
 *    <li>Processor instances may be accessed simultaneously by
25
 *        several threads. They should have no instance variables.</li>
26
 *    <li>Each use of a processor is initialized with the {@link #init init}
27
 *        or the {@link #updateEnvironment updateEnvironment} methods.
28
 *        Both methods have a {@link BidiComplexHelper} argument named <code>caller</code>.
29
 *        All calls to methods of <code>BidiComplexProcessor</code> have a
30
 *        <code>caller</code> argument.
31
 *        If a processor needs to retain some data across invocations, it may
32
 *        access the field {@link BidiComplexImpl#processorData caller.impl.processorData}.
33
 *        It is guaranteed that this field will not be modified by any code
34
 *        except the processor itself.</li>
35
 *    <li>The behavior of a processor is governed by 3 factors:
36
 *        <ul>
37
 *          <li>The {@link BidiComplexFeatures#operators operators} field of its
38
 *              {@link BidiComplexFeatures features} determines how submitted
39
 *              complex expressions are split into tokens.</li>
40
 *          <li>The tokens are displayed one after the other according
41
 *              to the appropriate {@link BidiComplexFeatures#dirArabic direction}.
42
 *          <li>The counter {@link BidiComplexFeatures#specialsCount specialsCount}
43
 *              determines how many special cases need to be handled by
44
 *              code specific to that processor.
45
 *  </ul>
46
 *
47
 *  @author Matitiahu Allouche
48
 */
49
public class BidiComplexProcessor implements IBidiComplexProcessor {
50
51
	/**
52
	 *  In <code>BidiComplexProcessor</code> this method returns a
53
	 *  {@link BidiComplexFeatures#DEFAULT DEFAULT} value which
54
	 *  directs the processor to do nothing.
55
	 */
56
	public BidiComplexFeatures init(BidiComplexHelper caller, BidiComplexEnvironment environment) {
57
		return BidiComplexFeatures.DEFAULT;
58
	}
59
60
	/**
61
	 *  In <code>BidiComplexProcessor</code> this method simply calls the
62
	 *  {@link #init init} method. If this is good enough, i.e.
63
	 *  if the {@link BidiComplexFeatures features} of the processor are
64
	 *  determined identically for initialization and after a
65
	 *  change in the {@link BidiComplexEnvironment environment}, subclasses of
66
	 *  <code>BidiComplexProcessor</code> don't need to override this
67
	 *  method.
68
	 */
69
	public BidiComplexFeatures updateEnvironment(BidiComplexHelper caller, BidiComplexEnvironment environment) {
70
		return init(caller, environment);
71
	}
72
73
	/**
74
	 *  In <code>BidiComplexProcessor</code> this method throws an
75
	 *  <code>IllegalStateException</code>. This is appropriate behavior
76
	 *  (and does not need to be overridden) for processors whose
77
	 *  {@link BidiComplexFeatures#specialsCount specialsCount} is zero, which
78
	 *  means that <code>indexOfSpecial</code> should never be called
79
	 *  for them.
80
	 */
81
	public int indexOfSpecial(BidiComplexHelper caller, int caseNumber, String srcText, int fromIndex) {
82
		// This method must be overridden by all subclasses with special cases.
83
		throw new IllegalStateException();
84
	}
85
86
	/**
87
	 *  In <code>BidiComplexProcessor</code> this method throws an
88
	 *  <code>IllegalStateException</code>. This is appropriate behavior
89
	 *  (and does not need to be overridden) for processors whose
90
	 *  {@link BidiComplexFeatures#specialsCount specialsCount} is zero, which
91
	 *  means that <code>processSpecial</code> should never be called
92
	 *  for them.
93
	 */
94
	public int processSpecial(BidiComplexHelper caller, int caseNumber, String srcText, int operLocation) {
95
		// This method must be overridden by all subclasses with any special case.
96
		throw new IllegalStateException();
97
	}
98
99
}
(-)src/org/eclipse/equinox/bidi/custom/BidiComplexStringProcessor.java (+40 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.custom;
12
13
import org.eclipse.equinox.bidi.internal.BidiComplexTypesCollector;
14
15
/**
16
 * This class provides access to registered complex expression processors.
17
 */
18
public class BidiComplexStringProcessor {
19
	/**
20
	 *  Retrieve all registered types of complex expression processors.
21
	 *
22
	 *  @return an array of strings, each string identifying a type of
23
	 *  complex expression processor.
24
	 */
25
	static public String[] getKnownTypes() {
26
		return BidiComplexTypesCollector.getInstance().getTypes();
27
	}
28
29
	/**
30
	 *  Get access to a complex expression processor of a given type.
31
	 *
32
	 *  @param type string identifying a type of processor
33
	 *
34
	 *  @return a reference to an instance of a processor of the
35
	 *  required type. If the type is unknown, return <code>null</code>.
36
	 */
37
	static public IBidiComplexProcessor getProcessor(String type) {
38
		return BidiComplexTypesCollector.getInstance().getProcessor(type);
39
	}
40
}
(-)src/org/eclipse/equinox/bidi/custom/IBidiComplexProcessor.java (+151 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.custom;
12
13
import org.eclipse.equinox.bidi.*;
14
15
import org.eclipse.equinox.bidi.internal.BidiComplexImpl;
16
17
/**
18
 *  Interface for all complex expression processors.
19
 *  For guidelines about implementation, see
20
 *  {@link BidiComplexProcessor}.
21
 *
22
 *  @author Matitiahu Allouche
23
 */
24
public interface IBidiComplexProcessor {
25
26
	/**
27
	 *  Do whatever initializations are needed and return the
28
	 *  {@link BidiComplexFeatures} characterizing the processor.
29
	 *
30
	 *  @param env the current environment, which may affect the
31
	 *          initializations.
32
	 *
33
	 *  @param caller <code>BidiComplexHelper</code> instance which called this method.
34
	 *          This allows access to the field
35
	 *          {@link BidiComplexImpl#processorData caller.impl.processorData} where
36
	 *          the processor can keep whatever data it needs.
37
	 *
38
	 *  @return the features in use for this processor.
39
	 */
40
	public abstract BidiComplexFeatures init(BidiComplexHelper caller, BidiComplexEnvironment env);
41
42
	/**
43
	 *  Do whatever renewed initializations are needed after a
44
	 *  change in the environment and return the possibly updated
45
	 *  {@link BidiComplexFeatures} characterizing the processor.
46
	 *
47
	 *  @param env the updated environment, which may affect the
48
	 *          initializations.
49
	 *
50
	 *  @param caller <code>BidiComplexHelper</code> instance which called this method.
51
	 *          This allows access to the field
52
	 *          {@link BidiComplexImpl#processorData caller.impl.processorData} where
53
	 *          the processor can keep whatever data it needs.
54
	 *
55
	 *  @return the features to use for this processor.
56
	 */
57
	public BidiComplexFeatures updateEnvironment(BidiComplexHelper caller, BidiComplexEnvironment env);
58
59
	/**
60
	 *  Locate occurrences of special strings within a complex expression
61
	 *  and return their indexes one after the other in successive calls.
62
	 *  <p>
63
	 *  This method is called repeatedly from the code implementing
64
	 *  {@link BidiComplexHelper#leanToFullText leanToFullText} if the field
65
	 *  {@link BidiComplexFeatures#specialsCount specialsCount} returned when
66
	 *  {@link #init initializing} the processor is greater than zero.
67
	 *  <p>
68
	 *  The code implementing this method may use the following methods
69
	 *  in {@link BidiComplexHelper}:
70
	 *  <ul>
71
	 *    <li>{@link BidiComplexHelper#getDirProp getDirProp}</li>
72
	 *    <li>{@link BidiComplexHelper#setDirProp setDirProp}</li>
73
	 *    <li>{@link BidiComplexHelper#insertMark insertMark}</li>
74
	 *    <li>{@link BidiComplexHelper#processOperator processOperator}</li>
75
	 *    <li>{@link BidiComplexHelper#setFinalState setFinalState}</li>
76
	 *  </ul>
77
	 *
78
	 *  @param  caseNumber number of the special case to locate.
79
	 *          This number varies from zero to <code>specialsCount - 1</code>.
80
	 *          The meaning of this number is internal to the class
81
	 *          implementing <code>indexOfSpecial</code>.
82
	 *
83
	 *  @param  srcText text of the complex expression before addition of any
84
	 *          directional formatting characters.
85
	 *
86
	 *  @param  fromIndex the index within <code>srcText</code> to start
87
	 *          the search from.
88
	 *
89
	 *  @return the position where the start of the special case was located.
90
	 *          The method must return the first occurrence of whatever
91
	 *          identifies the start of the special case starting from
92
	 *          <code>fromIndex</code>. The method does not have to check if
93
	 *          this occurrence appears within the scope of another special
94
	 *          case (e.g. a comment starting delimiter within the scope of
95
	 *          a literal or vice-versa).
96
	 *          <br>If no occurrence is found, the method must return -1.
97
	 */
98
	public int indexOfSpecial(BidiComplexHelper caller, int caseNumber, String srcText, int fromIndex);
99
100
	/**
101
	 *  This method is called by {@link BidiComplexHelper#leanToFullText leanToFullText}
102
	 *  when a special case occurrence is located by
103
	 *  {@link #indexOfSpecial indexOfSpecial}.
104
	 *  <p>
105
	 *  The code implementing this method may use the following methods
106
	 *  in {@link BidiComplexHelper}:
107
	 *  <ul>
108
	 *    <li>{@link BidiComplexHelper#getDirProp getDirProp}</li>
109
	 *    <li>{@link BidiComplexHelper#setDirProp setDirProp}</li>
110
	 *    <li>{@link BidiComplexHelper#insertMark insertMark}</li>
111
	 *    <li>{@link BidiComplexHelper#processOperator processOperator}</li>
112
	 *    <li>{@link BidiComplexHelper#setFinalState setFinalState}</li>
113
	 *  </ul>
114
	 *  <p>
115
	 *  If a special processing cannot be completed within a current call to
116
	 *  <code>processSpecial</code> (for instance, a comment has been started
117
	 *  in the current line but its end appears in a following line),
118
	 *  <code>processSpecial</code> should specify a final state using
119
	 *  the method {@link BidiComplexHelper#setFinalState setFinalState}.
120
	 *  The meaning of this state is internal to the processor.
121
	 *  On a later call to
122
	 *  {@link BidiComplexHelper#leanToFullText(String text, int initState)}
123
	 *  specifying that state value, <code>processSpecial</code> will be
124
	 *  called with that value for parameter <code>caseNumber</code> and
125
	 *  <code>-1</code> for parameter <code>operLocation</code> and should
126
	 *  perform whatever initializations are required depending on the state.
127
	 *
128
	 *  @param  caseNumber number of the special case to handle.
129
	 *
130
	 *  @param  srcText text of the complex expression.
131
	 *
132
	 *  @param  operLocation the position returned by
133
	 *          {@link #indexOfSpecial indexOfSpecial}. In calls to
134
	 *          {@link BidiComplexHelper#leanToFullText(String text, int initState)} or
135
	 *          {@link BidiComplexHelper#fullToLeanText(String text, int initState)}
136
	 *          specifying an <code>initState</code>
137
	 *          parameter, <code>processSpecial</code> is called when initializing
138
	 *          the processing with the value of <code>caseNumber</code>
139
	 *          equal to <code>initState</code> and the value of
140
	 *          <code>operLocation</code> equal to <code>-1</code>.
141
	 *
142
	 *  @return the position after the scope of the special case ends.
143
	 *          For instance, the position after the end of a comment,
144
	 *          the position after the end of a literal.
145
	 *          <br>A value greater or equal to the length of <code>srcText</code>
146
	 *          means that there is no further occurrence of this case in the
147
	 *          current complex expression.
148
	 */
149
	public int processSpecial(BidiComplexHelper caller, int caseNumber, String srcText, int operLocation);
150
151
}
(-)src/org/eclipse/equinox/bidi/custom/package.html (+27 lines)
Added Link Here
1
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
2
<html>
3
<head>
4
<META name="Author" content="Matitiahu Allouche">
5
</head>
6
<body bgcolor="white">
7
8
This package provides an interface and classes for
9
developing complex expressions processors.
10
11
<ul>
12
  <li>{@link <a href="IBidiComplexProcessor.html">IBidiComplexProcessor</a>}
13
      is an interface specifying which methods a processor must provide.</li>
14
  <li>{@link <a href="BidiComplexProcessor.html">BidiComplexProcessor</a>}
15
      is a generic processor which can be used as superclass for specific
16
      processors.</li>
17
  <li>{@link <a href="BidiComplexStringProcessor.html">BidiComplexStringProcessor</a>}
18
      is a class which allows retrieval of the defined processor types and of the
19
      corresponding processors.</li>
20
</ul>
21
22
This package is to be used together with package
23
{@link <a href="..\package-summary.html">
24
org.eclipse.equinox.bidi</a>}.
25
26
</body>
27
</html>
(-)src/org/eclipse/equinox/bidi/internal/BidiComplexActivator.java (+91 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.bidi.internal;
12
13
import java.util.Locale;
14
import org.eclipse.osgi.framework.log.FrameworkLog;
15
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
16
import org.eclipse.osgi.service.localization.LocaleProvider;
17
import org.osgi.framework.*;
18
import org.osgi.util.tracker.ServiceTracker;
19
20
public class BidiComplexActivator implements BundleActivator {
21
22
	private ServiceTracker logTracker = null;
23
	private BundleContext bundleContext;
24
	private static BidiComplexActivator instance;
25
26
	public BidiComplexActivator() {
27
		instance = this; // there is only one bundle activator
28
	}
29
30
	public void start(BundleContext context) throws Exception {
31
		bundleContext = context;
32
		instance = this;
33
	}
34
35
	public void stop(BundleContext context) throws Exception {
36
		if (logTracker != null) {
37
			logTracker.close();
38
			logTracker = null;
39
		}
40
		bundleContext = null;
41
	}
42
43
	public static BidiComplexActivator getInstance() {
44
		return instance;
45
	}
46
47
	public String getProperty(String key) {
48
		return bundleContext.getProperty(key);
49
	}
50
51
	public Locale getDefaultLocale() {
52
		// use OSGi service
53
		ServiceReference[] references = null;
54
		try {
55
			references = bundleContext.getAllServiceReferences(null, LocaleProvider.class.getName());
56
		} catch (InvalidSyntaxException e) {
57
			// do nothing
58
		}
59
		if (references == null || references.length < 1)
60
			return Locale.getDefault();
61
		Object service = bundleContext.getService(references[0]);
62
		LocaleProvider localeProvider = (LocaleProvider) service;
63
		if (localeProvider != null) {
64
			Locale currentLocale = localeProvider.getLocale();
65
			bundleContext.ungetService(references[0]);
66
			if (currentLocale != null)
67
				return currentLocale;
68
		}
69
		return Locale.getDefault();
70
	}
71
72
	private FrameworkLog getFrameworkLog() {
73
		if (logTracker == null) {
74
			logTracker = new ServiceTracker(bundleContext, FrameworkLog.class.getName(), null);
75
			logTracker.open();
76
		}
77
		return (FrameworkLog) logTracker.getService();
78
	}
79
80
	static public void logError(String message, Exception e) {
81
		FrameworkLog frameworkLog = instance.getFrameworkLog();
82
		if (frameworkLog != null) {
83
			frameworkLog.log(new FrameworkLogEntry("org.eclipse.equinox.bidi", FrameworkLogEntry.ERROR, 1, message, 0, e, null)); //$NON-NLS-1$
84
			return;
85
		}
86
		System.err.println(message);
87
		if (e != null)
88
			e.printStackTrace();
89
	}
90
91
}
(-)src/org/eclipse/equinox/bidi/internal/BidiComplexDelims.java (+62 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal;
12
13
import org.eclipse.equinox.bidi.custom.BidiComplexProcessor;
14
15
import org.eclipse.equinox.bidi.BidiComplexHelper;
16
17
/**
18
 *  <code>BidiComplexDelims</code> is a processor for complex expressions
19
 *  composed of text segments separated by operators where the text segments
20
 *  may include delimited parts within which operators are treated like
21
 *  regular characters.
22
 *
23
 *  @author Matitiahu Allouche
24
 */
25
public abstract class BidiComplexDelims extends BidiComplexProcessor {
26
27
	/**
28
	 *  This method locates occurrences of start delimiters.
29
	 */
30
	public int indexOfSpecial(BidiComplexHelper helper, int caseNumber, String srcText, int fromIndex) {
31
		char delim = getDelimiters().charAt(caseNumber * 2);
32
		return srcText.indexOf(delim, fromIndex);
33
	}
34
35
	/**
36
	 *  This method skips until after the matching end delimiter.
37
	 */
38
	public int processSpecial(BidiComplexHelper helper, int caseNumber, String srcText, int operLocation) {
39
		helper.processOperator(operLocation);
40
		int loc = operLocation + 1;
41
		char delim = getDelimiters().charAt((caseNumber * 2) + 1);
42
		loc = srcText.indexOf(delim, loc);
43
		if (loc < 0)
44
			return srcText.length();
45
		return loc + 1;
46
	}
47
48
	/**
49
	 *  @return a string containing the delimiters implemented in this class
50
	 *         instance. This string must include an even
51
	 *         number of characters. The first 2 characters of a string
52
	 *         constitute a pair, the next 2 characters are a second pair, etc...
53
	 *         In each pair, the first character is a start delimiter and
54
	 *         the second character is an end delimiter. In the <i>lean</i>
55
	 *         text, any part starting with a start delimiter and ending with
56
	 *         the corresponding end delimiter is a delimited part. Within a
57
	 *         delimited part, operators are treated like regular characters,
58
	 *         which means that they do not define new segments.
59
	 */
60
	protected abstract String getDelimiters();
61
62
}
(-)src/org/eclipse/equinox/bidi/internal/BidiComplexDelimsEsc.java (+55 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal;
12
13
import org.eclipse.equinox.bidi.BidiComplexHelper;
14
15
/**
16
 *  <code>BidiComplexDelims</code> is a processor for complex expressions
17
 *  composed of text segments separated by operators where the text segments
18
 *  may include delimited parts within which operators are treated like
19
 *  regular characters and the delimiters may be escaped.
20
 *  This is similar to {@link BidiComplexDelims} except
21
 *  that delimiters can be escaped using the backslash character.
22
 *  <ul>
23
 *    <li>Two consecutive backslashes in a delimited part are treated like
24
 *        one regular characters.</li>
25
 *    <li>An ending delimiter preceded by an odd number of backslashes is
26
 *        treated like a regular character of a delimited part.</li>
27
 *  </ul>
28
 *
29
 *  @author Matitiahu Allouche
30
 */
31
public abstract class BidiComplexDelimsEsc extends BidiComplexDelims {
32
33
	/**
34
	*  This method skips until after the matching end delimiter,
35
	*  ignoring possibly escaped end delimiters.
36
	*/
37
	public int processSpecial(BidiComplexHelper helper, int caseNumber, String srcText, int operLocation) {
38
		helper.processOperator(operLocation);
39
		int location = operLocation + 1;
40
		char delim = getDelimiters().charAt((caseNumber * 2) + 1);
41
		while (true) {
42
			location = srcText.indexOf(delim, location);
43
			if (location < 0)
44
				return srcText.length();
45
			int cnt = 0;
46
			for (int i = location - 1; srcText.charAt(i) == '\\'; i--) {
47
				cnt++;
48
			}
49
			location++;
50
			if ((cnt & 1) == 0)
51
				return location;
52
		}
53
	}
54
55
}
(-)src/org/eclipse/equinox/bidi/internal/BidiComplexImpl.java (+762 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal;
12
13
import org.eclipse.equinox.bidi.custom.IBidiComplexProcessor;
14
15
import org.eclipse.equinox.bidi.*;
16
17
/**
18
 *  <code>BidiComplexImpl</code> provides the code which implements the API in
19
 *  {@link BidiComplexHelper}. All its public methods are shadows of similarly
20
 *  signed methods of <code>BidiComplexHelper</code>, and their documentation
21
 *  is by reference to the methods in <code>BidiComplexHelper</code>.
22
 *
23
 *  @author Matitiahu Allouche
24
 */
25
public class BidiComplexImpl {
26
27
	static final String EMPTY_STRING = ""; //$NON-NLS-1$
28
	static final byte B = Character.DIRECTIONALITY_PARAGRAPH_SEPARATOR;
29
	static final byte L = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
30
	static final byte R = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
31
	static final byte AL = Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC;
32
	static final byte AN = Character.DIRECTIONALITY_ARABIC_NUMBER;
33
	static final byte EN = Character.DIRECTIONALITY_EUROPEAN_NUMBER;
34
	static final char LRM = 0x200E;
35
	static final char RLM = 0x200F;
36
	static final char LRE = 0x202A;
37
	static final char RLE = 0x202B;
38
	static final char PDF = 0x202C;
39
	static final char[] MARKS = {LRM, RLM};
40
	static final char[] EMBEDS = {LRE, RLE};
41
	static final byte[] STRONGS = {L, R};
42
	static final int PREFIX_LENGTH = 2;
43
	static final int SUFFIX_LENGTH = 2;
44
	static final int FIXES_LENGTH = PREFIX_LENGTH + SUFFIX_LENGTH;
45
46
	BidiComplexHelper helper;
47
48
	BidiComplexEnvironment environment;
49
50
	IBidiComplexProcessor processor;
51
52
	/**
53
	 *  This field is reserved for use of the complex expression
54
	 *  processor associated with this instance of <code>BidiComplexImpl</code>.
55
	 *  The processor can keep here a reference to an object that it
56
	 *  has sole control of.
57
	 */
58
	public Object processorData;
59
60
	/**
61
	 *  Features of the associated processor.
62
	 *
63
	 */
64
	public BidiComplexFeatures features;
65
66
	int state = BidiComplexHelper.STATE_NOTHING_GOING;
67
68
	// strong bidi class (L or R) for current expression direction
69
	byte curStrong = -1;
70
	// strong character (LRM or RLM) for current expression direction
71
	char curMark;
72
	// strong directional control (LRE or RLE) for current expression direction
73
	char curEmbed;
74
	int prefixLength;
75
	// index of next occurrence for each operator and each special case
76
	int[] locations;
77
	// number of special cases
78
	int specialsCount;
79
	String leanText;
80
	// positions where LRM/RLM must be added
81
	int[] offsets;
82
	// number of LRM/RLM to add
83
	int count;
84
	// For positions where it has been looked up, the entry will receive
85
	// the Character directionality + 2 (so that 0 indicates that the
86
	// the directionality has not been looked up yet.
87
	byte[] dirProps;
88
	// current UI orientation (after resolution if contextual)
89
	int curOrient = -1;
90
	// Current expression base direction (after resolution if depending on
91
	// script and/or on GUI mirroring (0=LTR, 1=RTL))
92
	int curDirection = -1;
93
94
	/**
95
	 *  @see BidiComplexHelper#BidiComplexHelper(IBidiComplexProcessor myProcessor, BidiComplexEnvironment environment)
96
	 */
97
	public BidiComplexImpl(BidiComplexHelper caller, IBidiComplexProcessor myProcessor, BidiComplexEnvironment environment) {
98
		helper = caller;
99
		if (environment == null) {
100
			this.environment = BidiComplexEnvironment.DEFAULT;
101
		} else {
102
			this.environment = environment;
103
		}
104
		processor = myProcessor;
105
		features = processor.init(helper, this.environment);
106
		// keep private copy of specialsCount to avoid later modification
107
		specialsCount = features.specialsCount;
108
		locations = new int[features.operators.length() + specialsCount];
109
	}
110
111
	long computeNextLocation(int curPos) {
112
		int operCount = features.operators.length();
113
		int len = leanText.length();
114
		int nextLocation = len;
115
		int idxLocation = 0;
116
		// Start with special sequences to give them precedence over simple
117
		// operators. This may apply to cases like slash+asterisk versus slash.
118
		for (int i = 0; i < specialsCount; i++) {
119
			int location = locations[operCount + i];
120
			if (location < curPos) {
121
				location = processor.indexOfSpecial(helper, i, leanText, curPos);
122
				if (location < 0)
123
					location = len;
124
				locations[operCount + i] = location;
125
			}
126
			if (location < nextLocation) {
127
				nextLocation = location;
128
				idxLocation = operCount + i;
129
			}
130
		}
131
		for (int i = 0; i < operCount; i++) {
132
			int location = locations[i];
133
			if (location < curPos) {
134
				location = leanText.indexOf(features.operators.charAt(i), curPos);
135
				if (location < 0)
136
					location = len;
137
				locations[i] = location;
138
			}
139
			if (location < nextLocation) {
140
				nextLocation = location;
141
				idxLocation = i;
142
			}
143
		}
144
		return nextLocation + (((long) idxLocation) << 32);
145
	}
146
147
	int getCurOrient() {
148
		if (curOrient >= 0)
149
			return curOrient;
150
151
		if ((environment.orientation & BidiComplexEnvironment.ORIENT_CONTEXTUAL_LTR) == 0) {
152
			// absolute orientation
153
			curOrient = environment.orientation;
154
			return curOrient;
155
		}
156
		// contextual orientation
157
		int len = leanText.length();
158
		byte dirProp;
159
		for (int i = 0; i < len; i++) {
160
			// In the following lines, B, L, R and AL represent bidi categories
161
			// as defined in the Unicode Bidirectional Algorithm
162
			// ( http://www.unicode.org/reports/tr9/ ).
163
			// B  represents the category Block Separator.
164
			// L  represents the category Left to Right character.
165
			// R  represents the category Right to Left character.
166
			// AL represents the category Arabic Letter.
167
			dirProp = dirProps[i];
168
			if (dirProp == 0) {
169
				dirProp = Character.getDirectionality(leanText.charAt(i));
170
				if (dirProp == B) // B char resolves to L or R depending on orientation
171
					continue;
172
				dirProps[i] = (byte) (dirProp + 2);
173
			} else {
174
				dirProp -= 2;
175
			}
176
			if (dirProp == L) {
177
				curOrient = BidiComplexEnvironment.ORIENT_LTR;
178
				return curOrient;
179
			}
180
			if (dirProp == R || dirProp == AL) {
181
				curOrient = BidiComplexEnvironment.ORIENT_RTL;
182
				return curOrient;
183
			}
184
		}
185
		curOrient = environment.orientation & 1;
186
		return curOrient;
187
	}
188
189
	/**
190
	 *  @see BidiComplexHelper#getCurDirection
191
	 */
192
	public int getCurDirection() {
193
		if (curDirection >= 0)
194
			return curDirection;
195
196
		curStrong = -1;
197
		// same direction for Arabic and Hebrew?
198
		if (features.dirArabic == features.dirHebrew) {
199
			curDirection = features.dirArabic;
200
			return curDirection;
201
		}
202
		// check if Arabic or Hebrew letter comes first
203
		int len = leanText.length();
204
		byte dirProp;
205
		for (int i = 0; i < len; i++) {
206
			// In the following lines, R and AL represent bidi categories
207
			// as defined in the Unicode Bidirectional Algorithm
208
			// ( http://www.unicode.org/reports/tr9/ ).
209
			// R  represents the category Right to Left character.
210
			// AL represents the category Arabic Letter.
211
			dirProp = getDirProp(i);
212
			if (dirProp == AL) {
213
				curDirection = features.dirArabic;
214
				return curDirection;
215
			}
216
			if (dirProp == R) {
217
				curDirection = features.dirHebrew;
218
				return curDirection;
219
			}
220
		}
221
		// found no Arabic or Hebrew character
222
		curDirection = BidiComplexFeatures.DIR_LTR;
223
		return curDirection;
224
	}
225
226
	void setMarkAndFixes() {
227
		int dir = getCurDirection();
228
		if (curStrong == STRONGS[dir])
229
			return;
230
		curStrong = STRONGS[dir];
231
		curMark = MARKS[dir];
232
		curEmbed = EMBEDS[dir];
233
	}
234
235
	/**
236
	 *  @see BidiComplexHelper#getDirProp(int index)
237
	 */
238
	public byte getDirProp(int index) {
239
		byte dirProp = dirProps[index];
240
		if (dirProp == 0) {
241
			// In the following lines, B, L and R represent bidi categories
242
			// as defined in the Unicode Bidirectional Algorithm
243
			// ( http://www.unicode.org/reports/tr9/ ).
244
			// B  represents the category Block Separator.
245
			// L  represents the category Left to Right character.
246
			// R  represents the category Right to Left character.
247
			dirProp = Character.getDirectionality(leanText.charAt(index));
248
			if (dirProp == B)
249
				dirProp = getCurOrient() == BidiComplexEnvironment.ORIENT_RTL ? R : L;
250
			dirProps[index] = (byte) (dirProp + 2);
251
			return dirProp;
252
		}
253
		return (byte) (dirProp - 2);
254
	}
255
256
	/**
257
	 *  @see BidiComplexHelper#setDirProp(int index, byte dirProp)
258
	 */
259
	public void setDirProp(int index, byte dirProp) {
260
		dirProps[index] = (byte) (dirProp + 2);
261
	}
262
263
	/**
264
	 *  @see BidiComplexHelper#processOperator(int operLocation)
265
	 */
266
	public void processOperator(int operLocation) {
267
		// In this method, L, R, AL, AN and EN represent bidi categories
268
		// as defined in the Unicode Bidirectional Algorithm
269
		// ( http://www.unicode.org/reports/tr9/ ).
270
		// L  represents the category Left to Right character.
271
		// R  represents the category Right to Left character.
272
		// AL represents the category Arabic Letter.
273
		// AN represents the category Arabic Number.
274
		// EN  represents the category European Number.
275
		int len = leanText.length();
276
		boolean doneAN = false;
277
278
		if (getCurDirection() == BidiComplexFeatures.DIR_RTL) {
279
			// the expression base direction is RTL
280
			for (int i = operLocation - 1; i >= 0; i--) {
281
				byte dirProp = getDirProp(i);
282
				if (dirProp == R || dirProp == AL)
283
					return;
284
285
				if (dirProp == L) {
286
					for (int j = operLocation; j < len; j++) {
287
						dirProp = getDirProp(j);
288
						if (dirProp == R || dirProp == AL)
289
							return;
290
						if (dirProp == L || dirProp == EN) {
291
							insertMark(operLocation);
292
							return;
293
						}
294
					}
295
					return;
296
				}
297
			}
298
			return;
299
		}
300
301
		// the expression base direction is LTR
302
		if (features.ignoreArabic) {
303
			if (features.ignoreHebrew) /* process neither Arabic nor Hebrew */
304
				return;
305
			/* process Hebrew, not Arabic */
306
			for (int i = operLocation - 1; i >= 0; i--) {
307
				byte dirProp = getDirProp(i);
308
				if (dirProp == L)
309
					return;
310
				if (dirProp == R) {
311
					for (int j = operLocation; j < len; j++) {
312
						dirProp = getDirProp(j);
313
						if (dirProp == L)
314
							return;
315
						if (dirProp == R || dirProp == EN) {
316
							insertMark(operLocation);
317
							return;
318
						}
319
					}
320
					return;
321
				}
322
			}
323
		} else {
324
			if (features.ignoreHebrew) { /* process Arabic, not Hebrew */
325
				for (int i = operLocation - 1; i >= 0; i--) {
326
					byte dirProp = getDirProp(i);
327
					if (dirProp == L)
328
						return;
329
					if (dirProp == AL) {
330
						for (int j = operLocation; j < len; j++) {
331
							dirProp = getDirProp(j);
332
							if (dirProp == L)
333
								return;
334
							if (dirProp == EN || dirProp == AL || dirProp == AN) {
335
								insertMark(operLocation);
336
								return;
337
							}
338
						}
339
						return;
340
					}
341
					if (dirProp == AN && !doneAN) {
342
						for (int j = operLocation; j < len; j++) {
343
							dirProp = getDirProp(j);
344
							if (dirProp == L)
345
								return;
346
							if (dirProp == AL || dirProp == AN) {
347
								insertMark(operLocation);
348
								return;
349
							}
350
						}
351
						doneAN = true;
352
					}
353
				}
354
			} else { /* process Arabic and Hebrew */
355
				for (int i = operLocation - 1; i >= 0; i--) {
356
					byte dirProp = getDirProp(i);
357
					if (dirProp == L)
358
						return;
359
					if (dirProp == R || dirProp == AL) {
360
						for (int j = operLocation; j < len; j++) {
361
							dirProp = getDirProp(j);
362
							if (dirProp == L)
363
								return;
364
							if (dirProp == R || dirProp == EN || dirProp == AL || dirProp == AN) {
365
								insertMark(operLocation);
366
								return;
367
							}
368
						}
369
						return;
370
					}
371
					if (dirProp == AN && !doneAN) {
372
						for (int j = operLocation; j < len; j++) {
373
							dirProp = getDirProp(j);
374
							if (dirProp == L)
375
								return;
376
							if (dirProp == AL || dirProp == AN || dirProp == R) {
377
								insertMark(operLocation);
378
								return;
379
							}
380
						}
381
						doneAN = true;
382
					}
383
				}
384
			}
385
		}
386
	}
387
388
	/**
389
	 *  @see BidiComplexHelper#getFinalState()
390
	 */
391
	public int getFinalState() {
392
		return state;
393
	}
394
395
	/**
396
	 *  @see BidiComplexHelper#setFinalState(int newState)
397
	 */
398
	public void setFinalState(int newState) {
399
		state = newState;
400
	}
401
402
	/**
403
	 *  @see BidiComplexHelper#leanToFullText(String text, int initState)
404
	 */
405
	public String leanToFullText(String text, int initState) {
406
		if (text.length() == 0) {
407
			prefixLength = 0;
408
			count = 0;
409
			return text;
410
		}
411
		leanToFullTextNofix(text, initState);
412
		return addMarks(true);
413
	}
414
415
	void leanToFullTextNofix(String text, int initState) {
416
		int operCount = features.operators.length();
417
		// current position
418
		int curPos = 0;
419
		int len = text.length();
420
		// location of next token to handle
421
		int nextLocation;
422
		// index of next token to handle (if < operCount, this is an operator; otherwise a special case
423
		int idxLocation;
424
		leanText = text;
425
		offsets = new int[20];
426
		count = 0;
427
		dirProps = new byte[len];
428
		curOrient = -1;
429
		curDirection = -1;
430
		// initialize locations
431
		int k = locations.length;
432
		for (int i = 0; i < k; i++) {
433
			locations[i] = -1;
434
		}
435
		state = BidiComplexHelper.STATE_NOTHING_GOING;
436
		if (initState != BidiComplexHelper.STATE_NOTHING_GOING)
437
			curPos = processor.processSpecial(helper, initState, leanText, -1);
438
439
		while (true) {
440
			long res = computeNextLocation(curPos);
441
			nextLocation = (int) (res & 0x00000000FFFFFFFF); /* low word */
442
			if (nextLocation >= len)
443
				break;
444
			idxLocation = (int) (res >> 32); /* high word */
445
			if (idxLocation < operCount) {
446
				processOperator(nextLocation);
447
				curPos = nextLocation + 1;
448
			} else {
449
				curPos = processor.processSpecial(helper, idxLocation - operCount, leanText, nextLocation);
450
			}
451
		}
452
	}
453
454
	/**
455
	 *  @see BidiComplexHelper#leanBidiCharOffsets()
456
	 */
457
	public int[] leanBidiCharOffsets() {
458
		int[] result = new int[count];
459
		System.arraycopy(offsets, 0, result, 0, count);
460
		return result;
461
	}
462
463
	/**
464
	 *  @see BidiComplexHelper#fullBidiCharOffsets()
465
	 */
466
	public int[] fullBidiCharOffsets() {
467
		int lim = count;
468
		if (prefixLength > 0) {
469
			if (prefixLength == 1)
470
				lim++;
471
			else
472
				lim += FIXES_LENGTH;
473
		}
474
		int[] fullOffsets = new int[lim];
475
		for (int i = 0; i < prefixLength; i++) {
476
			fullOffsets[i] = i;
477
		}
478
		int added = prefixLength;
479
		for (int i = 0; i < count; i++) {
480
			fullOffsets[prefixLength + i] = offsets[i] + added;
481
			added++;
482
		}
483
		if (prefixLength > 1) {
484
			int len = leanText.length();
485
			fullOffsets[lim - 2] = len + lim - 2;
486
			fullOffsets[lim - 1] = len + lim - 1;
487
		}
488
		return fullOffsets;
489
	}
490
491
	/**
492
	 *  @see BidiComplexHelper#fullToLeanText(String text, int initState)
493
	 */
494
	public String fullToLeanText(String text, int initState) {
495
		int i; // used as loop index
496
		setMarkAndFixes();
497
		// remove any prefix and leading mark
498
		int lenText = text.length();
499
		for (i = 0; i < lenText; i++) {
500
			char c = text.charAt(i);
501
			if (c != curEmbed && c != curMark)
502
				break;
503
		}
504
		if (i > 0) { // found at least one prefix or leading mark
505
			text = text.substring(i);
506
			lenText = text.length();
507
		}
508
		// remove any suffix and trailing mark
509
		for (i = lenText - 1; i >= 0; i--) {
510
			char c = text.charAt(i);
511
			if (c != PDF && c != curMark)
512
				break;
513
		}
514
		if (i < 0) { // only suffix and trailing marks, no real data
515
			leanText = EMPTY_STRING;
516
			prefixLength = 0;
517
			count = 0;
518
			return leanText;
519
		}
520
		if (i < (lenText - 1)) { // found at least one suffix or trailing mark
521
			text = text.substring(0, i + 1);
522
			lenText = text.length();
523
		}
524
		char[] chars = text.toCharArray();
525
		// remove marks from chars
526
		int cnt = 0;
527
		for (i = 0; i < lenText; i++) {
528
			char c = chars[i];
529
			if (c == curMark)
530
				cnt++;
531
			else if (cnt > 0)
532
				chars[i - cnt] = c;
533
		}
534
		String lean = new String(chars, 0, lenText - cnt);
535
		leanToFullTextNofix(lean, initState);
536
		String full = addMarks(false); /* only marks, no prefix/suffix */
537
		if (full.equals(text))
538
			return lean;
539
540
		// There are some marks in full which are not in text and/or vice versa.
541
		// We need to add to lean any mark appearing in text and not in full.
542
		// The completed lean can never be longer than text itself.
543
		char[] newChars = new char[lenText];
544
		char cFull, cText;
545
		int idxFull, idxText, idxLean, markPos, newCharsPos;
546
		int lenFull = full.length();
547
		idxFull = idxText = idxLean = newCharsPos = 0;
548
		while (idxText < lenText && idxFull < lenFull) {
549
			cFull = full.charAt(idxFull);
550
			cText = text.charAt(idxText);
551
			if (cFull == cText) { /* chars are equal, proceed */
552
				idxText++;
553
				idxFull++;
554
				continue;
555
			}
556
			if (cFull == curMark) { /* extra Mark in full text */
557
				idxFull++;
558
				continue;
559
			}
560
			if (cText == curMark) { /* extra Mark in source full text */
561
				idxText++;
562
				// idxText-2 always >= 0 since leading Marks were removed from text
563
				if (text.charAt(idxText - 2) == curMark)
564
					continue; // ignore successive Marks in text after the first one
565
				markPos = fullToLeanPos(idxFull);
566
				// copy from chars (== lean) to newChars until here
567
				for (i = idxLean; i < markPos; i++) {
568
					newChars[newCharsPos++] = chars[i];
569
				}
570
				idxLean = markPos;
571
				newChars[newCharsPos++] = curMark;
572
				continue;
573
			}
574
			// we should never get here (extra char which is not a Mark)
575
			throw new IllegalStateException("Internal error: extra character not a Mark."); //$NON-NLS-1$
576
		}
577
		if (idxText < lenText) /* full ended before text - this should never happen */
578
			throw new IllegalStateException("Internal error: unexpected EOL."); //$NON-NLS-1$
579
580
		// copy the last part of chars to newChars
581
		for (i = idxLean; i < lean.length(); i++) {
582
			newChars[newCharsPos++] = chars[i];
583
		}
584
		lean = new String(newChars, 0, newCharsPos);
585
		leanText = lean;
586
		return lean;
587
	}
588
589
	/**
590
	 *  @see BidiComplexHelper#leanToFullPos(int pos)
591
	 */
592
	public int leanToFullPos(int pos) {
593
		int added = prefixLength;
594
		for (int i = 0; i < count; i++) {
595
			if (offsets[i] <= pos)
596
				added++;
597
			else
598
				return pos + added;
599
		}
600
		return pos + added;
601
	}
602
603
	/**
604
	 *  @see BidiComplexHelper#fullToLeanPos(int pos)
605
	 */
606
	public int fullToLeanPos(int pos) {
607
		int len = leanText.length();
608
		int added = 0;
609
		pos -= prefixLength;
610
		for (int i = 0; i < count; i++) {
611
			if ((offsets[i] + added) < pos)
612
				added++;
613
			else
614
				break;
615
		}
616
		pos -= added;
617
		if (pos < 0)
618
			pos = 0;
619
		else if (pos > len)
620
			pos = len;
621
		return pos;
622
	}
623
624
	/**
625
	 *  @see BidiComplexHelper#insertMark(int offset)
626
	 */
627
	public void insertMark(int offset) {
628
		int index = count - 1; // index of greatest member <= offset
629
		// look up after which member the new offset should be inserted
630
		while (index >= 0) {
631
			int wrkOffset = offsets[index];
632
			if (offset > wrkOffset)
633
				break;
634
			if (offset == wrkOffset)
635
				return; // avoid duplicates
636
			index--;
637
		}
638
		index++; // index now points at where to insert
639
		// check if we have an available slot for new member
640
		if (count >= (offsets.length - 1)) {
641
			int[] newOffsets = new int[offsets.length * 2];
642
			System.arraycopy(offsets, 0, newOffsets, 0, count);
643
			offsets = newOffsets;
644
		}
645
646
		int length = count - index; // number of members to move up
647
		if (length > 0) // shift right all members greater than offset
648
			System.arraycopy(offsets, index, offsets, index + 1, length);
649
650
		offsets[index] = offset;
651
		count++;
652
		// if the offset is 0, adding a mark does not change anything
653
		if (offset < 1)
654
			return;
655
656
		byte dirProp = getDirProp(offset);
657
		// if the current char is a strong one or a digit, we change the
658
		//   dirProp of the previous char to account for the inserted mark.
659
		// In the following lines, L, R, AL, AN and EN represent bidi categories
660
		// as defined in the Unicode Bidirectional Algorithm
661
		// ( http://www.unicode.org/reports/tr9/ ).
662
		// L  represents the category Left to Right character.
663
		// R  represents the category Right to Left character.
664
		// AL represents the category Arabic Letter.
665
		// AN represents the category Arabic Number.
666
		// EN  represents the category European Number.
667
		if (dirProp == L || dirProp == R || dirProp == AL || dirProp == EN || dirProp == AN)
668
			index = offset - 1;
669
		else
670
			// if the current char is a neutral, we change its own dirProp
671
			index = offset;
672
		setMarkAndFixes();
673
		setDirProp(index, curStrong);
674
	}
675
676
	String addMarks(boolean addFixes) {
677
		// add prefix/suffix only if addFixes is true
678
		if ((count == 0) && (!addFixes || (getCurOrient() == getCurDirection()) || (curOrient == BidiComplexEnvironment.ORIENT_IGNORE))) {
679
			prefixLength = 0;
680
			return leanText;
681
		}
682
		int len = leanText.length();
683
		int newLen = len + count;
684
		if (addFixes && ((getCurOrient() != getCurDirection()) || (curOrient == BidiComplexEnvironment.ORIENT_UNKNOWN))) {
685
			if ((environment.orientation & BidiComplexEnvironment.ORIENT_CONTEXTUAL_LTR) == 0) {
686
				prefixLength = PREFIX_LENGTH;
687
				newLen += FIXES_LENGTH;
688
			} else { /* contextual orientation */
689
				prefixLength = 1;
690
				newLen++; /* +1 for a mark char */
691
			}
692
		} else {
693
			prefixLength = 0;
694
		}
695
		char[] fullChars = new char[newLen];
696
		// add a dummy offset as fence
697
		offsets[count] = len;
698
		int added = prefixLength;
699
		// add marks at offsets
700
		setMarkAndFixes();
701
		for (int i = 0, j = 0; i < len; i++) {
702
			char c = leanText.charAt(i);
703
			if (i == offsets[j]) {
704
				fullChars[i + added] = curMark;
705
				added++;
706
				j++;
707
			}
708
			fullChars[i + added] = c;
709
		}
710
		if (prefixLength > 0) { /* add prefix/suffix ? */
711
			if (prefixLength == 1) { /* contextual orientation */
712
				fullChars[0] = curMark;
713
			} else {
714
				// When the orientation is RTL, we need to add EMBED at the
715
				// start of the text and PDF at its end.
716
				// However, because of a bug in Windows' handling of LRE/PDF,
717
				// we add EMBED_PREFIX at the start and EMBED_SUFFIX at the end.
718
				fullChars[0] = curEmbed;
719
				fullChars[1] = curMark;
720
				fullChars[newLen - 1] = PDF;
721
				fullChars[newLen - 2] = curMark;
722
			}
723
		}
724
		return new String(fullChars);
725
	}
726
727
	/**
728
	 *  @see BidiComplexHelper#getEnvironment()
729
	 */
730
	public BidiComplexEnvironment getEnvironment() {
731
		return environment;
732
	}
733
734
	/**
735
	 *  @see BidiComplexHelper#setEnvironment(BidiComplexEnvironment environment)
736
	 */
737
	public void setEnvironment(BidiComplexEnvironment environment) {
738
		this.environment = environment;
739
		features = processor.updateEnvironment(helper, environment);
740
		specialsCount = features.specialsCount;
741
		if ((features.operators.length() + specialsCount) > locations.length)
742
			locations = new int[features.operators.length() + specialsCount];
743
744
	}
745
746
	/**
747
	 *  @see BidiComplexHelper#getFeatures()
748
	 */
749
	public BidiComplexFeatures getFeatures() {
750
		return features;
751
	}
752
753
	/**
754
	 *  @see BidiComplexHelper#setFeatures(BidiComplexFeatures features)
755
	 */
756
	public void setFeatures(BidiComplexFeatures features) {
757
		if ((features.operators.length() + specialsCount) > locations.length)
758
			locations = new int[features.operators.length() + specialsCount];
759
		this.features = features;
760
	}
761
762
}
(-)src/org/eclipse/equinox/bidi/internal/BidiComplexSingle.java (+53 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal;
12
13
import org.eclipse.equinox.bidi.custom.BidiComplexProcessor;
14
15
import org.eclipse.equinox.bidi.*;
16
17
/**
18
 *  <code>BidiComplexSingle</code> is a processor for complex expressions
19
 *  composed of two parts separated by an operator.
20
 *  The first occurrence of the operator delimits the end of the first part
21
 *  and the start of the second part. Further occurrences of the operator,
22
 *  if any, are treated like regular characters of the second text part.
23
 *  The processor makes sure that the expression be presented in the form
24
 *  (assuming that the equal sign is the operator):
25
 *  <pre>
26
 *  part1=part2
27
 *  </pre>
28
 *  The {@link BidiComplexFeatures#operators operators}
29
 *  field in the {@link BidiComplexFeatures features}
30
 *  of this processor should contain exactly one character.
31
 *  Additional characters will be ignored.
32
 *
33
 *  @author Matitiahu Allouche
34
 */
35
public abstract class BidiComplexSingle extends BidiComplexProcessor {
36
37
	/**
38
	 *  This method locates occurrences of the operator.
39
	 */
40
	public int indexOfSpecial(BidiComplexHelper helper, int caseNumber, String srcText, int fromIndex) {
41
		return srcText.indexOf(helper.impl.features.operators.charAt(0), fromIndex);
42
	}
43
44
	/**
45
	 *  This method inserts a mark before the operator if needed and
46
	 *  skips to the end of the source string.
47
	 */
48
	public int processSpecial(BidiComplexHelper helper, int caseNumber, String srcText, int operLocation) {
49
		helper.processOperator(operLocation);
50
		return srcText.length();
51
	}
52
53
}
(-)src/org/eclipse/equinox/bidi/internal/BidiComplexTypesCollector.java (+112 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.bidi.internal;
12
13
import org.eclipse.equinox.bidi.custom.IBidiComplexProcessor;
14
15
import java.util.HashMap;
16
import java.util.Map;
17
import org.eclipse.core.runtime.*;
18
19
public class BidiComplexTypesCollector implements IRegistryEventListener {
20
21
	private static final String EXT_POINT = "org.eclipse.equinox.bidi.bidiTypes"; //$NON-NLS-1$
22
23
	private static final String CE_NAME = "typeDescription"; //$NON-NLS-1$
24
	private static final String ATTR_TYPE = "type"; //$NON-NLS-1$
25
	private static final String ATTR_PROCESSOR = "class"; //$NON-NLS-1$
26
27
	private Map types;
28
	private Map factories;
29
30
	static private BidiComplexTypesCollector instance = new BidiComplexTypesCollector();
31
32
	private BidiComplexTypesCollector() {
33
		IExtensionRegistry registry = RegistryFactory.getRegistry();
34
		registry.addListener(this, EXT_POINT);
35
	}
36
37
	static public BidiComplexTypesCollector getInstance() {
38
		return instance;
39
	}
40
41
	public String[] getTypes() {
42
		if (types == null)
43
			read();
44
		int size = types.size();
45
		String[] result = new String[size];
46
		types.keySet().toArray(result);
47
		return result;
48
	}
49
50
	public IBidiComplexProcessor getProcessor(String type) {
51
		if (types == null)
52
			read();
53
		Object processor = types.get(type);
54
		if (processor instanceof IBidiComplexProcessor)
55
			return (IBidiComplexProcessor) processor;
56
		return null;
57
	}
58
59
	private void read() {
60
		if (types == null)
61
			types = new HashMap();
62
		else
63
			types.clear();
64
65
		if (factories == null)
66
			factories = new HashMap();
67
		else
68
			factories.clear();
69
70
		IExtensionRegistry registry = RegistryFactory.getRegistry();
71
		IExtensionPoint extPoint = registry.getExtensionPoint(EXT_POINT);
72
		IExtension[] extensions = extPoint.getExtensions();
73
74
		for (int i = 0; i < extensions.length; i++) {
75
			IConfigurationElement[] confElements = extensions[i].getConfigurationElements();
76
			for (int j = 0; j < confElements.length; j++) {
77
				if (CE_NAME != confElements[j].getName())
78
					BidiComplexActivator.logError("BiDi types: unexpected element name " + confElements[j].getName(), new IllegalArgumentException()); //$NON-NLS-1$
79
				String type = confElements[j].getAttribute(ATTR_TYPE);
80
				Object processor;
81
				try {
82
					processor = confElements[j].createExecutableExtension(ATTR_PROCESSOR);
83
				} catch (CoreException e) {
84
					BidiComplexActivator.logError("BiDi types: unable to create processor for " + type, e); //$NON-NLS-1$
85
					continue;
86
				}
87
				types.put(type, processor);
88
				factories.put(type, confElements[j]);
89
			}
90
		}
91
	}
92
93
	public void added(IExtension[] extensions) {
94
		types = null;
95
		factories = null;
96
	}
97
98
	public void removed(IExtension[] extensions) {
99
		types = null;
100
		factories = null;
101
	}
102
103
	public void added(IExtensionPoint[] extensionPoints) {
104
		types = null;
105
		factories = null;
106
	}
107
108
	public void removed(IExtensionPoint[] extensionPoints) {
109
		types = null;
110
		factories = null;
111
	}
112
}
(-)src/org/eclipse/equinox/bidi/internal/complexp/BiDiActivator.java (-62 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.complexp;
12
13
import org.eclipse.osgi.framework.log.FrameworkLog;
14
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
15
import org.osgi.framework.BundleActivator;
16
import org.osgi.framework.BundleContext;
17
import org.osgi.util.tracker.ServiceTracker;
18
19
public class BiDiActivator implements BundleActivator {
20
21
	private ServiceTracker logTracker = null;
22
	private BundleContext bundleContext;
23
24
	private static BiDiActivator instance;
25
26
	public BiDiActivator() {
27
		instance = this; // there is only one bundle activator
28
	}
29
30
	public void start(BundleContext context) throws Exception {
31
		bundleContext = context;
32
		instance = this;
33
	}
34
35
	public void stop(BundleContext context) throws Exception {
36
		if (logTracker != null) {
37
			logTracker.close();
38
			logTracker = null;
39
		}
40
		bundleContext = null;
41
	}
42
43
	private FrameworkLog getFrameworkLog() {
44
		if (logTracker == null) {
45
			logTracker = new ServiceTracker(bundleContext, FrameworkLog.class.getName(), null);
46
			logTracker.open();
47
		}
48
		return (FrameworkLog) logTracker.getService();
49
	}
50
51
	static public void logError(String message, Exception e) {
52
		FrameworkLog frameworkLog = instance.getFrameworkLog();
53
		if (frameworkLog != null) {
54
			frameworkLog.log(new FrameworkLogEntry("org.eclipse.equinox.bidi", FrameworkLogEntry.ERROR, 1, message, 0, e, null)); //$NON-NLS-1$
55
			return;
56
		}
57
		System.err.println(message);
58
		if (e != null)
59
			e.printStackTrace();
60
	}
61
62
}
(-)src/org/eclipse/equinox/bidi/internal/complexp/BiDiTypesCollector.java (-129 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.complexp;
12
13
import java.util.HashMap;
14
import java.util.Map;
15
import org.eclipse.core.runtime.*;
16
import org.eclipse.equinox.bidi.complexp.IComplExpProcessor;
17
18
public class BiDiTypesCollector implements IRegistryEventListener {
19
20
	private static final String EXT_POINT = "org.eclipse.equinox.bidi.bidiTypes"; //$NON-NLS-1$
21
22
	private static final String CE_NAME = "typeDescription"; //$NON-NLS-1$
23
	private static final String ATTR_TYPE = "type"; //$NON-NLS-1$
24
	private static final String ATTR_PROCESSOR = "class"; //$NON-NLS-1$
25
26
	private Map types;
27
	private Map factories;
28
29
	static private BiDiTypesCollector instance = new BiDiTypesCollector();
30
31
	private BiDiTypesCollector() {
32
		IExtensionRegistry registry = RegistryFactory.getRegistry();
33
		registry.addListener(this, EXT_POINT);
34
	}
35
36
	static public BiDiTypesCollector getInstance() {
37
		return instance;
38
	}
39
40
	public String[] getTypes() {
41
		if (types == null)
42
			read();
43
		int size = types.size();
44
		String[] result = new String[size];
45
		types.keySet().toArray(result);
46
		return result;
47
	}
48
49
	public IComplExpProcessor getProcessor(String type) {
50
		if (types == null)
51
			read();
52
		Object processor = types.get(type);
53
		if (processor instanceof IComplExpProcessor)
54
			return (IComplExpProcessor) processor;
55
		return null;
56
	}
57
58
	public IComplExpProcessor makeProcessor(String type) {
59
		if (factories == null)
60
			read();
61
		IConfigurationElement ce = (IConfigurationElement) factories.get(type);
62
		if (ce == null)
63
			return null;
64
		Object processor;
65
		try {
66
			processor = ce.createExecutableExtension(ATTR_PROCESSOR);
67
		} catch (CoreException e) {
68
			BiDiActivator.logError("BiDi types: unable to create processor for " + type, e); //$NON-NLS-1$
69
			return null;
70
		}
71
		if (processor instanceof IComplExpProcessor)
72
			return (IComplExpProcessor) processor;
73
		return null;
74
	}
75
76
	private void read() {
77
		if (types == null)
78
			types = new HashMap();
79
		else
80
			types.clear();
81
82
		if (factories == null)
83
			factories = new HashMap();
84
		else
85
			factories.clear();
86
87
		IExtensionRegistry registry = RegistryFactory.getRegistry();
88
		IExtensionPoint extPoint = registry.getExtensionPoint(EXT_POINT);
89
		IExtension[] extensions = extPoint.getExtensions();
90
91
		for (int i = 0; i < extensions.length; i++) {
92
			IConfigurationElement[] confElements = extensions[i].getConfigurationElements();
93
			for (int j = 0; j < confElements.length; j++) {
94
				if (CE_NAME != confElements[j].getName())
95
					BiDiActivator.logError("BiDi types: unexpected element name " + confElements[j].getName(), new IllegalArgumentException()); //$NON-NLS-1$
96
				String type = confElements[j].getAttribute(ATTR_TYPE);
97
				Object processor;
98
				try {
99
					processor = confElements[j].createExecutableExtension(ATTR_PROCESSOR);
100
				} catch (CoreException e) {
101
					BiDiActivator.logError("BiDi types: unable to create processor for " + type, e); //$NON-NLS-1$
102
					continue;
103
				}
104
				types.put(type, processor);
105
				factories.put(type, confElements[j]);
106
			}
107
		}
108
	}
109
110
	public void added(IExtension[] extensions) {
111
		types = null;
112
		factories = null;
113
	}
114
115
	public void removed(IExtension[] extensions) {
116
		types = null;
117
		factories = null;
118
	}
119
120
	public void added(IExtensionPoint[] extensionPoints) {
121
		types = null;
122
		factories = null;
123
	}
124
125
	public void removed(IExtensionPoint[] extensionPoints) {
126
		types = null;
127
		factories = null;
128
	}
129
}
(-)src/org/eclipse/equinox/bidi/internal/complexp/ComplExpDelims.java (-75 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.complexp;
12
13
import org.eclipse.equinox.bidi.complexp.IComplExpProcessor;
14
15
/**
16
 *  <code>ComplExpDelims</code> is a processor for complex expressions
17
 *  composed of text segments separated by operators where the text segments
18
 *  may include delimited parts within which operators are treated like
19
 *  regular characters.
20
 *
21
 *  @see IComplExpProcessor
22
 *  @see ComplExpBasic
23
 *
24
 *  @author Matitiahu Allouche
25
 */
26
public class ComplExpDelims extends ComplExpBasic {
27
	char[] delims;
28
29
	/**
30
	 *  Constructor for a complex expressions processor with support for
31
	 *  operators and delimiters.
32
	 *
33
	 *  @param operators string grouping one-character operators which
34
	 *         separate the text of the complex expression into segments.
35
	 *
36
	 *  @param delims delimiters implemented in this class instance.
37
	 *         This parameter is a string which must include an even
38
	 *         number of characters. The first 2 characters of a string
39
	 *         constitute a pair, the next 2 characters are a second pair, etc...
40
	 *         In each pair, the first character is a start delimiter and
41
	 *         the second character is an end delimiter. In the <i>lean</i>
42
	 *         text, any part starting with a start delimiter and ending with
43
	 *         the corresponding end delimiter is a delimited part. Within a
44
	 *         delimited part, operators are treated like regular characters,
45
	 *         which means that they do not define new segments.
46
	 */
47
	public ComplExpDelims(String operators, String delims) {
48
		super(operators, delims.length() / 2);
49
		this.delims = delims.toCharArray();
50
	}
51
52
	/**
53
	 *  This method is not supposed to be invoked directly by users of this
54
	 *  class. It may  be overridden by subclasses of this class.
55
	 */
56
	protected int indexOfSpecial(int whichSpecial, String srcText, int fromIndex) {
57
		char delim = delims[whichSpecial * 2];
58
59
		return srcText.indexOf(delim, fromIndex);
60
	}
61
62
	/**
63
	 *  This method is not supposed to be invoked directly by users of this
64
	 *  class. It may  be overridden by subclasses of this class.
65
	 */
66
	protected int processSpecial(int whichSpecial, String srcText, int operLocation) {
67
		processOperator(operLocation);
68
		int loc = operLocation + 1;
69
		char delim = delims[(whichSpecial * 2) + 1];
70
		loc = srcText.indexOf(delim, loc);
71
		if (loc < 0)
72
			return srcText.length();
73
		return loc + 1;
74
	}
75
}
(-)src/org/eclipse/equinox/bidi/internal/complexp/ComplExpDelimsEsc.java (-82 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.complexp;
12
13
import org.eclipse.equinox.bidi.complexp.IComplExpProcessor;
14
15
/**
16
 *  <code>ComplExpDelims</code> is a processor for complex expressions
17
 *  composed of text segments separated by operators where the text segments
18
 *  may include delimited parts within which operators are treated like
19
 *  regular characters and the delimiters may be escaped.
20
 *  This is similar to {@link ComplExpDelims} except
21
 *  that delimiters can be escaped using the backslash character.
22
 *  <ul>
23
 *    <li>Two consecutive backslashes in a delimited part are treated like
24
 *        regular characters.</li>
25
 *    <li>An ending delimiter preceded by an odd number of backslashes is
26
 *        treated like a regular character of a delimited part.</li>
27
 *  </ul>
28
 *
29
 *  @see IComplExpProcessor
30
 *  @see ComplExpBasic
31
 *
32
 *  @author Matitiahu Allouche
33
 */
34
public class ComplExpDelimsEsc extends ComplExpDelims {
35
	/**
36
	 *  Constructor for a complex expressions processor with support for
37
	 *  operators and delimiters which can be escaped.
38
	 *
39
	 *  @param operators string grouping one-character operators which
40
	 *         separate the text of the complex expression into segments.
41
	 *
42
	 *  @param delims delimiters implemented in this class instance.
43
	 *         This parameter is a string which must include an even
44
	 *         number of characters. The first 2 characters of a string
45
	 *         constitute a pair, the next 2 characters are a second pair, etc...
46
	 *         In each pair, the first character is a start delimiter and
47
	 *         the second character is an end delimiter. In the <i>lean</i>
48
	 *         text, any part starting with a start delimiter and ending with
49
	 *         the corresponding end delimiter is a delimited part. Within a
50
	 *         delimited part, operators are treated like regular characters,
51
	 *         which means that they do not define new segments.<br>
52
	 *         &nbsp;<br>
53
	 *         Note however that an ending delimiter preceded by an odd
54
	 *         number of backslashes is considered as a regular character
55
	 *         and does not mark the termination of a delimited part.
56
	 */
57
	public ComplExpDelimsEsc(String operators, String delims) {
58
		super(operators, delims);
59
	}
60
61
	/**
62
	 *  This method is not supposed to be invoked directly by users of this
63
	 *  class. It may  be overridden by subclasses of this class.
64
	 */
65
	protected int processSpecial(int whichSpecial, String srcText, int operLocation) {
66
		processOperator(operLocation);
67
		int loc = operLocation + 1;
68
		char delim = delims[(whichSpecial * 2) + 1];
69
		while (true) {
70
			loc = srcText.indexOf(delim, loc);
71
			if (loc < 0)
72
				return srcText.length();
73
			int cnt = 0;
74
			for (int i = loc - 1; srcText.charAt(i) == '\\'; i--) {
75
				cnt++;
76
			}
77
			loc++;
78
			if ((cnt & 1) == 0)
79
				return loc;
80
		}
81
	}
82
}
(-)src/org/eclipse/equinox/bidi/internal/complexp/ComplExpSingle.java (-65 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.complexp;
12
13
import org.eclipse.equinox.bidi.complexp.IComplExpProcessor;
14
15
/**
16
 *  <code>ComplExpSingle</code> is a processor for complex expressions
17
 *  composed of two parts separated by an operator.
18
 *  The first occurrence of the operator delimits the end of the first part
19
 *  and the start of the second part. Further occurrences of the operator,
20
 *  if any, are treated like regular characters of the second text part.
21
 *  The processor makes sure that the expression be presented in the form
22
 *  (assuming that the equal sign is the operator):
23
 *  <pre>
24
 *  part1=part2
25
 *  </pre>
26
 *
27
 *  @see IComplExpProcessor
28
 *  @see ComplExpBasic
29
 *
30
 *  @author Matitiahu Allouche
31
 */
32
public class ComplExpSingle extends ComplExpBasic {
33
	char separator;
34
35
	/**
36
	 *  Constructor for a complex expressions processor with support for one
37
	 *  operator.
38
	 *
39
	 *  @param operators string including at least one character. The
40
	 *         first character of the string is the operator which divides
41
	 *         the expression into 2 parts.
42
	 *
43
	 */
44
	public ComplExpSingle(String operators) {
45
		super(operators, 1);
46
		separator = operators.charAt(0);
47
	}
48
49
	/**
50
	 *  This method is not supposed to be invoked directly by users of this
51
	 *  class. It may  be overridden by subclasses of this class.
52
	 */
53
	protected int indexOfSpecial(int whichSpecial, String srcText, int fromIndex) {
54
		return srcText.indexOf(separator, fromIndex);
55
	}
56
57
	/**
58
	 *  This method is not supposed to be invoked directly by users of this
59
	 *  class. It may  be overridden by subclasses of this class.
60
	 */
61
	protected int processSpecial(int whichSpecial, String srcText, int operLocation) {
62
		processOperator(operLocation);
63
		return srcText.length();
64
	}
65
}
(-)src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpComma.java (-25 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.complexp.consumable;
12
13
import org.eclipse.equinox.bidi.internal.complexp.ComplExpBasic;
14
15
/**
16
 * Processor adapted to processing comma-delimited lists, such as: 
17
 * <pre>
18
 *  part1,part2,part3
19
 * </pre>
20
 */
21
public class ComplExpComma extends ComplExpBasic {
22
	public ComplExpComma() {
23
		super(","); //$NON-NLS-1$
24
	}
25
}
(-)src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpEmail.java (-22 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.complexp.consumable;
12
13
import org.eclipse.equinox.bidi.internal.complexp.ComplExpDelimsEsc;
14
15
/**
16
 * Processor adapted to processing e-mail addresses. 
17
 */
18
public class ComplExpEmail extends ComplExpDelimsEsc {
19
	public ComplExpEmail() {
20
		super("<>.:,;@", "()\"\""); //$NON-NLS-1$ //$NON-NLS-2$
21
	}
22
}
(-)src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpFile.java (-22 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.complexp.consumable;
12
13
import org.eclipse.equinox.bidi.internal.complexp.ComplExpBasic;
14
15
/**
16
 * Processor adapted to processing directory and file paths. 
17
 */
18
public class ComplExpFile extends ComplExpBasic {
19
	public ComplExpFile() {
20
		super(":/\\."); //$NON-NLS-1$
21
	}
22
}
(-)src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpJava.java (-117 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.complexp.consumable;
12
13
import org.eclipse.equinox.bidi.complexp.IComplExpProcessor;
14
import org.eclipse.equinox.bidi.internal.complexp.ComplExpBasic;
15
16
/**
17
 *  <code>ComplExpJava</code> is a processor for complex expressions
18
 *  composed of Java statements. Such a complex expression may span
19
 *  multiple lines.
20
 *  <p>
21
 *  In applications like an editor where parts of the text might be modified
22
 *  while other parts are not, the user may want to call
23
 *  {@link IComplExpProcessor#leanToFullText leanToFullText}
24
 *  separately on each line and save the initial state of each line (this is
25
 *  the final state of the previous line which can be retrieved using
26
 *  {@link IComplExpProcessor#getFinalState getFinalState}. If both the content
27
 *  of a line and its initial state have not changed, the user can be sure that
28
 *  the last <i>full</i> text computed for this line has not changed either.
29
 *
30
 *  @see IComplExpProcessor
31
 *  @author Matitiahu Allouche
32
 */
33
public class ComplExpJava extends ComplExpBasic {
34
	private static final byte WS = Character.DIRECTIONALITY_WHITESPACE;
35
	static final String operators = "[](){}.+-<>=~!&*/%^|?:,;\t"; //$NON-NLS-1$
36
	static String lineSep;
37
38
	/**
39
	 *  Constructor for a complex expressions processor with support for
40
	 *  Java statements.
41
	 */
42
	public ComplExpJava() {
43
		super(operators, 4);
44
		// TBD use bundle properties
45
		if (lineSep == null)
46
			lineSep = System.getProperty("line.separator", "\n"); //$NON-NLS-1$//$NON-NLS-2$
47
	}
48
49
	/**
50
	 *  This method is not supposed to be invoked directly by users of this
51
	 *  class. It may  be overridden by subclasses of this class.
52
	 */
53
	protected int indexOfSpecial(int whichSpecial, String srcText, int fromIndex) {
54
		switch (whichSpecial) {
55
			case 0 : /* space */
56
				return srcText.indexOf(' ', fromIndex);
57
			case 1 : /* literal */
58
				return srcText.indexOf('"', fromIndex);
59
			case 2 : /* slash-aster comment */
60
				return srcText.indexOf("/*", fromIndex); //$NON-NLS-1$
61
			case 3 : /* slash-slash comment */
62
				return srcText.indexOf("//", fromIndex); //$NON-NLS-1$
63
		}
64
		// we should never get here
65
		return -1;
66
	}
67
68
	/**
69
	 *  This method is not supposed to be invoked directly by users of this
70
	 *  class. It may  be overridden by subclasses of this class.
71
	 */
72
	protected int processSpecial(int whichSpecial, String srcText, int operLocation) {
73
		int loc, cnt, i;
74
75
		processOperator(operLocation);
76
		switch (whichSpecial) {
77
			case 0 : /* space */
78
				operLocation++;
79
				while (operLocation < srcText.length() && srcText.charAt(operLocation) == ' ') {
80
					setDirProp(operLocation, WS);
81
					operLocation++;
82
				}
83
				return operLocation;
84
			case 1 : /* literal */
85
				loc = operLocation + 1;
86
				while (true) {
87
					loc = srcText.indexOf('"', loc);
88
					if (loc < 0)
89
						return srcText.length();
90
					for (cnt = 0, i = loc - 1; srcText.charAt(i) == '\\'; i--) {
91
						cnt++;
92
					}
93
					loc++;
94
					if ((cnt & 1) == 0)
95
						return loc;
96
				}
97
			case 2 : /* slash-aster comment */
98
				if (operLocation < 0)
99
					loc = 0; // initial state from previous line
100
				else
101
					loc = operLocation + 2; // skip the opening slash-aster
102
				loc = srcText.indexOf("*/", loc); //$NON-NLS-1$
103
				if (loc < 0) {
104
					state = 2;
105
					return srcText.length();
106
				}
107
				return loc + 2;
108
			case 3 : /* slash-slash comment */
109
				loc = srcText.indexOf(lineSep, operLocation + 2);
110
				if (loc < 0)
111
					return srcText.length();
112
				return loc + lineSep.length();
113
		}
114
		// we should never get here
115
		return operLocation + 1;
116
	}
117
}
(-)src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpMath.java (-24 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.complexp.consumable;
12
13
import org.eclipse.equinox.bidi.internal.complexp.ComplExpBasic;
14
15
/**
16
 * Processor adapted to processing arithmetic expressions with right-to-left 
17
 * base direction. 
18
 */
19
public class ComplExpMath extends ComplExpBasic {
20
	public ComplExpMath() {
21
		super("+-/*()="); //$NON-NLS-1$
22
		setDirection(DIRECTION_RTL);
23
	}
24
}
(-)src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpProperty.java (-28 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.complexp.consumable;
12
13
import org.eclipse.equinox.bidi.internal.complexp.ComplExpSingle;
14
15
/**
16
 * Processor adapted to processing property file statements. 
17
 * It expects the following string format:
18
 * <pre>
19
 *  name=value
20
 * </pre>
21
 */
22
public class ComplExpProperty extends ComplExpSingle {
23
24
	public ComplExpProperty() {
25
		super("="); //$NON-NLS-1$
26
	}
27
28
}
(-)src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpRegex.java (-201 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.complexp.consumable;
12
13
import org.eclipse.equinox.bidi.complexp.IComplExpProcessor;
14
import org.eclipse.equinox.bidi.internal.complexp.ComplExpBasic;
15
16
/**
17
 *  <code>ComplExpRegex</code> is a processor for regular expressions.
18
 *  Such expressions may span multiple lines.
19
 *  <p>
20
 *  In applications like an editor where parts of the text might be modified
21
 *  while other parts are not, the user may want to call
22
 *  {@link IComplExpProcessor#leanToFullText leanToFullText}
23
 *  separately on each line and save the initial state of each line (this is
24
 *  the final state of the previous line which can be retrieved using
25
 *  {@link IComplExpProcessor#getFinalState getFinalState}. If both the content
26
 *  of a line and its initial state have not changed, the user can be sure that
27
 *  the last <i>full</i> text computed for this line has not changed either.
28
 *
29
 *  @see IComplExpProcessor
30
 *  @author Matitiahu Allouche
31
 */
32
public class ComplExpRegex extends ComplExpBasic {
33
	static final String operators = ""; //$NON-NLS-1$
34
	static final String[] startStrings = {"(?#", /*  0 *//* comment (?#...) *///$NON-NLS-1$
35
			"(?<", /*  1 *//* named group (?<name> *///$NON-NLS-1$
36
			"(?'", /*  2 *//* named group (?'name' *///$NON-NLS-1$
37
			"(?(<", /*  3 *//* conditional named back reference (?(<name>) *///$NON-NLS-1$
38
			"(?('", /*  4 *//* conditional named back reference (?('name') *///$NON-NLS-1$
39
			"(?(", /*  5 *//* conditional named back reference (?(name) *///$NON-NLS-1$
40
			"(?&", /*  6 *//* named parentheses reference (?&name) *///$NON-NLS-1$
41
			"(?P<", /*  7 *//* named group (?P<name> *///$NON-NLS-1$
42
			"\\k<", /*  8 *//* named back reference \k<name> *///$NON-NLS-1$
43
			"\\k'", /*  9 *//* named back reference \k'name' *///$NON-NLS-1$
44
			"\\k{", /* 10 *//* named back reference \k{name} *///$NON-NLS-1$
45
			"(?P=", /* 11 *//* named back reference (?P=name) *///$NON-NLS-1$
46
			"\\g{", /* 12 *//* named back reference \g{name} *///$NON-NLS-1$
47
			"\\g<", /* 13 *//* subroutine call \g<name> *///$NON-NLS-1$
48
			"\\g'", /* 14 *//* subroutine call \g'name' *///$NON-NLS-1$
49
			"(?(R&", /* 15 *//* named back reference recursion (?(R&name) *///$NON-NLS-1$
50
			"\\Q" /* 16 *//* quoted sequence \Q...\E *///$NON-NLS-1$
51
	};
52
	static final char[] endChars = {
53
			// 0    1     2    3    4    5    6    7    8     9   10   11   12   13    14   15
54
			')', '>', '\'', ')', ')', ')', ')', '>', '>', '\'', '}', ')', '}', '>', '\'', ')'};
55
	static final int numberOfStrings = startStrings.length;
56
	static final int maxSpecial = numberOfStrings + 1;
57
58
	/**
59
	 *  Constructor for a complex expressions processor with support for
60
	 *  regular expressions.
61
	 */
62
	public ComplExpRegex() {
63
		super(operators, maxSpecial);
64
	}
65
66
	/**
67
	 *  This method is not supposed to be invoked directly by users of this
68
	 *  class. It may  be overridden by subclasses of this class.
69
	 */
70
	protected int indexOfSpecial(int whichSpecial, String srcText, int fromIndex) {
71
		byte dirProp;
72
73
		if (whichSpecial < numberOfStrings) {
74
			/*  0 *//* comment (?#...) */
75
			/*  1 *//* named group (?<name> */
76
			/*  2 *//* named group (?'name' */
77
			/*  3 *//* conditional named back reference (?(name) */
78
			/*  4 *//* conditional named back reference (?(<name>) */
79
			/*  5 *//* conditional named back reference (?('name') */
80
			/*  6 *//* named parentheses reference (?&name) */
81
			/*  7 *//* named group (?P<name> */
82
			/*  8 *//* named back reference \k<name> */
83
			/*  9 *//* named back reference \k'name' */
84
			/* 10 *//* named back reference \k{name} */
85
			/* 11 *//* named back reference (?P=name) */
86
			/* 12 *//* named back reference \g{name} */
87
			/* 13 *//* subroutine call \g<name> */
88
			/* 14 *//* subroutine call \g'name' */
89
			/* 15 *//* named back reference recursion (?(R&name) */
90
			/* 16 *//* quoted sequence \Q...\E */
91
			return srcText.indexOf(startStrings[whichSpecial], fromIndex);
92
		}
93
		// look for R, AL, AN, EN which are potentially needing a mark
94
		for (; fromIndex < srcText.length(); fromIndex++) {
95
			// there never is a need for a mark before the first char
96
			if (fromIndex <= 0)
97
				continue;
98
99
			dirProp = getDirProp(fromIndex);
100
			// R and AL will always be examined using processOperator()
101
			if (dirProp == R || dirProp == AL)
102
				return fromIndex;
103
104
			if (dirProp == EN || dirProp == AN) {
105
				// no need for a mark after the first digit in a number
106
				if (getDirProp(fromIndex - 1) == dirProp)
107
					continue;
108
109
				for (int i = fromIndex - 1; i >= 0; i--) {
110
					dirProp = getDirProp(i);
111
					// after a L char, no need for a mark
112
					if (dirProp == L)
113
						continue;
114
115
					// digit after R or AL or AN need a mark, except for EN
116
					//   following AN, but this is a contrived case, so we
117
					//   don't check for it (and calling processOperator()
118
					//   for it will do no harm)
119
					if (dirProp == R || dirProp == AL || dirProp == AN)
120
						return fromIndex;
121
				}
122
				continue;
123
			}
124
		}
125
		return -1;
126
	}
127
128
	/**
129
	 *  This method is not supposed to be invoked directly by users of this
130
	 *  class. It may  be overridden by subclasses of this class.
131
	 */
132
	protected int processSpecial(int whichSpecial, String srcText, int operLocation) {
133
		int loc;
134
135
		switch (whichSpecial) {
136
			case 0 : /* comment (?#...) */
137
				if (operLocation < 0) {
138
					// initial state from previous line
139
					loc = 0;
140
				} else {
141
					processOperator(operLocation);
142
					// skip the opening "(?#"
143
					loc = operLocation + 3;
144
				}
145
				loc = srcText.indexOf(')', loc);
146
				if (loc < 0) {
147
					state = whichSpecial;
148
					return srcText.length();
149
				}
150
				return loc + 1;
151
			case 1 : /* named group (?<name> */
152
			case 2 : /* named group (?'name' */
153
			case 3 : /* conditional named back reference (?(name) */
154
			case 4 : /* conditional named back reference (?(<name>) */
155
			case 5 : /* conditional named back reference (?('name') */
156
			case 6 : /* named parentheses reference (?&name) */
157
				processOperator(operLocation);
158
				// no need for calling processOperator() for the following cases
159
				//   since the starting string contains a L char
160
			case 7 : /* named group (?P<name> */
161
			case 8 : /* named back reference \k<name> */
162
			case 9 : /* named back reference \k'name' */
163
			case 10 : /* named back reference \k{name} */
164
			case 11 : /* named back reference (?P=name) */
165
			case 12 : /* named back reference \g{name} */
166
			case 13 : /* subroutine call \g<name> */
167
			case 14 : /* subroutine call \g'name' */
168
			case 15 : /* named back reference recursion (?(R&name) */
169
				// skip the opening string
170
				loc = operLocation + startStrings[whichSpecial].length();
171
				// look for ending character
172
				loc = srcText.indexOf(endChars[whichSpecial], loc);
173
				if (loc < 0)
174
					return srcText.length();
175
				return loc + 1;
176
			case 16 : /* quoted sequence \Q...\E */
177
				if (operLocation < 0) {
178
					// initial state from previous line
179
					loc = 0;
180
				} else {
181
					processOperator(operLocation);
182
					// skip the opening "\Q"
183
					loc = operLocation + 2;
184
				}
185
				loc = srcText.indexOf("\\E", loc); //$NON-NLS-1$
186
				if (loc < 0) {
187
					state = whichSpecial;
188
					return srcText.length();
189
				}
190
				// set the dirProp for the "E"
191
				setDirProp(loc + 1, L);
192
				return loc + 2;
193
			case 17 : /* R, AL, AN, EN */
194
				processOperator(operLocation);
195
				return operLocation + 1;
196
197
		}
198
		// we should never get here
199
		return srcText.length();
200
	}
201
}
(-)src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpSql.java (-136 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.complexp.consumable;
12
13
import org.eclipse.equinox.bidi.complexp.IComplExpProcessor;
14
import org.eclipse.equinox.bidi.internal.complexp.ComplExpBasic;
15
16
/**
17
 *  <code>ComplExpSql</code> is a processor for complex expressions
18
 *  composed of SQL statements. Such a complex expression may span
19
 *  multiple lines.
20
 *  <p>
21
 *  In applications like an editor where parts of the text might be modified
22
 *  while other parts are not, the user may want to call
23
 *  {@link IComplExpProcessor#leanToFullText leanToFullText}
24
 *  separately on each line and save the initial state of each line (this is
25
 *  the final state of the previous line which can be retrieved using
26
 *  {@link IComplExpProcessor#getFinalState getFinalState}. If both the content
27
 *  of a line and its initial state have not changed, the user can be sure that
28
 *  the last <i>full</i> text computed for this line has not changed either.
29
 *
30
 *  @see IComplExpProcessor
31
 *  @author Matitiahu Allouche
32
 */
33
public class ComplExpSql extends ComplExpBasic {
34
	private static final byte WS = Character.DIRECTIONALITY_WHITESPACE;
35
	static final String operators = "\t!#%&()*+,-./:;<=>?|[]{}"; //$NON-NLS-1$
36
	static String lineSep;
37
38
	/**
39
	 *  Constructor for a complex expressions processor with support for
40
	 *  SQL statements.
41
	 */
42
	public ComplExpSql() {
43
		super(operators, 5);
44
		// TBD use bundle properties
45
		if (lineSep == null)
46
			lineSep = System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$
47
	}
48
49
	/**
50
	 *  This method is not supposed to be invoked directly by users of this
51
	 *  class. It may  be overridden by subclasses of this class.
52
	 */
53
	protected int indexOfSpecial(int whichSpecial, String srcText, int fromIndex) {
54
		switch (whichSpecial) {
55
			case 0 : /* space */
56
				return srcText.indexOf(" ", fromIndex); //$NON-NLS-1$
57
			case 1 : /* literal */
58
				return srcText.indexOf('\'', fromIndex);
59
			case 2 : /* delimited identifier */
60
				return srcText.indexOf('"', fromIndex);
61
			case 3 : /* slash-aster comment */
62
				return srcText.indexOf("/*", fromIndex); //$NON-NLS-1$
63
			case 4 : /* hyphen-hyphen comment */
64
				return srcText.indexOf("--", fromIndex); //$NON-NLS-1$
65
		}
66
		// we should never get here
67
		return -1;
68
	}
69
70
	/**
71
	 *  This method is not supposed to be invoked directly by users of this
72
	 *  class. It may  be overridden by subclasses of this class.
73
	 */
74
	protected int processSpecial(int whichSpecial, String srcText, int operLocation) {
75
		int loc;
76
77
		processOperator(operLocation);
78
		switch (whichSpecial) {
79
			case 0 : /* space */
80
				operLocation++;
81
				while (operLocation < srcText.length() && srcText.charAt(operLocation) == ' ') {
82
					setDirProp(operLocation, WS);
83
					operLocation++;
84
				}
85
				return operLocation;
86
			case 1 : /* literal */
87
				loc = operLocation + 1;
88
				while (true) {
89
					loc = srcText.indexOf('\'', loc);
90
					if (loc < 0) {
91
						state = whichSpecial;
92
						return srcText.length();
93
					}
94
					if ((loc + 1) < srcText.length() && srcText.charAt(loc + 1) == '\'') {
95
						loc += 2;
96
						continue;
97
					}
98
					return loc + 1;
99
				}
100
			case 2 : /* delimited identifier */
101
				loc = operLocation + 1;
102
				while (true) {
103
					loc = srcText.indexOf('"', loc);
104
					if (loc < 0)
105
						return srcText.length();
106
107
					if ((loc + 1) < srcText.length() && srcText.charAt(loc + 1) == '"') {
108
						loc += 2;
109
						continue;
110
					}
111
					return loc + 1;
112
				}
113
			case 3 : /* slash-aster comment */
114
				if (operLocation < 0)
115
					loc = 0; // initial state from previous line
116
				else
117
					loc = operLocation + 2; // skip the opening slash-aster
118
				loc = srcText.indexOf("*/", loc); //$NON-NLS-1$
119
				if (loc < 0) {
120
					state = whichSpecial;
121
					return srcText.length();
122
				}
123
				// we need to call processOperator since text may follow the
124
				//  end of comment immediately without even a space
125
				processOperator(loc);
126
				return loc + 2;
127
			case 4 : /* hyphen-hyphen comment */
128
				loc = srcText.indexOf(lineSep, operLocation + 2);
129
				if (loc < 0)
130
					return srcText.length();
131
				return loc + lineSep.length();
132
		}
133
		// we should never get here
134
		return srcText.length();
135
	}
136
}
(-)src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpSystem.java (-27 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.complexp.consumable;
12
13
import org.eclipse.equinox.bidi.internal.complexp.ComplExpSingle;
14
15
/**
16
 * Processor adapted to processing expressions with the following string format:
17
 * <pre>
18
 *  system(user)
19
 * </pre>
20
 */
21
public class ComplExpSystem extends ComplExpSingle {
22
23
	public ComplExpSystem() {
24
		super("("); //$NON-NLS-1$
25
	}
26
27
}
(-)src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpURL.java (-22 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.complexp.consumable;
12
13
import org.eclipse.equinox.bidi.internal.complexp.ComplExpBasic;
14
15
/**
16
 * Processor adapted to processing URLs. 
17
 */
18
public class ComplExpURL extends ComplExpBasic {
19
	public ComplExpURL() {
20
		super(":?#/@.[]"); //$NON-NLS-1$
21
	}
22
}
(-)src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpUnderscore.java (-27 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.complexp.consumable;
12
13
import org.eclipse.equinox.bidi.internal.complexp.ComplExpBasic;
14
15
/**
16
 * Processor adapted to processing compound names. 
17
 * This type covers names made of one or more parts, separated by underscores:
18
 * <pre>
19
 *  part1_part2_part3
20
 * </pre>
21
 */
22
public class ComplExpUnderscore extends ComplExpBasic {
23
	public ComplExpUnderscore() {
24
		super("_"); //$NON-NLS-1$
25
	}
26
27
}
(-)src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpXPath.java (-22 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.complexp.consumable;
12
13
import org.eclipse.equinox.bidi.internal.complexp.ComplExpDelims;
14
15
/**
16
 * Processor adapted to processing XPath expressions. 
17
 */
18
public class ComplExpXPath extends ComplExpDelims {
19
	public ComplExpXPath() {
20
		super(" /[]<>=!:@.|()+-*", "''\"\""); //$NON-NLS-1$ //$NON-NLS-2$
21
	}
22
}
(-)src/org/eclipse/equinox/bidi/internal/consumable/BidiComplexComma.java (+36 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.consumable;
12
13
import org.eclipse.equinox.bidi.custom.BidiComplexProcessor;
14
15
import org.eclipse.equinox.bidi.*;
16
17
/**
18
 * Processor adapted to processing comma-delimited lists, such as:
19
 * <pre>
20
 *  part1,part2,part3
21
 * </pre>
22
 */
23
public class BidiComplexComma extends BidiComplexProcessor {
24
	static final BidiComplexFeatures FEATURES = new BidiComplexFeatures(",", 0, -1, -1, false, false); //$NON-NLS-1$
25
26
	/**
27
	 *  This method retrieves the features specific to this processor.
28
	 *
29
	 *  @return features with one operator (comma), no special cases,
30
	 *          LTR direction for Arabic and Hebrew, and support for both.
31
	 */
32
	public BidiComplexFeatures init(BidiComplexHelper helper, BidiComplexEnvironment env) {
33
		return FEATURES;
34
	}
35
36
}
(-)src/org/eclipse/equinox/bidi/internal/consumable/BidiComplexEmail.java (+46 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.consumable;
12
13
import org.eclipse.equinox.bidi.internal.BidiComplexDelimsEsc;
14
15
import org.eclipse.equinox.bidi.*;
16
17
/**
18
 * Processor adapted to processing e-mail addresses.
19
 */
20
public class BidiComplexEmail extends BidiComplexDelimsEsc {
21
	static final int LTR = BidiComplexFeatures.DIR_LTR;
22
	static final int RTL = BidiComplexFeatures.DIR_RTL;
23
	static final BidiComplexFeatures MIRRORED = new BidiComplexFeatures("<>.:,;@", 2, RTL, LTR, false, false); //$NON-NLS-1$
24
	static final BidiComplexFeatures NOT_MIRRORED = new BidiComplexFeatures("<>.:,;@", 2, LTR, LTR, false, false); //$NON-NLS-1$
25
26
	/**
27
	 *  This method retrieves the features specific to this processor.
28
	 *
29
	 *  @return features with operators "<>.:,;@", 2 special cases,
30
	 *          LTR direction for Arabic when the GUI is not mirrored,
31
	 *          RTL direction for Arabic when the GUI is mirrored,
32
	 *          LTR direction for Hebrew in all cases,
33
	 *          and support for both Arabic and Hebrew.
34
	 */
35
	public BidiComplexFeatures init(BidiComplexHelper helper, BidiComplexEnvironment env) {
36
		return env.mirrored ? MIRRORED : NOT_MIRRORED;
37
	}
38
39
	/**
40
	 *  @return parentheses and quotation marks as delimiters.
41
	 */
42
	protected String getDelimiters() {
43
		return "()\"\""; //$NON-NLS-1$
44
	}
45
46
}
(-)src/org/eclipse/equinox/bidi/internal/consumable/BidiComplexFile.java (+33 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.consumable;
12
13
import org.eclipse.equinox.bidi.custom.BidiComplexProcessor;
14
15
import org.eclipse.equinox.bidi.*;
16
17
/**
18
 * Processor adapted to processing directory and file paths.
19
 */
20
public class BidiComplexFile extends BidiComplexProcessor {
21
	static final BidiComplexFeatures FEATURES = new BidiComplexFeatures(":/\\.", 0, -1, -1, false, false); //$NON-NLS-1$
22
23
	/**
24
	 *  This method retrieves the features specific to this processor.
25
	 *
26
	 *  @return features with operators ":/\.", no special cases,
27
	 *          LTR direction for Arabic and Hebrew, and support for both.
28
	 */
29
	public BidiComplexFeatures init(BidiComplexHelper helper, BidiComplexEnvironment env) {
30
		return FEATURES;
31
	}
32
33
}
(-)src/org/eclipse/equinox/bidi/internal/consumable/BidiComplexJava.java (+129 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.consumable;
12
13
import org.eclipse.equinox.bidi.custom.BidiComplexProcessor;
14
15
import org.eclipse.equinox.bidi.*;
16
17
/**
18
 *  <code>BidiComplexJava</code> is a processor for complex expressions
19
 *  composed of Java statements. Such a complex expression may span
20
 *  multiple lines.
21
 *  <p>
22
 *  In applications like an editor where parts of the text might be modified
23
 *  while other parts are not, the user may want to call
24
 *  {@link BidiComplexHelper#leanToFullText leanToFullText}
25
 *  separately on each line and save the initial state of each line (this is
26
 *  the final state of the previous line which can be retrieved using
27
 *  {@link BidiComplexHelper#getFinalState getFinalState}. If both the content
28
 *  of a line and its initial state have not changed, the user can be sure that
29
 *  the last <i>full</i> text computed for this line has not changed either.
30
 *
31
 *  @see BidiComplexHelper
32
 *
33
 *  @author Matitiahu Allouche
34
 */
35
public class BidiComplexJava extends BidiComplexProcessor {
36
	private static final byte WS = Character.DIRECTIONALITY_WHITESPACE;
37
	static final BidiComplexFeatures FEATURES = new BidiComplexFeatures("[](){}.+-<>=~!&*/%^|?:,;\t", 4, -1, -1, false, false); //$NON-NLS-1$
38
	static final String lineSep = BidiComplexEnvironment.getLineSep();
39
40
	/**
41
	 *  This method retrieves the features specific to this processor.
42
	 *
43
	 *  @return features with operators "[](){}.+-<>=~!&/*%^|?:,;\t",
44
	 *          4 special cases, LTR direction for Arabic and Hebrew,
45
	 *          and support for both.
46
	 */
47
	public BidiComplexFeatures init(BidiComplexHelper helper, BidiComplexEnvironment env) {
48
		return FEATURES;
49
	}
50
51
	/**
52
	     *  This method looks for occurrences of 4 special strings:
53
	     *  <ol>
54
	     *    <li>spaces</li>
55
	     *    <li>literals starting with quotation mark</li>
56
	     *    <li>comments starting with slash-asterisk</li>
57
	     *    <li>comments starting with slash-slash</li>
58
	     *  </ol>
59
	     */
60
	public int indexOfSpecial(BidiComplexHelper helper, int caseNumber, String srcText, int fromIndex) {
61
		switch (caseNumber) {
62
			case 0 : /* space */
63
				return srcText.indexOf(' ', fromIndex);
64
			case 1 : /* literal */
65
				return srcText.indexOf('"', fromIndex);
66
			case 2 : /* slash-aster comment */
67
				return srcText.indexOf("/*", fromIndex); //$NON-NLS-1$
68
			case 3 : /* slash-slash comment */
69
				return srcText.indexOf("//", fromIndex); //$NON-NLS-1$
70
		}
71
		// we should never get here
72
		return -1;
73
	}
74
75
	/**
76
	 *  This method processes the 4 special cases as follows.
77
	     *  <ol>
78
	     *    <li>skip the run of spaces</li>
79
	     *    <li>look for a matching quotation mark and skip until after it</li>
80
	     *    <li>skip until after the closing asterisk-slash</li>
81
	     *    <li>skip until after a line separator</li>
82
	     *  </ol>
83
	 */
84
	public int processSpecial(BidiComplexHelper helper, int caseNumber, String srcText, int operLocation) {
85
		int location, counter, i;
86
87
		helper.processOperator(operLocation);
88
		switch (caseNumber) {
89
			case 0 : /* space */
90
				operLocation++;
91
				while (operLocation < srcText.length() && srcText.charAt(operLocation) == ' ') {
92
					helper.setDirProp(operLocation, WS);
93
					operLocation++;
94
				}
95
				return operLocation;
96
			case 1 : /* literal */
97
				location = operLocation + 1;
98
				while (true) {
99
					location = srcText.indexOf('"', location);
100
					if (location < 0)
101
						return srcText.length();
102
					for (counter = 0, i = location - 1; srcText.charAt(i) == '\\'; i--) {
103
						counter++;
104
					}
105
					location++;
106
					if ((counter & 1) == 0)
107
						return location;
108
				}
109
			case 2 : /* slash-aster comment */
110
				if (operLocation < 0)
111
					location = 0; // initial state from previous line
112
				else
113
					location = operLocation + 2; // skip the opening slash-aster
114
				location = srcText.indexOf("*/", location); //$NON-NLS-1$
115
				if (location < 0) {
116
					helper.setFinalState(2);
117
					return srcText.length();
118
				}
119
				return location + 2;
120
			case 3 : /* slash-slash comment */
121
				location = srcText.indexOf(lineSep, operLocation + 2);
122
				if (location < 0)
123
					return srcText.length();
124
				return location + lineSep.length();
125
		}
126
		// we should never get here
127
		return srcText.length();
128
	}
129
}
(-)src/org/eclipse/equinox/bidi/internal/consumable/BidiComplexMath.java (+35 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.consumable;
12
13
import org.eclipse.equinox.bidi.custom.BidiComplexProcessor;
14
15
import org.eclipse.equinox.bidi.*;
16
17
/**
18
 * Processor adapted to processing arithmetic expressions with right-to-left
19
 * base direction.
20
 */
21
public class BidiComplexMath extends BidiComplexProcessor {
22
	static final int RTL = BidiComplexFeatures.DIR_RTL;
23
	static final BidiComplexFeatures FEATURES = new BidiComplexFeatures("+-/*()=", 0, RTL, RTL, false, false); //$NON-NLS-1$
24
25
	/**
26
	 *  This method retrieves the features specific to this processor.
27
	 *
28
	 *  @return features with operators "+-/*()=", no special cases,
29
	 *          RTL direction for Arabic and Hebrew, and support for both.
30
	 */
31
	public BidiComplexFeatures init(BidiComplexHelper helper, BidiComplexEnvironment env) {
32
		return FEATURES;
33
	}
34
35
}
(-)src/org/eclipse/equinox/bidi/internal/consumable/BidiComplexProperty.java (+37 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.consumable;
12
13
import org.eclipse.equinox.bidi.internal.BidiComplexSingle;
14
15
import org.eclipse.equinox.bidi.*;
16
17
/**
18
 * Processor adapted to processing property file statements.
19
 * It expects the following string format:
20
 * <pre>
21
 *  name=value
22
 * </pre>
23
 */
24
public class BidiComplexProperty extends BidiComplexSingle {
25
	static final BidiComplexFeatures FEATURES = new BidiComplexFeatures("=", 1, -1, -1, false, false); //$NON-NLS-1$
26
27
	/**
28
	 *  This method retrieves the features specific to this processor.
29
	 *
30
	 *  @return features with one operator (equal sign), 1 special case,
31
	 *          LTR direction for Arabic and Hebrew, and support for both.
32
	 */
33
	public BidiComplexFeatures init(BidiComplexHelper helper, BidiComplexEnvironment env) {
34
		return FEATURES;
35
	}
36
37
}
(-)src/org/eclipse/equinox/bidi/internal/consumable/BidiComplexRegex.java (+217 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.consumable;
12
13
import org.eclipse.equinox.bidi.custom.BidiComplexProcessor;
14
15
import org.eclipse.equinox.bidi.*;
16
17
/**
18
 *  <code>BidiComplexRegex</code> is a processor for regular expressions.
19
 *  Such expressions may span multiple lines.
20
 *  <p>
21
 *  In applications like an editor where parts of the text might be modified
22
 *  while other parts are not, the user may want to call
23
 *  {@link BidiComplexHelper#leanToFullText leanToFullText}
24
 *  separately on each line and save the initial state of each line (this is
25
 *  the final state of the previous line which can be retrieved using
26
 *  {@link BidiComplexHelper#getFinalState getFinalState}. If both the content
27
 *  of a line and its initial state have not changed, the user can be sure that
28
 *  the last <i>full</i> text computed for this line has not changed either.
29
 *
30
 *  @see BidiComplexHelper
31
 *
32
 *  @author Matitiahu Allouche
33
 */
34
public class BidiComplexRegex extends BidiComplexProcessor {
35
	static final String[] startStrings = {"(?#", /*  0 *//* comment (?#...) *///$NON-NLS-1$
36
			"(?<", /*  1 *//* named group (?<name> *///$NON-NLS-1$
37
			"(?'", /*  2 *//* named group (?'name' *///$NON-NLS-1$
38
			"(?(<", /*  3 *//* conditional named back reference (?(<name>) *///$NON-NLS-1$
39
			"(?('", /*  4 *//* conditional named back reference (?('name') *///$NON-NLS-1$
40
			"(?(", /*  5 *//* conditional named back reference (?(name) *///$NON-NLS-1$
41
			"(?&", /*  6 *//* named parentheses reference (?&name) *///$NON-NLS-1$
42
			"(?P<", /*  7 *//* named group (?P<name> *///$NON-NLS-1$
43
			"\\k<", /*  8 *//* named back reference \k<name> *///$NON-NLS-1$
44
			"\\k'", /*  9 *//* named back reference \k'name' *///$NON-NLS-1$
45
			"\\k{", /* 10 *//* named back reference \k{name} *///$NON-NLS-1$
46
			"(?P=", /* 11 *//* named back reference (?P=name) *///$NON-NLS-1$
47
			"\\g{", /* 12 *//* named back reference \g{name} *///$NON-NLS-1$
48
			"\\g<", /* 13 *//* subroutine call \g<name> *///$NON-NLS-1$
49
			"\\g'", /* 14 *//* subroutine call \g'name' *///$NON-NLS-1$
50
			"(?(R&", /* 15 *//* named back reference recursion (?(R&name) *///$NON-NLS-1$
51
			"\\Q" /* 16 *//* quoted sequence \Q...\E *///$NON-NLS-1$
52
	};
53
	static final char[] endChars = {
54
			// 0    1     2    3    4    5    6    7    8     9   10   11   12   13    14   15
55
			')', '>', '\'', ')', ')', ')', ')', '>', '>', '\'', '}', ')', '}', '>', '\'', ')'};
56
	static final int numberOfStrings = startStrings.length;
57
	static final int maxSpecial = numberOfStrings + 1;
58
	static final BidiComplexFeatures FEATURES = new BidiComplexFeatures(null, maxSpecial, -1, -1, false, false);
59
	static final byte L = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
60
	static final byte R = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
61
	static final byte AL = Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC;
62
	static final byte AN = Character.DIRECTIONALITY_ARABIC_NUMBER;
63
	static final byte EN = Character.DIRECTIONALITY_EUROPEAN_NUMBER;
64
65
	/**
66
	 *  This method retrieves the features specific to this processor.
67
	 *
68
	 *  @return features with no operators , special cases for each kind of
69
	 *          regular expression syntactic string,
70
	 *          LTR direction for Arabic and Hebrew, and support for both.
71
	 */
72
	public BidiComplexFeatures init(BidiComplexHelper helper, BidiComplexEnvironment env) {
73
		return FEATURES;
74
	}
75
76
	/**
77
	 *  This method locates occurrences of the syntactic strings and of
78
	 *  R, AL, EN, AN characters.
79
	 */
80
	public int indexOfSpecial(BidiComplexHelper helper, int caseNumber, String srcText, int fromIndex) {
81
		// In this method, L, R, AL, AN and EN represent bidi categories
82
		// as defined in the Unicode Bidirectional Algorithm
83
		// ( http://www.unicode.org/reports/tr9/ ).
84
		// L  represents the category Left to Right character.
85
		// R  represents the category Right to Left character.
86
		// AL represents the category Arabic Letter.
87
		// AN represents the category Arabic Number.
88
		// EN  represents the category European Number.
89
		byte dirProp;
90
91
		if (caseNumber < numberOfStrings) {
92
			/*  0 *//* comment (?#...) */
93
			/*  1 *//* named group (?<name> */
94
			/*  2 *//* named group (?'name' */
95
			/*  3 *//* conditional named back reference (?(name) */
96
			/*  4 *//* conditional named back reference (?(<name>) */
97
			/*  5 *//* conditional named back reference (?('name') */
98
			/*  6 *//* named parentheses reference (?&name) */
99
			/*  7 *//* named group (?P<name> */
100
			/*  8 *//* named back reference \k<name> */
101
			/*  9 *//* named back reference \k'name' */
102
			/* 10 *//* named back reference \k{name} */
103
			/* 11 *//* named back reference (?P=name) */
104
			/* 12 *//* named back reference \g{name} */
105
			/* 13 *//* subroutine call \g<name> */
106
			/* 14 *//* subroutine call \g'name' */
107
			/* 15 *//* named back reference recursion (?(R&name) */
108
			/* 16 *//* quoted sequence \Q...\E */
109
			return srcText.indexOf(startStrings[caseNumber], fromIndex);
110
		}
111
		// there never is a need for a mark before the first char
112
		if (fromIndex <= 0)
113
			fromIndex = 1;
114
		// look for R, AL, AN, EN which are potentially needing a mark
115
		for (; fromIndex < srcText.length(); fromIndex++) {
116
			dirProp = helper.getDirProp(fromIndex);
117
			// R and AL will always be examined using processOperator()
118
			if (dirProp == R || dirProp == AL)
119
				return fromIndex;
120
121
			if (dirProp == EN || dirProp == AN) {
122
				// no need for a mark after the first digit in a number
123
				if (helper.getDirProp(fromIndex - 1) == dirProp)
124
					continue;
125
126
				for (int i = fromIndex - 1; i >= 0; i--) {
127
					dirProp = helper.getDirProp(i);
128
					// after a L char, no need for a mark
129
					if (dirProp == L)
130
						continue;
131
132
					// digit after R or AL or AN need a mark, except for EN
133
					//   following AN, but this is a contrived case, so we
134
					//   don't check for it (and calling processOperator()
135
					//   for it will do no harm)
136
					if (dirProp == R || dirProp == AL || dirProp == AN)
137
						return fromIndex;
138
				}
139
				continue;
140
			}
141
		}
142
		return -1;
143
	}
144
145
	/**
146
	 *  This method process the special cases.
147
	 */
148
	public int processSpecial(BidiComplexHelper helper, int caseNumber, String srcText, int operLocation) {
149
		int location;
150
151
		switch (caseNumber) {
152
			case 0 : /* comment (?#...) */
153
				if (operLocation < 0) {
154
					// initial state from previous line
155
					location = 0;
156
				} else {
157
					helper.processOperator(operLocation);
158
					// skip the opening "(?#"
159
					location = operLocation + 3;
160
				}
161
				location = srcText.indexOf(')', location);
162
				if (location < 0) {
163
					helper.setFinalState(caseNumber);
164
					return srcText.length();
165
				}
166
				return location + 1;
167
			case 1 : /* named group (?<name> */
168
			case 2 : /* named group (?'name' */
169
			case 3 : /* conditional named back reference (?(name) */
170
			case 4 : /* conditional named back reference (?(<name>) */
171
			case 5 : /* conditional named back reference (?('name') */
172
			case 6 : /* named parentheses reference (?&name) */
173
				helper.processOperator(operLocation);
174
				// no need for calling processOperator() for the following cases
175
				//   since the starting string contains a L char
176
			case 7 : /* named group (?P<name> */
177
			case 8 : /* named back reference \k<name> */
178
			case 9 : /* named back reference \k'name' */
179
			case 10 : /* named back reference \k{name} */
180
			case 11 : /* named back reference (?P=name) */
181
			case 12 : /* named back reference \g{name} */
182
			case 13 : /* subroutine call \g<name> */
183
			case 14 : /* subroutine call \g'name' */
184
			case 15 : /* named back reference recursion (?(R&name) */
185
				// skip the opening string
186
				location = operLocation + startStrings[caseNumber].length();
187
				// look for ending character
188
				location = srcText.indexOf(endChars[caseNumber], location);
189
				if (location < 0)
190
					return srcText.length();
191
				return location + 1;
192
			case 16 : /* quoted sequence \Q...\E */
193
				if (operLocation < 0) {
194
					// initial state from previous line
195
					location = 0;
196
				} else {
197
					helper.processOperator(operLocation);
198
					// skip the opening "\Q"
199
					location = operLocation + 2;
200
				}
201
				location = srcText.indexOf("\\E", location); //$NON-NLS-1$
202
				if (location < 0) {
203
					helper.setFinalState(caseNumber);
204
					return srcText.length();
205
				}
206
				// set the dirProp for the "E" to L (Left to Right character)
207
				helper.setDirProp(location + 1, L);
208
				return location + 2;
209
			case 17 : /* R, AL, AN, EN */
210
				helper.processOperator(operLocation);
211
				return operLocation + 1;
212
213
		}
214
		// we should never get here
215
		return srcText.length();
216
	}
217
}
(-)src/org/eclipse/equinox/bidi/internal/consumable/BidiComplexSql.java (+150 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.consumable;
12
13
import org.eclipse.equinox.bidi.custom.BidiComplexProcessor;
14
15
import org.eclipse.equinox.bidi.*;
16
17
/**
18
 *  <code>BidiComplexSql</code> is a processor for complex expressions
19
 *  composed of SQL statements. Such a complex expression may span
20
 *  multiple lines.
21
 *  <p>
22
 *  In applications like an editor where parts of the text might be modified
23
 *  while other parts are not, the user may want to call
24
 *  {@link BidiComplexHelper#leanToFullText leanToFullText}
25
 *  separately on each line and save the initial state of each line (this is
26
 *  the final state of the previous line which can be retrieved using
27
 *  {@link BidiComplexHelper#getFinalState getFinalState}. If both the content
28
 *  of a line and its initial state have not changed, the user can be sure that
29
 *  the last <i>full</i> text computed for this line has not changed either.
30
 *
31
 *  @see BidiComplexHelper
32
 *
33
 *  @author Matitiahu Allouche
34
 */
35
public class BidiComplexSql extends BidiComplexProcessor {
36
	private static final byte WS = Character.DIRECTIONALITY_WHITESPACE;
37
	static final String operators = "\t!#%&()*+,-./:;<=>?|[]{}"; //$NON-NLS-1$
38
	static final BidiComplexFeatures FEATURES = new BidiComplexFeatures(operators, 5, -1, -1, false, false);
39
	static final String lineSep = BidiComplexEnvironment.getLineSep();
40
41
	/**
42
	 *  This method retrieves the features specific to this processor.
43
	 *
44
	 *  @return features with operators "\t!#%&()*+,-./:;<=>?|[]{}", 5 special cases,
45
	 *          LTR direction for Arabic and Hebrew, and support for both.
46
	 */
47
	public BidiComplexFeatures init(BidiComplexHelper helper, BidiComplexEnvironment env) {
48
		return FEATURES;
49
	}
50
51
	/**
52
	  *  This method looks for occurrences of 5 special strings:
53
	  *  <ol>
54
	  *    <li>spaces</li>
55
	  *    <li>literals starting with apostrophe</li>
56
	  *    <li>identifiers starting with quotation mark</li>
57
	  *    <li>comments starting with slash-asterisk</li>
58
	  *    <li>comments starting with hyphen-hyphen</li>
59
	  *  </ol>
60
	  */
61
	public int indexOfSpecial(BidiComplexHelper helper, int caseNumber, String srcText, int fromIndex) {
62
		switch (caseNumber) {
63
			case 0 : /* space */
64
				return srcText.indexOf(" ", fromIndex); //$NON-NLS-1$
65
			case 1 : /* literal */
66
				return srcText.indexOf('\'', fromIndex);
67
			case 2 : /* delimited identifier */
68
				return srcText.indexOf('"', fromIndex);
69
			case 3 : /* slash-aster comment */
70
				return srcText.indexOf("/*", fromIndex); //$NON-NLS-1$
71
			case 4 : /* hyphen-hyphen comment */
72
				return srcText.indexOf("--", fromIndex); //$NON-NLS-1$
73
		}
74
		// we should never get here
75
		return -1;
76
	}
77
78
	/**
79
	 *  This method processes the 5 special cases as follows.
80
	     *  <ol>
81
	     *    <li>skip the run of spaces</li>
82
	     *    <li>look for a matching apostrophe and skip until after it</li>
83
	     *    <li>look for a matching quotation mark and skip until after it</li>
84
	     *    <li>skip until after the closing asterisk-slash</li>
85
	     *    <li>skip until after a line separator</li>
86
	     *  </ol>
87
	 */
88
	public int processSpecial(BidiComplexHelper helper, int caseNumber, String srcText, int operLocation) {
89
		int location;
90
91
		helper.processOperator(operLocation);
92
		switch (caseNumber) {
93
			case 0 : /* space */
94
				operLocation++;
95
				while (operLocation < srcText.length() && srcText.charAt(operLocation) == ' ') {
96
					helper.setDirProp(operLocation, WS);
97
					operLocation++;
98
				}
99
				return operLocation;
100
			case 1 : /* literal */
101
				location = operLocation + 1;
102
				while (true) {
103
					location = srcText.indexOf('\'', location);
104
					if (location < 0) {
105
						helper.setFinalState(caseNumber);
106
						return srcText.length();
107
					}
108
					if ((location + 1) < srcText.length() && srcText.charAt(location + 1) == '\'') {
109
						location += 2;
110
						continue;
111
					}
112
					return location + 1;
113
				}
114
			case 2 : /* delimited identifier */
115
				location = operLocation + 1;
116
				while (true) {
117
					location = srcText.indexOf('"', location);
118
					if (location < 0)
119
						return srcText.length();
120
121
					if ((location + 1) < srcText.length() && srcText.charAt(location + 1) == '"') {
122
						location += 2;
123
						continue;
124
					}
125
					return location + 1;
126
				}
127
			case 3 : /* slash-aster comment */
128
				if (operLocation < 0)
129
					location = 0; // initial state from previous line
130
				else
131
					location = operLocation + 2; // skip the opening slash-aster
132
				location = srcText.indexOf("*/", location); //$NON-NLS-1$
133
				if (location < 0) {
134
					helper.setFinalState(caseNumber);
135
					return srcText.length();
136
				}
137
				// we need to call processOperator since text may follow the
138
				//  end of comment immediately without even a space
139
				helper.processOperator(location);
140
				return location + 2;
141
			case 4 : /* hyphen-hyphen comment */
142
				location = srcText.indexOf(lineSep, operLocation + 2);
143
				if (location < 0)
144
					return srcText.length();
145
				return location + lineSep.length();
146
		}
147
		// we should never get here
148
		return srcText.length();
149
	}
150
}
(-)src/org/eclipse/equinox/bidi/internal/consumable/BidiComplexSystem.java (+36 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.consumable;
12
13
import org.eclipse.equinox.bidi.internal.BidiComplexSingle;
14
15
import org.eclipse.equinox.bidi.*;
16
17
/**
18
 * Processor adapted to processing expressions with the following string format:
19
 * <pre>
20
 *  system(user)
21
 * </pre>
22
 */
23
public class BidiComplexSystem extends BidiComplexSingle {
24
	static final BidiComplexFeatures FEATURES = new BidiComplexFeatures("(", 0, -1, -1, false, false); //$NON-NLS-1$
25
26
	/**
27
	 *  This method retrieves the features specific to this processor.
28
	 *
29
	 *  @return features with one operator (opening parhenthesis),
30
	 *          no special cases, LTR direction for Arabic and Hebrew,
31
	 *          and support for both.
32
	 */
33
	public BidiComplexFeatures init(BidiComplexHelper helper, BidiComplexEnvironment env) {
34
		return FEATURES;
35
	}
36
}
(-)src/org/eclipse/equinox/bidi/internal/consumable/BidiComplexURL.java (+34 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.consumable;
12
13
import org.eclipse.equinox.bidi.custom.BidiComplexProcessor;
14
15
import org.eclipse.equinox.bidi.*;
16
17
/**
18
 * Processor adapted to processing URLs.
19
 */
20
public class BidiComplexURL extends BidiComplexProcessor {
21
	static final BidiComplexFeatures FEATURES = new BidiComplexFeatures(":?#/@.[]", 0, -1, -1, false, false); //$NON-NLS-1$
22
23
	/**
24
	 *  This method retrieves the features specific to this processor.
25
	 *
26
	 *  @return features with operators ":?#/@.[]",
27
	 *          no special cases, LTR direction for Arabic and Hebrew,
28
	 *          and support for both.
29
	 */
30
	public BidiComplexFeatures init(BidiComplexHelper helper, BidiComplexEnvironment env) {
31
		return FEATURES;
32
	}
33
34
}
(-)src/org/eclipse/equinox/bidi/internal/consumable/BidiComplexUnderscore.java (+38 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.consumable;
12
13
import org.eclipse.equinox.bidi.custom.BidiComplexProcessor;
14
15
import org.eclipse.equinox.bidi.*;
16
17
/**
18
 * Processor adapted to processing compound names.
19
 * This type covers names made of one or more parts, separated by underscores:
20
 * <pre>
21
 *  part1_part2_part3
22
 * </pre>
23
 */
24
public class BidiComplexUnderscore extends BidiComplexProcessor {
25
	static final BidiComplexFeatures FEATURES = new BidiComplexFeatures("_", 0, -1, -1, false, false); //$NON-NLS-1$
26
27
	/**
28
	 *  This method retrieves the features specific to this processor.
29
	 *
30
	 *  @return features with one operator (underscore),
31
	 *          no special cases, LTR direction for Arabic and Hebrew,
32
	 *          and support for both.
33
	 */
34
	public BidiComplexFeatures init(BidiComplexHelper helper, BidiComplexEnvironment env) {
35
		return FEATURES;
36
	}
37
38
}
(-)src/org/eclipse/equinox/bidi/internal/consumable/BidiComplexXPath.java (+41 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
11
package org.eclipse.equinox.bidi.internal.consumable;
12
13
import org.eclipse.equinox.bidi.internal.BidiComplexDelims;
14
15
import org.eclipse.equinox.bidi.*;
16
17
/**
18
 * Processor adapted to processing XPath expressions.
19
 */
20
public class BidiComplexXPath extends BidiComplexDelims {
21
	static final BidiComplexFeatures FEATURES = new BidiComplexFeatures(" /[]<>=!:@.|()+-*", 2, -1, -1, false, false); //$NON-NLS-1$
22
23
	/**
24
	 *  This method retrieves the features specific to this processor.
25
	 *
26
	 *  @return features with operators " /[]<>=!:@.|()+-*",
27
	 *          2 special cases, LTR direction for Arabic and Hebrew,
28
	 *          and support for both.
29
	 */
30
	public BidiComplexFeatures init(BidiComplexHelper helper, BidiComplexEnvironment env) {
31
		return FEATURES;
32
	}
33
34
	/**
35
	 *  @return parentheses apostrophe and quotation mark as delimiters.
36
	 */
37
	protected String getDelimiters() {
38
		return "''\"\""; //$NON-NLS-1$
39
	}
40
41
}
(-)src/org/eclipse/equinox/bidi/internal/consumable/package.html (+15 lines)
Added Link Here
1
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
2
<html>
3
<head>
4
<META name="Author" content="Matitiahu Allouche">
5
</head>
6
<body bgcolor="white">
7
8
This package provides implementations for complex expression processors.
9
More specifically, it provides implementations for all the
10
complex expression processors whose types are listed in
11
{@link <a href="..\..\IBidiComplexExpressionTypes.html">
12
IBidiComplexExpressionTypes</a>}.
13
14
</body>
15
</html>
(-)src/org/eclipse/equinox/bidi/internal/package.html (+12 lines)
Added Link Here
1
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
2
<html>
3
<head>
4
<META name="Author" content="Matitiahu Allouche">
5
</head>
6
<body bgcolor="white">
7
8
This package provides internal tools for the implementation
9
of complex expression processors.
10
11
</body>
12
</html>
(-)src/org/eclipse/equinox/bidi/package.html (+180 lines)
Added Link Here
1
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
2
<html>
3
<head>
4
<META name="Author" content="Matitiahu Allouche">
5
</head>
6
<body bgcolor="white">
7
8
This package provides interfaces and classes for
9
processing complex expressions.
10
11
12
<h2>Introduction to Complex Expressions</h2>
13
<p>
14
Bidirectional text offers interesting challenges to presentation systems.
15
For plain text, the Unicode Bidirectional Algorithm
16
(<a href="http://www.unicode.org/reports/tr9/">UBA</a>)
17
generally specifies satisfactorily how to reorder bidirectional text for
18
display. This algorithm is implemented in Java's presentation system.</p>
19
<p>
20
However, all bidirectional text is not necessarily plain text. There
21
are also instances of text structured to follow a given syntax, which
22
should be reflected in the display order. The general algorithm, which
23
has no awareness of these special cases, often gives incorrect results
24
when displaying such structured text.</p>
25
<p>
26
The general idea in handling complex expressions is to add directional
27
formatting characters at proper locations in the text to supplement the
28
standard algorithm, so that the final result is correctly displayed
29
using the UBA.
30
A class which handles complex expressions is thus essentially a
31
transformation engine which receives text without directional formatting
32
characters as input and produces as output the same text with added
33
directional formatting characters, hopefully in the minimum quantity
34
which is sufficient to ensure correct display, considering the type of
35
complex expression involved.</p>
36
<p>
37
In this package, text without directional formatting characters is
38
called <b><i>lean</i></b> text while the text with added directional
39
formatting characters is called <b><i>full</i></b> text.</p>
40
<p>
41
The class {@link
42
<a href="BidiComplexHelper.html"><b>BidiComplexHelper</b></a>}
43
is the main tool for processing complex expressions.  It facilitates
44
handling several types of complex expressions, each type being handled
45
by a specific
46
{@link <a href="custom\IBidiComplexProcessor.html"><b><i>processor</i></b></a>} :</p>
47
<ul>
48
  <li>property (name=value)</li>
49
  <li>compound name (xxx_yy_zzzz)</li>
50
  <li>comma delimited list</li>
51
  <li>system(user)</li>
52
  <li>directory and file path</li>
53
  <li>e-mail address</li>
54
  <li>URL</li>
55
  <li>regular expression</li>
56
  <li>Xpath</li>
57
  <li>Java code</li>
58
  <li>SQL statements</li>
59
  <li>RTL arithmetic expressions</li>
60
</ul>
61
<p>
62
Other classes and one interface in this package may be used to
63
complement and facilitate the action of
64
{@link <a href="BidiComplexHelper.html">BidiComplexHelper</a>}:
65
<ul>
66
  <li>{@link <a href="BidiComplexEnvironment.html">BidiComplexEnvironment</a>}
67
  which regroups details about the environment</li>
68
  <li>{@link <a href="BidiComplexFeatures.html">BidiComplexFeatures</a>}
69
      which allows viewing and manipulating some factors which affect
70
      a complex expression processor's behavior</li>
71
  <li>{@link <a href="BidiComplexUtil.html">BidiComplexUtil</a>}
72
      provides a number of convenience methods to process some common types of
73
      complex expressions.  When using methods in this class, there is no need
74
      to use other classes of this package.  However, the other classes allow
75
      more precise control and possibly better performance.</li>
76
  <li>{@link <a href="IBidiComplexExpressionTypes.html">IBidiComplexExpressionTypes</a>}
77
      is an interface which contains only literals identifying the various types
78
      of complex expressions currently supported.</li>
79
  <li>{@link <a href="BidiComplexStringRecord.html">BidiComplexStringRecord</a>}
80
      which allows to record strings which are complex expressions with their
81
      type, so that another module can check if a given string has been recorded
82
      as a complex expression and retrieve its type.</li>
83
</ul>
84
<p>
85
{@link <a href="BidiComplexHelper.html">BidiComplexHelper</a>} and the
86
other classes and interface mentioned above are intended for users who
87
need to process complex expressions for which there already exist
88
processors.
89
<p>
90
Developers who want to develop new processors to support types of complex
91
expressions not currently supported can use the following components of the
92
package {@link <a href="custom\package-summary.html">
93
org.eclipse.equinox.bidi.custom</a>}:
94
<ul>
95
  <li>{@link <a href="custom\IBidiComplexProcessor.html">IBidiComplexProcessor</a>}
96
      is an interface specifying which methods a processor must provide.</li>
97
  <li>{@link <a href="custom\BidiComplexProcessor.html">BidiComplexProcessor</a>}
98
      is a generic processor which can be used as superclass for specific
99
      processors.</li>
100
  <li>{@link <a href="custom\BidiComplexStringProcessor.html">BidiComplexStringProcessor</a>}
101
      is a class which allows retrieval of the defined processor types and of the
102
      corresponding processors.</li>
103
</ul>
104
<p>
105
There are two other packages associated with the current one:
106
<ul>
107
  <li>{@link <a href="internal\package-summary.html">
108
      org.eclipse.equinox.bidi.internal</a>}</li>
109
  <li>{@link <a href="internal\consumable\package-summary.html">
110
       org.eclipse.equinox.bidi.internal.consumable</a>}</li>
111
</ul>
112
The tools in the first package can serve as example of how to develop
113
processors for currently unsupported types of complex expressions.<br>
114
The latter package contains classes for the processors implementing
115
the currently supported types of complex expressions.
116
<p>
117
However, users wishing to process the currently supported types of
118
complex expressions typically don't need to interact with these
119
two packages.
120
121
<p>&nbsp;</p>
122
123
<h2>Abbreviations used in the documentation of this package</h2>
124
125
<dl>
126
<dt><b>UBA</b><dd>Unicode Bidirectional Algorithm
127
128
<dt><b>Bidi</b><dd>Bidirectional
129
130
<dt><b>GUI</b><dd>Graphical User Interface
131
132
<dt><b>UI</b><dd>User Interface
133
134
<dt><b>LTR</b><dd>Left to Right
135
136
<dt><b>RTL</b><dd>Right to Left
137
138
<dt><b>LRM</b><dd>Left-to-Right Mark
139
140
<dt><b>RLM</b><dd>Right-to-Left Mark
141
142
<dt><b>LRE</b><dd>Left-to-Right Embedding
143
144
<dt><b>RLE</b><dd>Right-to-Left Embedding
145
146
<dt><b>PDF</b><dd>Pop Directional Formatting
147
</dl>
148
149
<p>&nbsp;</p>
150
151
<h2>Known Limitations</h2>
152
153
<p>The proposed solution is making extensive usage of LRM, RLM, LRE, RLE
154
and PDF directional controls which are invisible but affect the way bidi
155
text is displayed. The following related key points merit special
156
attention:</p>
157
158
<ul>
159
<li>Implementations of the UBA on various platforms (e.g., Windows and
160
Linux) are very similar but nevertheless have known differences. Those
161
differences are minor and will not have a visible effect in most cases.
162
However there might be cases in which the same bidi text on two
163
platforms might look different. These differences will surface in Java
164
applications when they use the platform visual components for their UI
165
(e.g., AWT, SWT).</li>
166
167
<li>It is assumed that the presentation engine supports LRE, RLE and
168
PDF directional formatting characters.</li>
169
170
<li>Because some presentation engines are not strictly conformant to the
171
UBA, the implementation of complex expressions in this package adds LRM
172
or RLM characters in association with LRE, RLE or PDF in cases where
173
this would not be needed if the presentation engine was fully conformant
174
to the UBA. Such added marks will not have harmful effects on
175
conformant presentation engines and will help less conformant engines to
176
achieve the desired presentation.</li>
177
</ul>
178
179
</body>
180
</html>

Return to bug 183164