1919
2020import org .eclipse .jface .fieldassist .ControlDecoration ;
2121import org .eclipse .jface .fieldassist .FieldDecorationRegistry ;
22+ import org .eclipse .swt .graphics .GC ;
2223import org .eclipse .swt .graphics .Image ;
24+ import org .eclipse .swt .widgets .Control ;
2325
2426/**
2527 * This class contains methods to validate and decorate search fields.
@@ -41,11 +43,10 @@ private SearchDecoration() {
4143 * the validation.
4244 */
4345 public static boolean validateRegex (String regex , ControlDecoration targetDecoration ) {
44- String errorMessage = getValidationError (regex );
46+ String errorMessage = getValidationError (regex , targetDecoration . getControl () );
4547 if (errorMessage .isEmpty ()) {
4648 targetDecoration .hide ();
4749 return true ;
48-
4950 }
5051
5152 Image decorationImage = FieldDecorationRegistry .getDefault ()
@@ -62,21 +63,54 @@ public static boolean validateRegex(String regex, ControlDecoration targetDecora
6263 * @return The appropriate error message if the regex is invalid or an empty
6364 * string if the regex is valid.
6465 */
65- private static String getValidationError (String regex ) {
66+ private static String getValidationError (String regex , Control targetControl ) {
6667 try {
6768 Pattern .compile (regex );
6869 return "" ; //$NON-NLS-1$
6970 } catch (PatternSyntaxException e ) {
70- String message = e .getLocalizedMessage ();
71+ return buildValidationErrorString (e , targetControl );
72+ }
73+ }
74+
75+ private static String buildValidationErrorString (PatternSyntaxException e , Control targetControl ) {
76+ String description = e .getDescription ();
77+ int errorIndex = e .getIndex ();
78+
79+ if (errorIndex == -1 ) {
80+ return description ;
81+ }
82+
83+ GC gc = new GC (targetControl );
84+ String pattern = e .getPattern ();
7185
72- // Only preserve the first line of the original error message.
73- int i = 0 ;
74- while (i < message .length () && "\n \r " .indexOf (message .charAt (i )) == -1 ) { //$NON-NLS-1$
75- i ++;
76- }
86+ StringBuilder validationErrorMessage = new StringBuilder ();
7787
78- return message .substring (0 , i );
88+ validationErrorMessage .append (description );
89+ validationErrorMessage .append (" at index " ).append (errorIndex ).append (System .lineSeparator ()); //$NON-NLS-1$
90+ validationErrorMessage .append (pattern ).append (System .lineSeparator ());
91+
92+ String stringToIndexString = pattern .substring (0 , errorIndex + 1 );
93+ String hairSpace = "\u200A " ; //$NON-NLS-1$
94+ int hairSpaceWidth = gc .stringExtent (hairSpace ).x ;
95+
96+ int stringToIndex = gc .stringExtent (stringToIndexString ).x ;
97+ String lastCharacter = stringToIndexString .substring (stringToIndexString .length () - 1 );
98+
99+ int widthLastChar = gc .stringExtent (lastCharacter ).x ;
100+ int upWidth = gc .stringExtent ("^" ).x ; //$NON-NLS-1$
101+
102+ double howFar = stringToIndex - widthLastChar / 2 - upWidth / 2 ;
103+ int currentWidth = 0 ;
104+
105+ while (currentWidth < howFar ) {
106+ currentWidth += hairSpaceWidth ;
107+ validationErrorMessage .append (hairSpace );
79108 }
109+
110+ validationErrorMessage .append ("^" ); //$NON-NLS-1$
111+ gc .dispose ();
112+
113+ return validationErrorMessage .toString ();
80114 }
81115
82116}
0 commit comments