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

Collapse All | Expand All

(-)src/org/eclipse/core/internal/databinding/BindingMessages.java (-5 / +16 lines)
Lines 18-24 Link Here
18
18
19
/**
19
/**
20
 * @since 1.0
20
 * @since 1.0
21
 *
21
 * 
22
 */
22
 */
23
public class BindingMessages {
23
public class BindingMessages {
24
24
Lines 112-118 Link Here
112
	 * Returns the resource object with the given key in the resource bundle for
112
	 * Returns the resource object with the given key in the resource bundle for
113
	 * JFace Data Binding. If there isn't any value under the given key, the key
113
	 * JFace Data Binding. If there isn't any value under the given key, the key
114
	 * is returned.
114
	 * is returned.
115
	 *
115
	 * 
116
	 * @param key
116
	 * @param key
117
	 *            the resource name
117
	 *            the resource name
118
	 * @return the string
118
	 * @return the string
Lines 128-143 Link Here
128
	/**
128
	/**
129
	 * Returns a formatted string with the given key in the resource bundle for
129
	 * Returns a formatted string with the given key in the resource bundle for
130
	 * JFace Data Binding.
130
	 * JFace Data Binding.
131
	 *
131
	 * 
132
	 * @param key
132
	 * @param key
133
	 * @param arguments
133
	 * @param arguments
134
	 * @return formatted string, the key if the key is invalid
134
	 * @return formatted string, the key if the key is invalid
135
	 */
135
	 */
136
	public static String formatString(String key, Object[] arguments) {
136
	public static String getFormattedString(String key, Object[] arguments) {
137
		try {
137
		try {
138
			return MessageFormat.format(bundle.getString(key), arguments);
138
			return formatMessage(getString(key), arguments);
139
		} catch (MissingResourceException e) {
139
		} catch (MissingResourceException e) {
140
			return key;
140
			return key;
141
		}
141
		}
142
	}
142
	}
143
144
	/**
145
	 * Formats the given message pattern with the provided arguments.
146
	 * 
147
	 * @param pattern
148
	 * @param arguments
149
	 * @return formatted string
150
	 */
151
	public static String formatMessage(String pattern, Object[] arguments) {
152
		return MessageFormat.format(pattern, arguments);
153
	}
143
}
154
}
(-)src/org/eclipse/core/internal/databinding/conversion/StringToDateConverter.java (-2 / +20 lines)
Lines 15-27 Link Here
15
15
16
import org.eclipse.core.databinding.conversion.IConverter;
16
import org.eclipse.core.databinding.conversion.IConverter;
17
17
18
import com.ibm.icu.text.DateFormat;
18
19
19
/**
20
/**
20
 * Convert a String to a java.util.Date, respecting the current locale
21
 * Convert a String to a java.util.Date, respecting the current locale
21
 * 
22
 * 
22
 * @since 1.0
23
 * @since 1.0
23
 */
24
 */
24
public class StringToDateConverter extends DateConversionSupport implements IConverter {
25
public class StringToDateConverter extends DateConversionSupport implements
26
		IConverter {
27
28
	/**
29
	 * 
30
	 */
31
	public StringToDateConverter() {
32
		super();
33
	}
34
35
	/**
36
	 * 
37
	 * @param formats
38
	 */
39
	public StringToDateConverter(DateFormat[] formats) {
40
		super(formats);
41
	}
42
25
	public Object convert(Object source) {
43
	public Object convert(Object source) {
26
		return parse(source.toString());
44
		return parse(source.toString());
27
	}
45
	}
Lines 32-36 Link Here
32
50
33
	public Object getToType() {
51
	public Object getToType() {
34
		return Date.class;
52
		return Date.class;
35
	}	
53
	}
36
}
54
}
(-)src/org/eclipse/core/internal/databinding/conversion/DateConversionSupport.java (-35 / +51 lines)
Lines 31-88 Link Here
31
 * </p>
31
 * </p>
32
 */
32
 */
33
public abstract class DateConversionSupport {
33
public abstract class DateConversionSupport {
34
	private final static int DATE_FORMAT=DateFormat.SHORT;
34
	private final static int DATE_FORMAT = DateFormat.SHORT;
35
	private final static int DEFAULT_FORMATTER_INDEX=0;
35
	private final static int DEFAULT_FORMATTER_INDEX = 0;
36
36
37
	private final static int NUM_VIRTUAL_FORMATTERS=1;
37
	private final static int NUM_VIRTUAL_FORMATTERS = 1;
38
38
39
	/**
39
	/**
40
	 * Alternative formatters for date, time and date/time.
40
	 * Alternative formatters for date, time and date/time. Raw milliseconds are
41
	 * Raw milliseconds are covered as a special case.
41
	 * covered as a special case.
42
	 */
42
	 */
43
	// TODO: These could be shared, but would have to be synchronized.
43
	private final DateFormat[] formatters;
44
	private DateFormat[] formatters = {
44
45
			new SimpleDateFormat(BindingMessages.getString(BindingMessages.DATE_FORMAT_DATE_TIME)),
45
	/**
46
			new SimpleDateFormat(BindingMessages.getString(BindingMessages.DATEFORMAT_TIME)),
46
	 * 
47
			DateFormat.getDateTimeInstance(DATE_FORMAT, DateFormat.SHORT),
47
	 */
48
			DateFormat.getDateInstance(DATE_FORMAT),
48
	public DateConversionSupport() {
49
			DateFormat.getTimeInstance(DateFormat.SHORT),
49
		// TODO: These could be shared, but would have to be synchronized.
50
            DateFormat.getDateTimeInstance(DATE_FORMAT,DateFormat.MEDIUM),
50
		this(new DateFormat[] {
51
            DateFormat.getTimeInstance(DateFormat.MEDIUM)
51
				new SimpleDateFormat(BindingMessages
52
	};
52
						.getString(BindingMessages.DATE_FORMAT_DATE_TIME)),
53
				new SimpleDateFormat(BindingMessages
54
						.getString(BindingMessages.DATEFORMAT_TIME)),
55
				DateFormat.getDateTimeInstance(DATE_FORMAT, DateFormat.SHORT),
56
				DateFormat.getDateInstance(DATE_FORMAT),
57
				DateFormat.getTimeInstance(DateFormat.SHORT),
58
				DateFormat.getDateTimeInstance(DATE_FORMAT, DateFormat.MEDIUM),
59
				DateFormat.getTimeInstance(DateFormat.MEDIUM) });
60
	}
61
62
	/**
63
	 * 
64
	 * @param formats
65
	 */
66
	public DateConversionSupport(DateFormat[] formats) {
67
		this.formatters = formats;
68
	}
53
69
54
	/**
70
	/**
55
	 * Tries all available formatters to parse the given string according to the
71
	 * Tries all available formatters to parse the given string according to the
56
	 * default locale or as a raw millisecond value and returns the result of the
72
	 * default locale or as a raw millisecond value and returns the result of the
57
	 * first successful run.
73
	 * first successful run.
58
	 *
74
	 * 
59
	 * @param str A string specifying a date according to the default locale or in raw milliseconds
75
	 * @param str A string specifying a date according to the default locale or in raw milliseconds
60
	 * @return The parsed date, or null, if no available formatter could interpret the input string
76
	 * @return The parsed date, or null, if no available formatter could interpret the input string
61
	 */
77
	 */
62
	protected Date parse(String str) {
78
	protected Date parse(String str) {
63
		for (int formatterIdx = 0; formatterIdx < formatters.length; formatterIdx++) {
79
		for (int formatterIdx = 0; formatterIdx < formatters.length; formatterIdx++) {
64
			Date parsed=parse(str,formatterIdx);
80
			Date parsed = parse(str, formatterIdx);
65
			if(parsed!=null) {
81
			if (parsed != null) {
66
				return parsed;
82
				return parsed;
67
			}
83
			}
68
		}
84
		}
69
		return null;
85
		return null;
70
	}
86
	}
71
87
72
	protected Date parse(String str,int formatterIdx) {
88
	protected Date parse(String str, int formatterIdx) {
73
		if(formatterIdx>=0) {
89
		if (formatterIdx >= 0) {
74
				ParsePosition pos=new ParsePosition(0);
90
			ParsePosition pos = new ParsePosition(0);
75
				if (str == null) {
91
			if (str == null) {
76
					return null;
92
				return null;
77
				}
93
			}
78
				Date date=formatters[formatterIdx].parse(str,pos);
94
			Date date = formatters[formatterIdx].parse(str, pos);
79
				if(pos.getErrorIndex()!=-1||pos.getIndex()!=str.length()) {
95
			if (pos.getErrorIndex() != -1 || pos.getIndex() != str.length()) {
80
					return null;
96
				return null;
81
				}
97
			}
82
				return date;
98
			return date;
83
		}
99
		}
84
		try {
100
		try {
85
			long millisecs=Long.parseLong(str);
101
			long millisecs = Long.parseLong(str);
86
			return new Date(millisecs);
102
			return new Date(millisecs);
87
		}
103
		}
88
		catch(NumberFormatException exc) {
104
		catch(NumberFormatException exc) {
Lines 96-115 Link Here
96
	 * @return a string representation of the given date according to the default locale
112
	 * @return a string representation of the given date according to the default locale
97
	 */
113
	 */
98
	protected String format(Date date) {
114
	protected String format(Date date) {
99
		return format(date,DEFAULT_FORMATTER_INDEX);
115
		return format(date, DEFAULT_FORMATTER_INDEX);
100
	}
116
	}
101
117
102
	protected String format(Date date,int formatterIdx) {
118
	protected String format(Date date, int formatterIdx) {
103
		if (date == null)
119
		if (date == null)
104
			return null;
120
			return null;
105
		if(formatterIdx>=0) {
121
		if (formatterIdx >= 0) {
106
			return formatters[formatterIdx].format(date);
122
			return formatters[formatterIdx].format(date);
107
		}
123
		}
108
		return String.valueOf(date.getTime());
124
		return String.valueOf(date.getTime());
109
	}
125
	}
110
126
111
	protected int numFormatters() {
127
	protected int numFormatters() {
112
		return formatters.length+NUM_VIRTUAL_FORMATTERS;
128
		return formatters.length + NUM_VIRTUAL_FORMATTERS;
113
	}
129
	}
114
130
115
	/**
131
	/**
Lines 118-124 Link Here
118
	 * This is for testing purposes only and should not be a part of the API if
134
	 * This is for testing purposes only and should not be a part of the API if
119
	 * this class was to be exposed.
135
	 * this class was to be exposed.
120
	 * </p>
136
	 * </p>
121
	 *
137
	 * 
122
	 * @param index
138
	 * @param index
123
	 * @return date format
139
	 * @return date format
124
	 */
140
	 */
(-)src/org/eclipse/core/internal/databinding/conversion/StringToNumberParser.java (-17 / +33 lines)
Lines 21-27 Link Here
21
21
22
/**
22
/**
23
 * Utility class for the parsing of strings to numbers.
23
 * Utility class for the parsing of strings to numbers.
24
 *
24
 * 
25
 * @since 1.0
25
 * @since 1.0
26
 */
26
 */
27
public class StringToNumberParser {
27
public class StringToNumberParser {
Lines 73-79 Link Here
73
73
74
	/**
74
	/**
75
	 * The result of a parse operation.
75
	 * The result of a parse operation.
76
	 *
76
	 * 
77
	 * @since 1.0
77
	 * @since 1.0
78
	 */
78
	 */
79
	public static class ParseResult {
79
	public static class ParseResult {
Lines 84-90 Link Here
84
		 * The number as a result of the conversion. <code>null</code> if the
84
		 * The number as a result of the conversion. <code>null</code> if the
85
		 * value could not be converted or if the type is not a primitive and
85
		 * value could not be converted or if the type is not a primitive and
86
		 * the value was an empty string.
86
		 * the value was an empty string.
87
		 *
87
		 * 
88
		 * @return number
88
		 * @return number
89
		 */
89
		 */
90
		public Number getNumber() {
90
		public Number getNumber() {
Lines 94-100 Link Here
94
		/**
94
		/**
95
		 * ParsePosition if an error occurred while parsing. <code>null</code>
95
		 * ParsePosition if an error occurred while parsing. <code>null</code>
96
		 * if no error occurred.
96
		 * if no error occurred.
97
		 *
97
		 * 
98
		 * @return parse position
98
		 * @return parse position
99
		 */
99
		 */
100
		public ParsePosition getPosition() {
100
		public ParsePosition getPosition() {
Lines 104-110 Link Here
104
104
105
	/**
105
	/**
106
	 * Formats an appropriate message for a parsing error.
106
	 * Formats an appropriate message for a parsing error.
107
	 *
107
	 * 
108
	 * @param value
108
	 * @param value
109
	 * @param position
109
	 * @param position
110
	 * @return message
110
	 * @return message
Lines 115-131 Link Here
115
				.getErrorIndex() : position.getIndex();
115
				.getErrorIndex() : position.getIndex();
116
116
117
		if (errorIndex < value.length()) {
117
		if (errorIndex < value.length()) {
118
			return BindingMessages.formatString(BindingMessages.VALIDATE_NUMBER_PARSE_ERROR,
118
			return BindingMessages.getFormattedString(BindingMessages.VALIDATE_NUMBER_PARSE_ERROR,
119
					new Object[] { value, new Integer(errorIndex + 1),
119
					new Object[] { value, new Integer(errorIndex + 1),
120
							new Character(value.charAt(errorIndex)) });
120
							new Character(value.charAt(errorIndex)) });
121
		}
121
		}
122
		return BindingMessages.formatString(BindingMessages.VALIDATE_NUMBER_PARSE_ERROR_NO_CHARACTER,
122
		return BindingMessages.getFormattedString(BindingMessages.VALIDATE_NUMBER_PARSE_ERROR_NO_CHARACTER,
123
				new Object[] { value, new Integer(errorIndex + 1) });
123
				new Object[] { value, new Integer(errorIndex + 1) });
124
	}
124
	}
125
125
126
	/**
126
	/**
127
	 * Formats an appropriate message for an out of range error.
127
	 * Formats an appropriate message for an out of range error.
128
	 *
128
	 * 
129
	 * @param minValue
129
	 * @param minValue
130
	 * @param maxValue
130
	 * @param maxValue
131
	 * @param numberFormat when accessed method synchronizes on instance
131
	 * @param numberFormat when accessed method synchronizes on instance
Lines 133-138 Link Here
133
	 */
133
	 */
134
	public static String createOutOfRangeMessage(Number minValue,
134
	public static String createOutOfRangeMessage(Number minValue,
135
			Number maxValue, NumberFormat numberFormat) {
135
			Number maxValue, NumberFormat numberFormat) {
136
		return createOutOfRangeMessage(
137
				BindingMessages.getString("Validate_NumberOutOfRangeError"), minValue, maxValue, numberFormat); //$NON-NLS-1$
138
	}
139
140
	/**
141
	 * Formats an appropriate message for an out of range error.
142
	 * 
143
	 * @param message
144
	 * @param minValue
145
	 * @param maxValue
146
	 * @param numberFormat
147
	 *            when accessed method synchronizes on instance
148
	 * @return message
149
	 */
150
	public static String createOutOfRangeMessage(String message,
151
			Number minValue, Number maxValue, NumberFormat numberFormat) {
136
		String min = null;
152
		String min = null;
137
		String max = null;
153
		String max = null;
138
154
Lines 141-154 Link Here
141
			max = numberFormat.format(maxValue);
157
			max = numberFormat.format(maxValue);
142
		}
158
		}
143
159
144
		return BindingMessages.formatString(
160
		return BindingMessages.formatMessage(message, new Object[] { min,
145
				"Validate_NumberOutOfRangeError", new Object[] { min, max }); //$NON-NLS-1$
161
				max });
146
	}
162
	}
147
163
148
	/**
164
	/**
149
	 * Returns <code>true</code> if the provided <code>number</code> is in
165
	 * Returns <code>true</code> if the provided <code>number</code> is in
150
	 * the range of a integer.
166
	 * the range of a integer.
151
	 *
167
	 * 
152
	 * @param number
168
	 * @param number
153
	 * @return <code>true</code> if a valid integer
169
	 * @return <code>true</code> if a valid integer
154
	 * @throws IllegalArgumentException
170
	 * @throws IllegalArgumentException
Lines 160-166 Link Here
160
176
161
	/**
177
	/**
162
	 * Validates the range of the provided <code>number</code>.
178
	 * Validates the range of the provided <code>number</code>.
163
	 *
179
	 * 
164
	 * @param number
180
	 * @param number
165
	 * @param bitLength number of bits allowed to be in range
181
	 * @param bitLength number of bits allowed to be in range
166
	 * @return <code>true</code> if in range
182
	 * @return <code>true</code> if in range
Lines 204-210 Link Here
204
	/**
220
	/**
205
	 * Returns <code>true</code> if the provided <code>number</code> is in
221
	 * Returns <code>true</code> if the provided <code>number</code> is in
206
	 * the range of a long.
222
	 * the range of a long.
207
	 *
223
	 * 
208
	 * @param number
224
	 * @param number
209
	 * @return <code>true</code> if in range
225
	 * @return <code>true</code> if in range
210
	 * @throws IllegalArgumentException
226
	 * @throws IllegalArgumentException
Lines 217-223 Link Here
217
	/**
233
	/**
218
	 * Returns <code>true</code> if the provided <code>number</code> is in
234
	 * Returns <code>true</code> if the provided <code>number</code> is in
219
	 * the range of a float.
235
	 * the range of a float.
220
	 *
236
	 * 
221
	 * @param number
237
	 * @param number
222
	 * @return <code>true</code> if in range
238
	 * @return <code>true</code> if in range
223
	 * @throws IllegalArgumentException
239
	 * @throws IllegalArgumentException
Lines 267-273 Link Here
267
	/**
283
	/**
268
	 * Returns <code>true</code> if the provided <code>number</code> is in
284
	 * Returns <code>true</code> if the provided <code>number</code> is in
269
	 * the range of a double.
285
	 * the range of a double.
270
	 *
286
	 * 
271
	 * @param number
287
	 * @param number
272
	 * @return <code>true</code> if in range
288
	 * @return <code>true</code> if in range
273
	 * @throws IllegalArgumentException
289
	 * @throws IllegalArgumentException
Lines 280-286 Link Here
280
	/**
296
	/**
281
	 * Returns <code>true</code> if the provided <code>number</code> is in
297
	 * Returns <code>true</code> if the provided <code>number</code> is in
282
	 * the range of a short.
298
	 * the range of a short.
283
	 *
299
	 * 
284
	 * @param number
300
	 * @param number
285
	 * @return <code>true</code> if in range
301
	 * @return <code>true</code> if in range
286
	 */
302
	 */
Lines 291-297 Link Here
291
	/**
307
	/**
292
	 * Returns <code>true</code> if the provided <code>number</code> is in
308
	 * Returns <code>true</code> if the provided <code>number</code> is in
293
	 * the range of a byte.
309
	 * the range of a byte.
294
	 *
310
	 * 
295
	 * @param number
311
	 * @param number
296
	 * @return <code>true</code> if in range
312
	 * @return <code>true</code> if in range
297
	 */
313
	 */
(-)src/org/eclipse/core/internal/databinding/conversion/DateToStringConverter.java (-4 / +22 lines)
Lines 15-31 Link Here
15
15
16
import org.eclipse.core.databinding.conversion.IConverter;
16
import org.eclipse.core.databinding.conversion.IConverter;
17
17
18
import com.ibm.icu.text.DateFormat;
18
19
19
/**
20
/**
20
 * Converts a Java.util.Date to a String using the current locale.  Null date
21
 * Converts a Java.util.Date to a String using the current locale. Null date
21
 * values are converted to an empty string.
22
 * values are converted to an empty string.
22
 * 
23
 * 
23
 * @since 1.0
24
 * @since 1.0
24
 */
25
 */
25
public class DateToStringConverter extends DateConversionSupport implements IConverter {	
26
public class DateToStringConverter extends DateConversionSupport implements
27
		IConverter {
28
29
	/**
30
	 * 
31
	 */
32
	public DateToStringConverter() {
33
		super();
34
	}
35
36
	/**
37
	 * 
38
	 * @param format
39
	 */
40
	public DateToStringConverter(DateFormat format) {
41
		super(new DateFormat[] { format });
42
	}
43
26
	public Object convert(Object source) {
44
	public Object convert(Object source) {
27
		if (source != null)
45
		if (source != null)
28
			return format((Date)source);
46
			return format((Date) source);
29
		return ""; //$NON-NLS-1$
47
		return ""; //$NON-NLS-1$
30
	}
48
	}
31
49
Lines 35-39 Link Here
35
53
36
	public Object getToType() {
54
	public Object getToType() {
37
		return String.class;
55
		return String.class;
38
	}	
56
	}
39
}
57
}
(-)src/org/eclipse/core/internal/databinding/validation/StringToIntegerValidator.java (-1 / +10 lines)
Lines 13-19 Link Here
13
13
14
import org.eclipse.core.internal.databinding.conversion.StringToNumberParser;
14
import org.eclipse.core.internal.databinding.conversion.StringToNumberParser;
15
15
16
17
/**
16
/**
18
 * Validates that a string is of the appropriate format and is in the range of
17
 * Validates that a string is of the appropriate format and is in the range of
19
 * an integer.
18
 * an integer.
Lines 31-36 Link Here
31
		super(converter, MIN, MAX);
30
		super(converter, MIN, MAX);
32
	}
31
	}
33
32
33
	/**
34
	 * @param converter
35
	 * @param parseErrorMessage
36
	 * @param outOfRangeMessage
37
	 */
38
	public StringToIntegerValidator(NumberFormatConverter converter,
39
			String parseErrorMessage, String outOfRangeMessage) {
40
		super(converter, MIN, MAX, parseErrorMessage, outOfRangeMessage);
41
	}
42
34
	/* (non-Javadoc)
43
	/* (non-Javadoc)
35
	 * @see org.eclipse.core.internal.databinding.validation.AbstractStringToNumberValidator#inRange(java.lang.Number)
44
	 * @see org.eclipse.core.internal.databinding.validation.AbstractStringToNumberValidator#inRange(java.lang.Number)
36
	 */
45
	 */
(-)src/org/eclipse/core/internal/databinding/validation/StringToDateValidator.java (-7 / +23 lines)
Lines 28-51 Link Here
28
public class StringToDateValidator implements IValidator {
28
public class StringToDateValidator implements IValidator {
29
	private final StringToDateConverter converter;
29
	private final StringToDateConverter converter;
30
30
31
	private final String parseErrorMessage;
32
31
	/**
33
	/**
32
	 * @param converter
34
	 * @param converter
33
	 */
35
	 */
34
	public StringToDateValidator(StringToDateConverter converter) {
36
	public StringToDateValidator(StringToDateConverter converter) {
37
		this(converter, null);
38
	}
39
40
	/**
41
	 * @param converter
42
	 * @param parseErrorMessage
43
	 */
44
	public StringToDateValidator(StringToDateConverter converter,
45
			String parseErrorMessage) {
35
		this.converter = converter;
46
		this.converter = converter;
47
		this.parseErrorMessage = parseErrorMessage;
36
	}
48
	}
37
49
38
	/*
50
	/*
39
	 * (non-Javadoc)
51
	 * (non-Javadoc)
40
	 *
52
	 * 
41
	 * @see org.eclipse.core.databinding.validation.IValidator#validate(java.lang.Object)
53
	 * @see org.eclipse.core.databinding.validation.IValidator#validate(java.lang.Object)
42
	 */
54
	 */
43
	public IStatus validate(Object value) {
55
	public IStatus validate(Object value) {
44
		if (value instanceof String && ((String)value).trim().length()==0) {
56
		if (value instanceof String && ((String) value).trim().length() == 0) {
45
			return Status.OK_STATUS;
57
			return Status.OK_STATUS;
46
		}
58
		}
47
		Object convertedValue = converter.convert(value);
59
		Object convertedValue = converter.convert(value);
48
		//The StringToDateConverter returns null if it can't parse the date.
60
		// The StringToDateConverter returns null if it can't parse the date.
49
		if (convertedValue == null) {
61
		if (convertedValue == null) {
50
			return ValidationStatus.error(getErrorMessage());
62
			return ValidationStatus.error(getErrorMessage());
51
		}
63
		}
Lines 55-64 Link Here
55
67
56
	/*
68
	/*
57
	 * (non-Javadoc)
69
	 * (non-Javadoc)
58
	 *
70
	 * 
59
	 * @see org.eclipse.core.internal.databinding.validation.WrappedConverterValidator#getErrorMessage()
71
	 * @see org.eclipse.core.internal.databinding.validation.WrappedConverterValidator#getErrorMessage()
60
	 */
72
	 */
61
	protected String getErrorMessage() {
73
	protected String getErrorMessage() {
74
		if (parseErrorMessage != null) {
75
			return parseErrorMessage;
76
		}
77
62
		Date sampleDate = new Date();
78
		Date sampleDate = new Date();
63
79
64
		// FIXME We need to use the information from the
80
		// FIXME We need to use the information from the
Lines 79-85 Link Here
79
	private static class FormatUtil extends DateConversionSupport {
95
	private static class FormatUtil extends DateConversionSupport {
80
		/*
96
		/*
81
		 * (non-Javadoc)
97
		 * (non-Javadoc)
82
		 *
98
		 * 
83
		 * @see org.eclipse.core.internal.databinding.conversion.DateConversionSupport#numFormatters()
99
		 * @see org.eclipse.core.internal.databinding.conversion.DateConversionSupport#numFormatters()
84
		 */
100
		 */
85
		protected int numFormatters() {
101
		protected int numFormatters() {
Lines 88-94 Link Here
88
104
89
		/*
105
		/*
90
		 * (non-Javadoc)
106
		 * (non-Javadoc)
91
		 *
107
		 * 
92
		 * @see org.eclipse.core.internal.databinding.conversion.DateConversionSupport#format(java.util.Date)
108
		 * @see org.eclipse.core.internal.databinding.conversion.DateConversionSupport#format(java.util.Date)
93
		 */
109
		 */
94
		protected String format(Date date) {
110
		protected String format(Date date) {
Lines 97-103 Link Here
97
113
98
		/*
114
		/*
99
		 * (non-Javadoc)
115
		 * (non-Javadoc)
100
		 *
116
		 * 
101
		 * @see org.eclipse.core.internal.databinding.conversion.DateConversionSupport#format(java.util.Date,
117
		 * @see org.eclipse.core.internal.databinding.conversion.DateConversionSupport#format(java.util.Date,
102
		 *      int)
118
		 *      int)
103
		 */
119
		 */
(-)src/org/eclipse/core/internal/databinding/validation/AbstractStringToNumberValidator.java (-8 / +46 lines)
Lines 11-16 Link Here
11
11
12
package org.eclipse.core.internal.databinding.validation;
12
package org.eclipse.core.internal.databinding.validation;
13
13
14
import java.text.ParsePosition;
15
14
import org.eclipse.core.databinding.validation.IValidator;
16
import org.eclipse.core.databinding.validation.IValidator;
15
import org.eclipse.core.databinding.validation.ValidationStatus;
17
import org.eclipse.core.databinding.validation.ValidationStatus;
16
import org.eclipse.core.internal.databinding.conversion.StringToNumberParser;
18
import org.eclipse.core.internal.databinding.conversion.StringToNumberParser;
Lines 31-37 Link Here
31
	private final Number min;
33
	private final Number min;
32
	private final Number max;
34
	private final Number max;
33
35
34
	private String outOfRangeMessage;
36
	private final String parseErrorMessage;
37
	private final String outOfRangeMessage;
38
39
	private String formattedOutOfRangeMessage;
35
40
36
	/**
41
	/**
37
	 * Constructs a new instance.
42
	 * Constructs a new instance.
Lines 42-50 Link Here
42
	 */
47
	 */
43
	protected AbstractStringToNumberValidator(NumberFormatConverter converter,
48
	protected AbstractStringToNumberValidator(NumberFormatConverter converter,
44
			Number min, Number max) {
49
			Number min, Number max) {
50
		this(converter, min, max, null, null);
51
	}
52
53
	/**
54
	 * Constructs a new instance.
55
	 * 
56
	 * @param converter converter and thus formatter to be used in validation
57
	 * @param min minimum value, used for reporting a range error to the user
58
	 * @param max maximum value, used for reporting a range error to the user
59
	 * @param parseErrorMessage
60
	 * @param outOfRangeMessage
61
	 */
62
	protected AbstractStringToNumberValidator(NumberFormatConverter converter,
63
			Number min, Number max, String parseErrorMessage,
64
			String outOfRangeMessage) {
45
		this.converter = converter;
65
		this.converter = converter;
46
		this.min = min;
66
		this.min = min;
47
		this.max = max;
67
		this.max = max;
68
		this.parseErrorMessage = parseErrorMessage;
69
		this.outOfRangeMessage = outOfRangeMessage;
48
70
49
		if (converter.getToType() instanceof Class) {
71
		if (converter.getToType() instanceof Class) {
50
			Class clazz = (Class) converter.getToType();
72
			Class clazz = (Class) converter.getToType();
Lines 69-85 Link Here
69
91
70
		if (result.getNumber() != null) {
92
		if (result.getNumber() != null) {
71
			if (!isInRange(result.getNumber())) {
93
			if (!isInRange(result.getNumber())) {
72
				if (outOfRangeMessage == null) {
94
				if (formattedOutOfRangeMessage == null) {
73
					outOfRangeMessage = StringToNumberParser
95
					formattedOutOfRangeMessage = createOutOfRangeMessage();
74
							.createOutOfRangeMessage(min, max, converter
75
									.getNumberFormat());
76
				}
96
				}
77
97
78
				return ValidationStatus.error(outOfRangeMessage);
98
				return ValidationStatus.error(formattedOutOfRangeMessage);
79
			}
99
			}
80
		} else if (result.getPosition() != null) {
100
		} else if (result.getPosition() != null) {
81
			String parseErrorMessage = StringToNumberParser.createParseErrorMessage(
101
			String parseErrorMessage = createParseErrorMessage((String) value,
82
					(String) value, result.getPosition());
102
					result.getPosition());
83
103
84
			return ValidationStatus.error(parseErrorMessage);
104
			return ValidationStatus.error(parseErrorMessage);
85
		}
105
		}
Lines 94-97 Link Here
94
	 * @return <code>true</code> if in range
114
	 * @return <code>true</code> if in range
95
	 */
115
	 */
96
	protected abstract boolean isInRange(Number number);
116
	protected abstract boolean isInRange(Number number);
117
118
	private String createParseErrorMessage(String input,
119
			ParsePosition parsePosition) {
120
		if (parseErrorMessage == null) {
121
			return StringToNumberParser.createParseErrorMessage(input,
122
					parsePosition);
123
		}
124
		return parseErrorMessage;
125
	}
126
127
	private String createOutOfRangeMessage() {
128
		if (outOfRangeMessage == null) {
129
			return StringToNumberParser.createOutOfRangeMessage(min, max,
130
					converter.getNumberFormat());
131
		}
132
		return StringToNumberParser.createOutOfRangeMessage(outOfRangeMessage,
133
				min, max, converter.getNumberFormat());
134
	}
97
}
135
}
(-).settings/org.eclipse.jdt.ui.prefs (-2 / +2 lines)
Lines 1-4 Link Here
1
#Tue Feb 10 16:05:48 MST 2009
1
#Sat Aug 29 00:54:17 CEST 2009
2
cleanup.add_default_serial_version_id=true
2
cleanup.add_default_serial_version_id=true
3
cleanup.add_generated_serial_version_id=false
3
cleanup.add_generated_serial_version_id=false
4
cleanup.add_missing_annotations=true
4
cleanup.add_missing_annotations=true
Lines 78-84 Link Here
78
sp_cleanup.always_use_this_for_non_static_method_access=false
78
sp_cleanup.always_use_this_for_non_static_method_access=false
79
sp_cleanup.convert_to_enhanced_for_loop=false
79
sp_cleanup.convert_to_enhanced_for_loop=false
80
sp_cleanup.correct_indentation=false
80
sp_cleanup.correct_indentation=false
81
sp_cleanup.format_source_code=true
81
sp_cleanup.format_source_code=false
82
sp_cleanup.format_source_code_changes_only=false
82
sp_cleanup.format_source_code_changes_only=false
83
sp_cleanup.make_local_variable_final=false
83
sp_cleanup.make_local_variable_final=false
84
sp_cleanup.make_parameters_final=false
84
sp_cleanup.make_parameters_final=false
(-)META-INF/MANIFEST.MF (+2 lines)
Lines 8-14 Link Here
8
Bundle-Localization: plugin
8
Bundle-Localization: plugin
9
Export-Package: org.eclipse.core.databinding,
9
Export-Package: org.eclipse.core.databinding,
10
 org.eclipse.core.databinding.conversion;x-internal:=false,
10
 org.eclipse.core.databinding.conversion;x-internal:=false,
11
 org.eclipse.core.databinding.editing,
11
 org.eclipse.core.databinding.validation;x-internal:=false,
12
 org.eclipse.core.databinding.validation;x-internal:=false,
13
 org.eclipse.core.databinding.validation.constraint,
12
 org.eclipse.core.internal.databinding;x-friends:="org.eclipse.core.databinding.beans",
14
 org.eclipse.core.internal.databinding;x-friends:="org.eclipse.core.databinding.beans",
13
 org.eclipse.core.internal.databinding.conversion;x-friends:="org.eclipse.jface.tests.databinding",
15
 org.eclipse.core.internal.databinding.conversion;x-friends:="org.eclipse.jface.tests.databinding",
14
 org.eclipse.core.internal.databinding.validation;x-friends:="org.eclipse.jface.tests.databinding"
16
 org.eclipse.core.internal.databinding.validation;x-friends:="org.eclipse.jface.tests.databinding"
(-)src/org/eclipse/core/internal/databinding/validation/NonEmptyStringValidator.java (+48 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Ovidio Mallo 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
 *     Ovidio Mallo - initial API and implementation (bug 183055)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.validation;
13
14
import org.eclipse.core.databinding.validation.IValidator;
15
import org.eclipse.core.databinding.validation.ValidationStatus;
16
import org.eclipse.core.runtime.IStatus;
17
18
/**
19
 * @since 1.3
20
 */
21
public class NonEmptyStringValidator implements IValidator {
22
23
	private final String validationMessage;
24
25
	/**
26
	 * 
27
	 */
28
	public NonEmptyStringValidator() {
29
		this(null);
30
	}
31
32
	/**
33
	 * @param validationMessage
34
	 */
35
	public NonEmptyStringValidator(String validationMessage) {
36
		// TODO: Externalize
37
		this.validationMessage = validationMessage != null ? validationMessage
38
				: "The string must not be empty."; //$NON-NLS-1$
39
	}
40
41
	public IStatus validate(Object value) {
42
		String input = (String) value;
43
		if ("".equals(input)) { //$NON-NLS-1$
44
			return ValidationStatus.error(validationMessage);
45
		}
46
		return ValidationStatus.ok();
47
	}
48
}
(-)src/org/eclipse/core/databinding/editing/StringEditing.java (+213 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Ovidio Mallo 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
 *     Ovidio Mallo - initial API and implementation (bug 183055)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.editing;
13
14
import org.eclipse.core.databinding.conversion.IConverter;
15
import org.eclipse.core.databinding.validation.constraint.Constraints;
16
import org.eclipse.core.databinding.validation.constraint.StringConstraints;
17
import org.eclipse.core.internal.databinding.conversion.StringStripConverter;
18
19
/**
20
 * @since 1.3
21
 */
22
public final class StringEditing extends Editing {
23
24
	private StringEditing(IConverter targetConverter) {
25
		setTargetConverter(targetConverter);
26
	}
27
28
	/**
29
	 * Creates a new editing object for strings which performs no validation or
30
	 * conversion.
31
	 * 
32
	 * @return The new editing object which performs no validation or
33
	 *         conversion.
34
	 */
35
	public static StringEditing withDefaults() {
36
		return new StringEditing(null);
37
	}
38
39
	/**
40
	 * Creates a new editing object which strips whitespace from both ends of
41
	 * the input string.
42
	 * 
43
	 * @param stripToNull
44
	 *            Whether to convert the input string to <code>null</code> in
45
	 *            case stripping the input string results in an empty string.
46
	 * @return The new editing object which strips whitespace from both ends of
47
	 *         the input string.
48
	 */
49
	public static StringEditing stripped(boolean stripToNull) {
50
		return new StringEditing(new StringStripConverter(stripToNull));
51
	}
52
53
	/**
54
	 * Returns the target constraints to apply.
55
	 * 
56
	 * <p>
57
	 * This method provides a typesafe access to the {@link StringConstraints
58
	 * string target constraints} of this editing object and is equivalent to
59
	 * {@code (StringConstraints) targetConstraints()}.
60
	 * </p>
61
	 * 
62
	 * @return The target constraints to apply.
63
	 * 
64
	 * @see #targetConstraints()
65
	 * @see StringConstraints
66
	 */
67
	public StringConstraints targetStringConstraints() {
68
		return (StringConstraints) targetConstraints();
69
	}
70
71
	/**
72
	 * Returns the model constraints to apply.
73
	 * 
74
	 * <p>
75
	 * This method provides a typesafe access to the {@link StringConstraints
76
	 * string model constraints} of this editing object and is equivalent to
77
	 * {@code (StringConstraints) modelConstraints()}.
78
	 * </p>
79
	 * 
80
	 * @return The target constraints to apply.
81
	 * 
82
	 * @see #modelConstraints()
83
	 * @see StringConstraints
84
	 */
85
	public StringConstraints modelStringConstraints() {
86
		return (StringConstraints) modelConstraints();
87
	}
88
89
	/**
90
	 * Returns the before-set model constraints to apply.
91
	 * 
92
	 * <p>
93
	 * This method provides a typesafe access to the {@link StringConstraints
94
	 * string before-set model constraints} of this editing object and is
95
	 * equivalent to {@code (StringConstraints) beforeSetModelConstraints()}.
96
	 * </p>
97
	 * 
98
	 * @return The target constraints to apply.
99
	 * 
100
	 * @see #beforeSetModelConstraints()
101
	 * @see StringConstraints
102
	 */
103
	public StringConstraints beforeSetModelStringConstraints() {
104
		return (StringConstraints) beforeSetModelConstraints();
105
	}
106
107
	protected Constraints createTargetConstraints() {
108
		return new StringConstraints();
109
	}
110
111
	protected Constraints createModelConstraints() {
112
		return new StringConstraints();
113
	}
114
115
	protected Constraints createBeforeSetModelConstraints() {
116
		return new StringConstraints();
117
	}
118
119
	/**
120
	 * Convenience method which adds a {@link StringConstraints#required()
121
	 * required constraint} to the set of {@link #modelStringConstraints()}.
122
	 * 
123
	 * @return This editing instance for method chaining.
124
	 * 
125
	 * @see StringConstraints#required()
126
	 * @see #modelStringConstraints()
127
	 */
128
	public StringEditing required() {
129
		modelStringConstraints().required();
130
		return this;
131
	}
132
133
	/**
134
	 * Convenience method which adds a {@link StringConstraints#nonEmpty()
135
	 * non-empty constraint} to the set of {@link #modelStringConstraints()}.
136
	 * 
137
	 * @return This editing instance for method chaining.
138
	 * 
139
	 * @see StringConstraints#nonEmpty()
140
	 * @see #modelStringConstraints()
141
	 */
142
	public StringEditing nonEmpty() {
143
		modelStringConstraints().nonEmpty();
144
		return this;
145
	}
146
147
	/**
148
	 * Convenience method which adds a {@link StringConstraints#minLength(int)
149
	 * min-length constraint} to the set of {@link #modelStringConstraints()}.
150
	 * 
151
	 * @param minLength
152
	 *            The min length of the min-length constraint.
153
	 * @return This editing instance for method chaining.
154
	 * 
155
	 * @see StringConstraints#minLength(int)
156
	 * @see #modelStringConstraints()
157
	 */
158
	public StringEditing minLength(int minLength) {
159
		modelStringConstraints().minLength(minLength);
160
		return this;
161
	}
162
163
	/**
164
	 * Convenience method which adds a {@link StringConstraints#maxLength(int)
165
	 * max-length constraint} to the set of {@link #modelStringConstraints()}.
166
	 * 
167
	 * @param maxLength
168
	 *            The max length of the max-length constraint.
169
	 * @return This editing instance for method chaining.
170
	 * 
171
	 * @see StringConstraints#maxLength(int)
172
	 * @see #modelStringConstraints()
173
	 */
174
	public StringEditing maxLength(int maxLength) {
175
		modelStringConstraints().maxLength(maxLength);
176
		return this;
177
	}
178
179
	/**
180
	 * Convenience method which adds a
181
	 * {@link StringConstraints#lengthRange(int, int) length-range constraint}
182
	 * to the set of {@link #modelStringConstraints()}.
183
	 * 
184
	 * @param minLength
185
	 *            The min length of the length-range constraint.
186
	 * @param maxLength
187
	 *            The max length of the length-range constraint.
188
	 * @return This editing instance for method chaining.
189
	 * 
190
	 * @see StringConstraints#lengthRange(int, int)
191
	 * @see #modelStringConstraints()
192
	 */
193
	public StringEditing lengthRange(int minLength, int maxLength) {
194
		modelStringConstraints().lengthRange(minLength, maxLength);
195
		return this;
196
	}
197
198
	/**
199
	 * Convenience method which adds a {@link StringConstraints#matches(String)
200
	 * matches constraint} to the set of {@link #modelStringConstraints()}.
201
	 * 
202
	 * @param regex
203
	 *            The regular expression of the matches constraint.
204
	 * @return This editing instance for method chaining.
205
	 * 
206
	 * @see StringConstraints#matches(String)
207
	 * @see #modelStringConstraints()
208
	 */
209
	public StringEditing matches(String regex) {
210
		modelStringConstraints().matches(regex);
211
		return this;
212
	}
213
}
(-)src/org/eclipse/core/internal/databinding/conversion/StringTrimConverter.java (+45 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Ovidio Mallo 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
 *     Ovidio Mallo - initial API and implementation (bug 183055)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.conversion;
13
14
import org.eclipse.core.databinding.conversion.Converter;
15
16
/**
17
 * @since 1.3
18
 */
19
public class StringTrimConverter extends Converter {
20
21
	private final boolean trimToNull;
22
23
	/**
24
	 * 
25
	 * @param trimToNull
26
	 */
27
	public StringTrimConverter(boolean trimToNull) {
28
		super(String.class, String.class);
29
		this.trimToNull = trimToNull;
30
	}
31
32
	public Object convert(Object fromObject) {
33
		String string = (String) fromObject;
34
35
		if (string != null) {
36
			string = string.trim();
37
38
			if (trimToNull && string.length() == 0) {
39
				string = null;
40
			}
41
		}
42
43
		return string;
44
	}
45
}
(-)src/org/eclipse/core/databinding/validation/constraint/Constraints.java (+180 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Ovidio Mallo 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
 *     Ovidio Mallo - initial API and implementation (bug 183055)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.validation.constraint;
13
14
import java.util.ArrayList;
15
import java.util.Iterator;
16
import java.util.List;
17
18
import org.eclipse.core.databinding.util.Policy;
19
import org.eclipse.core.databinding.validation.IValidator;
20
import org.eclipse.core.internal.databinding.BindingMessages;
21
import org.eclipse.core.runtime.IStatus;
22
import org.eclipse.core.runtime.MultiStatus;
23
import org.eclipse.core.runtime.Status;
24
25
/**
26
 * @since 1.3
27
 */
28
public class Constraints {
29
30
	/**
31
	 * Constant denoting an aggregation strategy that merges multiple non-OK
32
	 * status objects in a {@link MultiStatus}. Returns an OK status result if
33
	 * all statuses from the set of validators to apply are an OK status.
34
	 * Returns a single status if there is only one non-OK status.
35
	 * 
36
	 * @see #aggregationPolicy(int)
37
	 */
38
	public static final int AGGREGATION_MERGED = 1;
39
40
	/**
41
	 * Constant denoting an aggregation strategy that always returns the most
42
	 * severe status from the set of validators to apply. If there is more than
43
	 * one status at the same severity level, it picks the first one it
44
	 * encounters.
45
	 * 
46
	 * @see #aggregationPolicy(int)
47
	 */
48
	public static final int AGGREGATION_MAX_SEVERITY = 2;
49
50
	// Will be initialized lazily.
51
	private List validators = null;
52
53
	private IValidator cachedValidator = null;
54
55
	private int aggregationPolicy = AGGREGATION_MAX_SEVERITY;
56
57
	/**
58
	 * Adds a custom validator to the set of constraints to apply.
59
	 * 
60
	 * @param validator
61
	 *            The custom validator to add to the set of constraints.
62
	 * @return This constraints instance for method chaining.
63
	 */
64
	public final Constraints addValidator(IValidator validator) {
65
		if (validators == null) {
66
			validators = new ArrayList(2);
67
		}
68
		validators.add(validator);
69
		cachedValidator = null;
70
		return this;
71
	}
72
73
	/**
74
	 * Sets the aggregation policy to apply to the individual validations which
75
	 * constitute this set of constraints.
76
	 * 
77
	 * @param policy
78
	 *            The validation aggregation policy to set. Must be one of
79
	 *            {@link #AGGREGATION_MERGED} or
80
	 *            {@link #AGGREGATION_MAX_SEVERITY}.
81
	 * @return This constraints instance for method chaining.
82
	 * 
83
	 * @see #AGGREGATION_MERGED
84
	 * @see #AGGREGATION_MAX_SEVERITY
85
	 */
86
	public final Constraints aggregationPolicy(int policy) {
87
		this.aggregationPolicy = policy;
88
		cachedValidator = null;
89
		return this;
90
	}
91
92
	/**
93
	 * Creates a validator which enforces the current set of constraints.
94
	 * 
95
	 * <p>
96
	 * Note that this method will return <code>null</code> in case the set of
97
	 * constraints to apply is empty.
98
	 * </p>
99
	 * 
100
	 * @return A validator which enforces the current set of constraints. May be
101
	 *         <code>null</code>.
102
	 */
103
	public final IValidator createValidator() {
104
		if (validators != null && !validators.isEmpty()) {
105
			if (cachedValidator == null) {
106
				if (validators.size() == 1) {
107
					cachedValidator = (IValidator) validators.get(0);
108
				} else {
109
					IValidator[] currentValidators = (IValidator[]) validators
110
							.toArray(new IValidator[validators.size()]);
111
					cachedValidator = new ConstraintsValidator(
112
							currentValidators, aggregationPolicy);
113
				}
114
			}
115
			return cachedValidator;
116
		}
117
		return null;
118
	}
119
120
	private static final class ConstraintsValidator implements IValidator {
121
122
		private final IValidator[] validators;
123
124
		private final int aggregationPolicy;
125
126
		public ConstraintsValidator(IValidator[] validators,
127
				int aggregationPolicy) {
128
			this.validators = validators;
129
			this.aggregationPolicy = aggregationPolicy;
130
		}
131
132
		public IStatus validate(Object value) {
133
			return (aggregationPolicy == AGGREGATION_MERGED) ? validateMerged(value)
134
					: validateMaxSeverity(value);
135
		}
136
137
		private IStatus validateMerged(Object value) {
138
			List statuses = new ArrayList();
139
			for (int i = 0; i < validators.length; i++) {
140
				IValidator validator = validators[i];
141
				IStatus status = validator.validate(value);
142
				if (!status.isOK()) {
143
					statuses.add(status);
144
				}
145
			}
146
147
			if (statuses.size() == 1) {
148
				return (IStatus) statuses.get(0);
149
			}
150
151
			if (!statuses.isEmpty()) {
152
				MultiStatus result = new MultiStatus(Policy.JFACE_DATABINDING,
153
						0, BindingMessages
154
								.getString(BindingMessages.MULTIPLE_PROBLEMS),
155
						null);
156
				for (Iterator it = statuses.iterator(); it.hasNext();) {
157
					IStatus status = (IStatus) it.next();
158
					result.merge(status);
159
				}
160
				return result;
161
			}
162
163
			return Status.OK_STATUS;
164
		}
165
166
		private IStatus validateMaxSeverity(Object value) {
167
			int maxSeverity = IStatus.OK;
168
			IStatus maxStatus = Status.OK_STATUS;
169
			for (int i = 0; i < validators.length; i++) {
170
				IValidator validator = validators[i];
171
				IStatus status = validator.validate(value);
172
				if (status.getSeverity() > maxSeverity) {
173
					maxSeverity = status.getSeverity();
174
					maxStatus = status;
175
				}
176
			}
177
			return maxStatus;
178
		}
179
	}
180
}
(-)src/org/eclipse/core/databinding/editing/Editing.java (+1010 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Ovidio Mallo 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
 *     Ovidio Mallo - initial API and implementation (bug 183055)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.editing;
13
14
import org.eclipse.core.databinding.Binding;
15
import org.eclipse.core.databinding.DataBindingContext;
16
import org.eclipse.core.databinding.UpdateListStrategy;
17
import org.eclipse.core.databinding.UpdateSetStrategy;
18
import org.eclipse.core.databinding.UpdateValueStrategy;
19
import org.eclipse.core.databinding.conversion.IConverter;
20
import org.eclipse.core.databinding.observable.list.IObservableList;
21
import org.eclipse.core.databinding.observable.set.IObservableSet;
22
import org.eclipse.core.databinding.observable.value.IObservableValue;
23
import org.eclipse.core.databinding.validation.IValidator;
24
import org.eclipse.core.databinding.validation.constraint.Constraints;
25
import org.eclipse.core.runtime.IStatus;
26
import org.eclipse.core.runtime.MultiStatus;
27
28
/**
29
 * @since 1.3
30
 */
31
public class Editing {
32
33
	private Constraints targetConstraints;
34
35
	private Constraints modelConstraints;
36
37
	private Constraints beforeSetModelConstraints;
38
39
	private IConverter targetConverter;
40
41
	private IConverter modelConverter;
42
43
	/**
44
	 * Default constructor which creates an unconfigured editing instance.
45
	 */
46
	protected Editing() {
47
		// empty editing instance
48
	}
49
50
	/**
51
	 * Creates an unconfigured editing instance.
52
	 * 
53
	 * @return A new, unconfigured editing instance.
54
	 */
55
	public static Editing create() {
56
		return new Editing();
57
	}
58
59
	/**
60
	 * Creates an editing instance with the given target-to-model and
61
	 * model-to-target converters.
62
	 * 
63
	 * @param t2mConverter
64
	 *            The target-to-model converter to set. May be <code>null</code>
65
	 *            .
66
	 * @param m2tConverter
67
	 *            The model-to-target converter to set. May be <code>null</code>
68
	 *            .
69
	 * @return A new editing instance with the given target-to-model and
70
	 *         model-to-target converters.
71
	 */
72
	public static Editing withConverters(IConverter t2mConverter,
73
			IConverter m2tConverter) {
74
		Editing editing = new Editing();
75
		editing.setTargetConverter(t2mConverter);
76
		editing.setModelConverter(m2tConverter);
77
		return editing;
78
	}
79
80
	/**
81
	 * Returns the target constraints to apply.
82
	 * 
83
	 * @return The target constraints to apply.
84
	 * 
85
	 * @see #createTargetConstraints()
86
	 */
87
	public final Constraints targetConstraints() {
88
		if (targetConstraints == null) {
89
			targetConstraints = createTargetConstraints();
90
		}
91
		return targetConstraints;
92
	}
93
94
	/**
95
	 * Returns the model constraints to apply.
96
	 * 
97
	 * @return The model constraints to apply.
98
	 * 
99
	 * @see #createModelConstraints()
100
	 */
101
	public final Constraints modelConstraints() {
102
		if (modelConstraints == null) {
103
			modelConstraints = createModelConstraints();
104
		}
105
		return modelConstraints;
106
	}
107
108
	/**
109
	 * Returns the before-set model constraints to apply.
110
	 * 
111
	 * @return The before-set model constraints to apply.
112
	 * 
113
	 * @see #createBeforeSetModelConstraints()
114
	 */
115
	public final Constraints beforeSetModelConstraints() {
116
		if (beforeSetModelConstraints == null) {
117
			beforeSetModelConstraints = createBeforeSetModelConstraints();
118
		}
119
		return beforeSetModelConstraints;
120
	}
121
122
	/**
123
	 * Creates the target constraints to apply.
124
	 * 
125
	 * <p>
126
	 * The constraints object created by this method will be exposed as the
127
	 * {@link #targetConstraints()} of this editing object. By default, this
128
	 * method returns a plain {@link Constraints} object.
129
	 * </p>
130
	 * 
131
	 * <p>
132
	 * This method will be called lazily the first time the target constraints
133
	 * are accessed. Subclasses may overwrite this method in order to create a
134
	 * custom constraints object which will then be typically exposed in the
135
	 * subclass as API in order to allow for a typesafe access.
136
	 * </p>
137
	 * 
138
	 * @return The target constraints to apply.
139
	 * 
140
	 * @see #targetConstraints()
141
	 */
142
	protected Constraints createTargetConstraints() {
143
		return new Constraints();
144
	}
145
146
	/**
147
	 * Creates the model constraints to apply.
148
	 * 
149
	 * <p>
150
	 * The constraints object created by this method will be exposed as the
151
	 * {@link #modelConstraints()} of this editing object. By default, this
152
	 * method returns a plain {@link Constraints} object.
153
	 * </p>
154
	 * 
155
	 * <p>
156
	 * This method will be called lazily the first time the model constraints
157
	 * are accessed. Subclasses may overwrite this method in order to create a
158
	 * custom constraints object which will then be typically exposed in the
159
	 * subclass as API in order to allow for a typesafe access.
160
	 * </p>
161
	 * 
162
	 * @return The model constraints to apply.
163
	 * 
164
	 * @see #modelConstraints()
165
	 */
166
	protected Constraints createModelConstraints() {
167
		return new Constraints();
168
	}
169
170
	/**
171
	 * Creates the before-set model constraints to apply.
172
	 * 
173
	 * <p>
174
	 * The constraints object created by this method will be exposed as the
175
	 * {@link #beforeSetModelConstraints()} of this editing object. By default,
176
	 * this method returns a plain {@link Constraints} object.
177
	 * </p>
178
	 * 
179
	 * <p>
180
	 * This method will be called lazily the first time the before-set model
181
	 * constraints are accessed. Subclasses may overwrite this method in order
182
	 * to create a custom constraints object which will then be typically
183
	 * exposed in the subclass as API in order to allow for a typesafe access.
184
	 * </p>
185
	 * 
186
	 * @return The before-set model constraints to apply.
187
	 * 
188
	 * @see #beforeSetModelConstraints()
189
	 */
190
	protected Constraints createBeforeSetModelConstraints() {
191
		return new Constraints();
192
	}
193
194
	/**
195
	 * Convenience method which {@link Constraints#addValidator(IValidator)
196
	 * adds} the given validator to the set of {@link #targetConstraints()}.
197
	 * 
198
	 * @param validator
199
	 *            The validator to add to the target constraints.
200
	 * @return This editing instance for method chaining.
201
	 * 
202
	 * @see Constraints#addValidator(IValidator)
203
	 * @see #targetConstraints()
204
	 */
205
	public final Editing addTargetValidator(IValidator validator) {
206
		targetConstraints().addValidator(validator);
207
		return this;
208
	}
209
210
	/**
211
	 * Convenience method which {@link Constraints#addValidator(IValidator)
212
	 * adds} the given validator to the set of {@link #modelConstraints()}.
213
	 * 
214
	 * @param validator
215
	 *            The validator to add to the model constraints.
216
	 * @return This editing instance for method chaining.
217
	 * 
218
	 * @see Constraints#addValidator(IValidator)
219
	 * @see #modelConstraints()
220
	 */
221
	public final Editing addModelValidator(IValidator validator) {
222
		modelConstraints().addValidator(validator);
223
		return this;
224
	}
225
226
	/**
227
	 * Convenience method which {@link Constraints#addValidator(IValidator)
228
	 * adds} the given validator to the set of
229
	 * {@link #beforeSetModelConstraints()}.
230
	 * 
231
	 * @param validator
232
	 *            The validator to add to the before-set model constraints.
233
	 * @return This editing instance for method chaining.
234
	 * 
235
	 * @see Constraints#addValidator(IValidator)
236
	 * @see #beforeSetModelConstraints
237
	 */
238
	public final Editing addBeforeSetModelValidator(IValidator validator) {
239
		beforeSetModelConstraints().addValidator(validator);
240
		return this;
241
	}
242
243
	/**
244
	 * Sets the target-to-model converter for this editing instance.
245
	 * 
246
	 * @param converter
247
	 *            The target-to-model converter to set.
248
	 */
249
	protected final void setTargetConverter(IConverter converter) {
250
		this.targetConverter = converter;
251
	}
252
253
	/**
254
	 * Sets the model-to-target converter for this editing instance.
255
	 * 
256
	 * @param converter
257
	 *            The model-to-target converter to set.
258
	 */
259
	protected final void setModelConverter(IConverter converter) {
260
		this.modelConverter = converter;
261
	}
262
263
	/**
264
	 * Creates a new target-to-model {@link UpdateValueStrategy} with a default
265
	 * update policy configured by the current state of this editing object.
266
	 * 
267
	 * @return A new target-to-model {@link UpdateValueStrategy} configured by
268
	 *         the current state of this editing object.
269
	 * 
270
	 * @see UpdateValueStrategy#UpdateValueStrategy()
271
	 * @see #applyToT2MValueStrategy(UpdateValueStrategy)
272
	 */
273
	public final UpdateValueStrategy createT2MValueStrategy() {
274
		return applyToT2MValueStrategy(new UpdateValueStrategy());
275
	}
276
277
	/**
278
	 * Creates a new target-to-model {@link UpdateValueStrategy} with the given
279
	 * update policy configured by the current state of this editing object.
280
	 * 
281
	 * @param updatePolicy
282
	 *            The update policy to use.
283
	 * @return A new target-to-model {@link UpdateValueStrategy} configured by
284
	 *         the current state of this editing object.
285
	 * 
286
	 * @see UpdateValueStrategy#UpdateValueStrategy(int)
287
	 * @see #applyToT2MValueStrategy(UpdateValueStrategy)
288
	 */
289
	public final UpdateValueStrategy createT2MValueStrategy(int updatePolicy) {
290
		return applyToT2MValueStrategy(new UpdateValueStrategy(updatePolicy));
291
	}
292
293
	/**
294
	 * Creates a new model-to-target {@link UpdateValueStrategy} with a default
295
	 * update policy configured by the current state of this editing object.
296
	 * 
297
	 * @return A new model-to-target {@link UpdateValueStrategy} configured by
298
	 *         the current state of this editing object.
299
	 * 
300
	 * @see UpdateValueStrategy#UpdateValueStrategy()
301
	 * @see #applyToM2TValueStrategy(UpdateValueStrategy)
302
	 */
303
	public final UpdateValueStrategy createM2TValueStrategy() {
304
		return applyToM2TValueStrategy(new UpdateValueStrategy());
305
	}
306
307
	/**
308
	 * Creates a new model-to-target {@link UpdateValueStrategy} with the given
309
	 * update policy configured by the current state of this editing object.
310
	 * 
311
	 * @param updatePolicy
312
	 *            The update policy to use.
313
	 * @return A new model-to-target {@link UpdateValueStrategy} configured by
314
	 *         the current state of this editing object.
315
	 * 
316
	 * @see UpdateValueStrategy#UpdateValueStrategy(int)
317
	 * @see #applyToM2TValueStrategy(UpdateValueStrategy)
318
	 */
319
	public final UpdateValueStrategy createM2TValueStrategy(int updatePolicy) {
320
		return applyToM2TValueStrategy(new UpdateValueStrategy(updatePolicy));
321
	}
322
323
	/**
324
	 * Creates a new target-to-model {@link UpdateListStrategy} with a default
325
	 * update policy configured by the current state of this editing object.
326
	 * 
327
	 * @return A new target-to-model {@link UpdateListStrategy} configured by
328
	 *         the current state of this editing object.
329
	 * 
330
	 * @see UpdateListStrategy#UpdateListStrategy()
331
	 * @see #applyToT2MListStrategy(UpdateListStrategy)
332
	 */
333
	public final UpdateListStrategy createT2MListStrategy() {
334
		return applyToT2MListStrategy(new UpdateListStrategy());
335
	}
336
337
	/**
338
	 * Creates a new target-to-model {@link UpdateListStrategy} with the given
339
	 * update policy configured by the current state of this editing object.
340
	 * 
341
	 * @param updatePolicy
342
	 *            The update policy to use.
343
	 * @return A new target-to-model {@link UpdateListStrategy} configured by
344
	 *         the current state of this editing object.
345
	 * 
346
	 * @see UpdateListStrategy#UpdateListStrategy(int)
347
	 * @see #applyToT2MListStrategy(UpdateListStrategy)
348
	 */
349
	public final UpdateListStrategy createT2MListStrategy(int updatePolicy) {
350
		return applyToT2MListStrategy(new UpdateListStrategy(updatePolicy));
351
	}
352
353
	/**
354
	 * Creates a new model-to-target {@link UpdateListStrategy} with a default
355
	 * update policy configured by the current state of this editing object.
356
	 * 
357
	 * @return A new model-to-target {@link UpdateListStrategy} configured by
358
	 *         the current state of this editing object.
359
	 * 
360
	 * @see UpdateListStrategy#UpdateListStrategy()
361
	 * @see #applyToM2TListStrategy(UpdateListStrategy)
362
	 */
363
	public final UpdateListStrategy createM2TListStrategy() {
364
		return applyToM2TListStrategy(new UpdateListStrategy());
365
	}
366
367
	/**
368
	 * Creates a new model-to-target {@link UpdateListStrategy} with the given
369
	 * update policy configured by the current state of this editing object.
370
	 * 
371
	 * @param updatePolicy
372
	 *            The update policy to use.
373
	 * @return A new model-to-target {@link UpdateListStrategy} configured by
374
	 *         the current state of this editing object.
375
	 * 
376
	 * @see UpdateListStrategy#UpdateListStrategy(int)
377
	 * @see #applyToM2TListStrategy(UpdateListStrategy)
378
	 */
379
	public final UpdateListStrategy createM2TListStrategy(int updatePolicy) {
380
		return applyToM2TListStrategy(new UpdateListStrategy(updatePolicy));
381
	}
382
383
	/**
384
	 * Creates a new target-to-model {@link UpdateSetStrategy} with a default
385
	 * update policy configured by the current state of this editing object.
386
	 * 
387
	 * @return A new target-to-model {@link UpdateSetStrategy} configured by the
388
	 *         current state of this editing object.
389
	 * 
390
	 * @see UpdateListStrategy#UpdateListStrategy()
391
	 * @see #applyToT2MSetStrategy(UpdateSetStrategy)
392
	 */
393
	public final UpdateSetStrategy createT2MSetStrategy() {
394
		return applyToT2MSetStrategy(new UpdateSetStrategy());
395
	}
396
397
	/**
398
	 * Creates a new target-to-model {@link UpdateListStrategy} with the given
399
	 * update policy configured by the current state of this editing object.
400
	 * 
401
	 * @param updatePolicy
402
	 *            The update policy to use.
403
	 * @return A new target-to-model {@link UpdateListStrategy} configured by
404
	 *         the current state of this editing object.
405
	 * 
406
	 * @see UpdateSetStrategy#UpdateSetStrategy(int)
407
	 * @see #applyToT2MSetStrategy(UpdateSetStrategy)
408
	 */
409
	public final UpdateSetStrategy createT2MSetStrategy(int updatePolicy) {
410
		return applyToT2MSetStrategy(new UpdateSetStrategy(updatePolicy));
411
	}
412
413
	/**
414
	 * Creates a new model-to-target {@link UpdateSetStrategy} with a default
415
	 * update policy configured by the current state of this editing object.
416
	 * 
417
	 * @return A new model-to-target {@link UpdateSetStrategy} configured by the
418
	 *         current state of this editing object.
419
	 * 
420
	 * @see UpdateSetStrategy#UpdateSetStrategy()
421
	 * @see #applyToM2TSetStrategy(UpdateSetStrategy)
422
	 */
423
	public final UpdateSetStrategy createM2TSetStrategy() {
424
		return applyToM2TSetStrategy(new UpdateSetStrategy());
425
	}
426
427
	/**
428
	 * Creates a new model-to-target {@link UpdateSetStrategy} with the given
429
	 * update policy configured by the current state of this editing object.
430
	 * 
431
	 * @param updatePolicy
432
	 *            The update policy to use.
433
	 * @return A new model-to-target {@link UpdateSetStrategy} configured by the
434
	 *         current state of this editing object.
435
	 * 
436
	 * @see UpdateSetStrategy#UpdateSetStrategy(int)
437
	 * @see #applyToM2TSetStrategy(UpdateSetStrategy)
438
	 */
439
	public final UpdateSetStrategy createM2TSetStrategy(int updatePolicy) {
440
		return applyToM2TSetStrategy(new UpdateSetStrategy(updatePolicy));
441
	}
442
443
	/**
444
	 * Configures an existing target-to-model {@link UpdateValueStrategy} with
445
	 * the current state of this editing object.
446
	 * 
447
	 * <p>
448
	 * The configuration is done as follows:
449
	 * <ul>
450
	 * <li>
451
	 * The {@link Constraints#createValidator() validator} of the
452
	 * {@link #targetConstraints() target constraints} is set as the
453
	 * {@link UpdateValueStrategy#setAfterGetValidator(IValidator) after-get
454
	 * validator} of the update strategy.</li>
455
	 * <li>The {@link #setTargetConverter(IConverter) target converter} is set
456
	 * as the {@link UpdateValueStrategy#setConverter(IConverter) converter} of
457
	 * the update strategy.</li>
458
	 * <li>
459
	 * The {@link Constraints#createValidator() validator} of the
460
	 * {@link #modelConstraints() model constraints} is set as the
461
	 * {@link UpdateValueStrategy#setAfterConvertValidator(IValidator)
462
	 * after-convert validator} of the update strategy.</li>
463
	 * The {@link Constraints#createValidator() validator} of the
464
	 * {@link #beforeSetModelConstraints() before-set model constraints} is set
465
	 * as the {@link UpdateValueStrategy#setBeforeSetValidator(IValidator)
466
	 * before-set validator} of the update strategy.</li>
467
	 * </ul>
468
	 * </p>
469
	 * 
470
	 * @param updateStrategy
471
	 *            The {@link UpdateValueStrategy} to configure.
472
	 * @return The passed-in, configured target-to-model
473
	 *         {@link UpdateValueStrategy}.
474
	 * 
475
	 * @see UpdateValueStrategy#setAfterGetValidator(IValidator)
476
	 * @see UpdateValueStrategy#setConverter(IConverter)
477
	 * @see UpdateValueStrategy#setAfterConvertValidator(IValidator)
478
	 * @see UpdateValueStrategy#setBeforeSetValidator(IValidator)
479
	 */
480
	public final UpdateValueStrategy applyToT2MValueStrategy(
481
			UpdateValueStrategy updateStrategy) {
482
		updateStrategy.setAfterGetValidator(createValidator(targetConstraints));
483
		updateStrategy.setConverter(targetConverter);
484
		updateStrategy
485
				.setAfterConvertValidator(createValidator(modelConstraints));
486
		updateStrategy
487
				.setBeforeSetValidator(createValidator(beforeSetModelConstraints));
488
		return updateStrategy;
489
	}
490
491
	/**
492
	 * Configures an existing model-to-target {@link UpdateValueStrategy} with
493
	 * the current state of this editing object by setting the
494
	 * {@link #setModelConverter(IConverter) model converter} as the
495
	 * {@link UpdateValueStrategy#setConverter(IConverter) converter} of the
496
	 * update strategy.
497
	 * 
498
	 * @param updateStrategy
499
	 *            The {@link UpdateValueStrategy} to configure.
500
	 * @return The passed-in, configured model-to-target
501
	 *         {@link UpdateValueStrategy}.
502
	 * 
503
	 * @see UpdateValueStrategy#setConverter(IConverter)
504
	 */
505
	public final UpdateValueStrategy applyToM2TValueStrategy(
506
			UpdateValueStrategy updateStrategy) {
507
		updateStrategy.setConverter(modelConverter);
508
		return updateStrategy;
509
	}
510
511
	/**
512
	 * Configures an existing target-to-model {@link UpdateListStrategy} with
513
	 * the current state of this editing object by setting the
514
	 * {@link #setTargetConverter(IConverter) target converter} as the
515
	 * {@link UpdateListStrategy#setConverter(IConverter) converter} of the
516
	 * update strategy.
517
	 * 
518
	 * @param updateStrategy
519
	 *            The {@link UpdateListStrategy} to configure.
520
	 * @return The passed-in, configured target-to-model
521
	 *         {@link UpdateListStrategy}.
522
	 * 
523
	 * @see UpdateListStrategy#setConverter(IConverter)
524
	 */
525
	public final UpdateListStrategy applyToT2MListStrategy(
526
			UpdateListStrategy updateStrategy) {
527
		updateStrategy.setConverter(targetConverter);
528
		return updateStrategy;
529
	}
530
531
	/**
532
	 * Configures an existing model-to-target {@link UpdateListStrategy} with
533
	 * the current state of this editing object by setting the
534
	 * {@link #setModelConverter(IConverter) model converter} as the
535
	 * {@link UpdateListStrategy#setConverter(IConverter) converter} of the
536
	 * update strategy.
537
	 * 
538
	 * @param updateStrategy
539
	 *            The {@link UpdateListStrategy} to configure.
540
	 * @return The passed-in, configured model-to-target
541
	 *         {@link UpdateListStrategy}.
542
	 * 
543
	 * @see UpdateListStrategy#setConverter(IConverter)
544
	 */
545
	public final UpdateListStrategy applyToM2TListStrategy(
546
			UpdateListStrategy updateStrategy) {
547
		updateStrategy.setConverter(modelConverter);
548
		return updateStrategy;
549
	}
550
551
	/**
552
	 * Configures an existing target-to-model {@link UpdateListStrategy} with
553
	 * the current state of this editing object by setting the
554
	 * {@link #setTargetConverter(IConverter) target converter} as the
555
	 * {@link UpdateSetStrategy#setConverter(IConverter) converter} of the
556
	 * update strategy.
557
	 * 
558
	 * @param updateStrategy
559
	 *            The {@link UpdateSetStrategy} to configure.
560
	 * @return The passed-in, configured target-to-model
561
	 *         {@link UpdateSetStrategy}.
562
	 * 
563
	 * @see UpdateSetStrategy#setConverter(IConverter)
564
	 */
565
	public final UpdateSetStrategy applyToT2MSetStrategy(
566
			UpdateSetStrategy updateStrategy) {
567
		updateStrategy.setConverter(targetConverter);
568
		return updateStrategy;
569
	}
570
571
	/**
572
	 * Configures an existing model-to-target {@link UpdateSetStrategy} with the
573
	 * current state of this editing object by setting the
574
	 * {@link #setModelConverter(IConverter) model converter} as the
575
	 * {@link UpdateSetStrategy#setConverter(IConverter) converter} of the
576
	 * update strategy.
577
	 * 
578
	 * @param updateStrategy
579
	 *            The {@link UpdateSetStrategy} to configure.
580
	 * @return The passed-in, configured model-to-target
581
	 *         {@link UpdateSetStrategy}.
582
	 * 
583
	 * @see UpdateSetStrategy#setConverter(IConverter)
584
	 */
585
	public final UpdateSetStrategy applyToM2TSetStrategy(
586
			UpdateSetStrategy updateStrategy) {
587
		updateStrategy.setConverter(modelConverter);
588
		return updateStrategy;
589
	}
590
591
	/**
592
	 * Converts a target value to a model value by performing the following
593
	 * steps:
594
	 * <ul>
595
	 * <li>
596
	 * Applying all the {@link #targetConstraints() target constraints} to the
597
	 * given target value.</li>
598
	 * <li>
599
	 * {@link #setTargetConverter(IConverter) Converting} the target value to
600
	 * the model value.</li>
601
	 * <li>
602
	 * Applying all the {@link #modelConstraints() model constraints} to the
603
	 * converted model value.</li>
604
	 * <li>
605
	 * Applying all the {@link #beforeSetModelConstraints() before-set model
606
	 * constraints} to the converted model value.</li>
607
	 * </ul>
608
	 * 
609
	 * <p>
610
	 * The conversion process will be aborted by returning <code>null</code>
611
	 * whenever any of the applied validators produces a {@link IStatus
612
	 * validation status} having {@link IStatus#getSeverity() severity}
613
	 * <code>IStatus.ERROR</code> or <code>IStatus.CANCEL</code>. During the
614
	 * conversion process, any validation status whose severity is different
615
	 * from <code>IStatus.OK</code> will be {@link MultiStatus#merge(IStatus)
616
	 * aggregated} on the given <code>validationStatus</code>.
617
	 * </p>
618
	 * 
619
	 * @param targetValue
620
	 *            The target value to be converted to a model value.
621
	 * @param validationStatus
622
	 *            Aggregate validation status to which to add the validations
623
	 *            produced during the conversion process.
624
	 * @return The converted model value or <code>null</code> in case the
625
	 *         conversion has been aborted due to a validation error.
626
	 */
627
	public final Object convertToModel(Object targetValue,
628
			MultiStatus validationStatus) {
629
		IValidator targetValidator = createValidator(targetConstraints);
630
		if (!applyValidator(targetValidator, targetValue, validationStatus)) {
631
			return null;
632
		}
633
634
		Object modelValue = (targetConverter != null) ? targetConverter
635
				.convert(targetValue) : targetValue;
636
637
		IValidator modelValidator = createValidator(modelConstraints);
638
		if (!applyValidator(modelValidator, modelValue, validationStatus)) {
639
			return null;
640
		}
641
642
		IValidator beforeSetModelValidator = createValidator(beforeSetModelConstraints);
643
		if (!applyValidator(beforeSetModelValidator, modelValue,
644
				validationStatus)) {
645
			return null;
646
		}
647
648
		return modelValue;
649
	}
650
651
	/**
652
	 * {@link #setModelConverter(IConverter) Converts} a model value to a target
653
	 * value.
654
	 * 
655
	 * @param modelValue
656
	 *            The model value to be converted to a target value.
657
	 * @return The converted target value.
658
	 */
659
	public final Object convertToTarget(Object modelValue) {
660
		return (modelConverter != null) ? modelConverter.convert(modelValue)
661
				: modelValue;
662
	}
663
664
	/**
665
	 * Creates a binding between a target and model observable value on the
666
	 * given binding context by creating new update strategies which will be
667
	 * both configured with the state of this editing object before passing them
668
	 * to the binding.
669
	 * 
670
	 * <p>
671
	 * The target-to-model and model-to-target update strategies for the binding
672
	 * will be created by the methods {@link #createT2MValueStrategy()} and
673
	 * {@link #createM2TValueStrategy()}, respectively.
674
	 * </p>
675
	 * 
676
	 * @param dbc
677
	 *            The binding context on which to create the value binding.
678
	 * @param targetObservableValue
679
	 *            The target observable value of the binding.
680
	 * @param modelObservableValue
681
	 *            The model observable value of the binding.
682
	 * @return The new value binding.
683
	 * 
684
	 * @see #createT2MValueStrategy()
685
	 * @see #createM2TValueStrategy()
686
	 * @see DataBindingContext#bindValue(IObservableValue, IObservableValue,
687
	 *      UpdateValueStrategy, UpdateValueStrategy)
688
	 */
689
	public final Binding bindValue(DataBindingContext dbc,
690
			IObservableValue targetObservableValue,
691
			IObservableValue modelObservableValue) {
692
		return dbc.bindValue(targetObservableValue, modelObservableValue,
693
				createT2MValueStrategy(), createM2TValueStrategy());
694
	}
695
696
	/**
697
	 * Creates a binding between a target and model observable value on the
698
	 * given binding context by creating new update strategies with the provided
699
	 * update policies which will be both configured with the state of this
700
	 * editing object before passing them to the binding.
701
	 * 
702
	 * @param dbc
703
	 *            The binding context on which to create the value binding.
704
	 * @param targetObservableValue
705
	 *            The target observable value of the binding.
706
	 * @param modelObservableValue
707
	 *            The model observable value of the binding.
708
	 * @param t2mUpdatePolicy
709
	 *            The update policy for the target-to-model
710
	 *            {@link UpdateValueStrategy} which is
711
	 *            {@link #createT2MValueStrategy(int) created} and passed to the
712
	 *            new binding.
713
	 * @param m2tUpdatePolicy
714
	 *            The update policy for the model-to-target
715
	 *            {@link UpdateValueStrategy} which is
716
	 *            {@link #createM2TValueStrategy(int) created} and passed to the
717
	 *            new binding.
718
	 * @return The new value binding.
719
	 * 
720
	 * @see #createT2MValueStrategy(int)
721
	 * @see #createM2TValueStrategy(int)
722
	 * @see DataBindingContext#bindValue(IObservableValue, IObservableValue,
723
	 *      UpdateValueStrategy, UpdateValueStrategy)
724
	 */
725
	public final Binding bindValue(DataBindingContext dbc,
726
			IObservableValue targetObservableValue,
727
			IObservableValue modelObservableValue, int t2mUpdatePolicy,
728
			int m2tUpdatePolicy) {
729
		return dbc.bindValue(targetObservableValue, modelObservableValue,
730
				createT2MValueStrategy(t2mUpdatePolicy),
731
				createM2TValueStrategy(m2tUpdatePolicy));
732
	}
733
734
	/**
735
	 * Creates a binding between a target and model observable value on the
736
	 * given binding context by using the provided update strategies which will
737
	 * be both configured with the state of this editing object before passing
738
	 * them to the binding.
739
	 * 
740
	 * @param dbc
741
	 *            The binding context on which to create the value binding.
742
	 * @param targetObservableValue
743
	 *            The target observable value of the binding.
744
	 * @param modelObservableValue
745
	 *            The model observable value of the binding.
746
	 * @param t2mUpdateStrategy
747
	 *            The target-to-model {@link UpdateValueStrategy} of the binding
748
	 *            to be {@link #applyToT2MValueStrategy(UpdateValueStrategy)
749
	 *            configured} with the state of this editing object before
750
	 *            passing it to the binding.
751
	 * @param m2tUpdateStrategy
752
	 *            The model-to-target {@link UpdateValueStrategy} of the binding
753
	 *            to be {@link #applyToM2TValueStrategy(UpdateValueStrategy)
754
	 *            configured} with the state of this editing object before
755
	 *            passing it to the binding.
756
	 * @return The new value binding.
757
	 * 
758
	 * @see #applyToT2MValueStrategy(UpdateValueStrategy)
759
	 * @see #applyToM2TValueStrategy(UpdateValueStrategy)
760
	 * @see DataBindingContext#bindValue(IObservableValue, IObservableValue,
761
	 *      UpdateValueStrategy, UpdateValueStrategy)
762
	 */
763
	public final Binding bindValue(DataBindingContext dbc,
764
			IObservableValue targetObservableValue,
765
			IObservableValue modelObservableValue,
766
			UpdateValueStrategy t2mUpdateStrategy,
767
			UpdateValueStrategy m2tUpdateStrategy) {
768
		return dbc.bindValue(targetObservableValue, modelObservableValue,
769
				applyToT2MValueStrategy(t2mUpdateStrategy),
770
				applyToM2TValueStrategy(m2tUpdateStrategy));
771
	}
772
773
	/**
774
	 * Creates a binding between a target and model observable list on the given
775
	 * binding context by creating new update strategies which will be both
776
	 * configured with the state of this editing object before passing them to
777
	 * the binding.
778
	 * 
779
	 * <p>
780
	 * The target-to-model and model-to-target update strategies for the binding
781
	 * will be created by the methods {@link #createT2MListStrategy()} and
782
	 * {@link #createM2TListStrategy()}, respectively.
783
	 * </p>
784
	 * 
785
	 * @param dbc
786
	 *            The binding context on which to create the list binding.
787
	 * @param targetObservableList
788
	 *            The target observable list of the binding.
789
	 * @param modelObservableList
790
	 *            The model observable list of the binding.
791
	 * @return The new list binding.
792
	 * 
793
	 * @see #createT2MListStrategy()
794
	 * @see #createM2TListStrategy()
795
	 * @see DataBindingContext#bindList(IObservableList, IObservableList,
796
	 *      UpdateListStrategy, UpdateListStrategy)
797
	 */
798
	public final Binding bindList(DataBindingContext dbc,
799
			IObservableList targetObservableList,
800
			IObservableList modelObservableList) {
801
		return dbc.bindList(targetObservableList, modelObservableList,
802
				createT2MListStrategy(), createM2TListStrategy());
803
	}
804
805
	/**
806
	 * Creates a binding between a target and model observable list on the given
807
	 * binding context by creating new update strategies with the provided
808
	 * update policies which will be both configured with the state of this
809
	 * editing object before passing them to the binding.
810
	 * 
811
	 * @param dbc
812
	 *            The binding context on which to create the list binding.
813
	 * @param targetObservableList
814
	 *            The target observable list of the binding.
815
	 * @param modelObservableList
816
	 *            The model observable list of the binding.
817
	 * @param t2mUpdatePolicy
818
	 *            The update policy for the target-to-model
819
	 *            {@link UpdateListStrategy} which is
820
	 *            {@link #createT2MListStrategy(int) created} and passed to the
821
	 *            new binding.
822
	 * @param m2tUpdatePolicy
823
	 *            The update policy for the model-to-target
824
	 *            {@link UpdateListStrategy} which is
825
	 *            {@link #createM2TListStrategy(int) created} and passed to the
826
	 *            new binding.
827
	 * @return The new list binding.
828
	 * 
829
	 * @see #createT2MListStrategy(int)
830
	 * @see #createM2TListStrategy(int)
831
	 * @see DataBindingContext#bindList(IObservableList, IObservableList,
832
	 *      UpdateListStrategy, UpdateListStrategy)
833
	 */
834
	public final Binding bindList(DataBindingContext dbc,
835
			IObservableList targetObservableList,
836
			IObservableList modelObservableList, int t2mUpdatePolicy,
837
			int m2tUpdatePolicy) {
838
		return dbc.bindList(targetObservableList, modelObservableList,
839
				createT2MListStrategy(t2mUpdatePolicy),
840
				createM2TListStrategy(m2tUpdatePolicy));
841
	}
842
843
	/**
844
	 * Creates a binding between a target and model observable list on the given
845
	 * binding context by using the provided update strategies which will be
846
	 * both configured with the state of this editing object before passing them
847
	 * to the binding.
848
	 * 
849
	 * @param dbc
850
	 *            The binding context on which to create the list binding.
851
	 * @param targetObservableList
852
	 *            The target observable list of the binding.
853
	 * @param modelObservableList
854
	 *            The model observable list of the binding.
855
	 * @param t2mUpdateStrategy
856
	 *            The target-to-model {@link UpdateListStrategy} of the binding
857
	 *            to be {@link #applyToT2MListStrategy(UpdateListStrategy)
858
	 *            configured} with the state of this editing object before
859
	 *            passing it to the binding.
860
	 * @param m2tUpdateStrategy
861
	 *            The model-to-target {@link UpdateListStrategy} of the binding
862
	 *            to be {@link #applyToM2TListStrategy(UpdateListStrategy)
863
	 *            configured} with the state of this editing object before
864
	 *            passing it to the binding.
865
	 * @return The new list binding.
866
	 * 
867
	 * @see #applyToT2MListStrategy(UpdateListStrategy)
868
	 * @see #applyToM2TListStrategy(UpdateListStrategy)
869
	 * @see DataBindingContext#bindList(IObservableList, IObservableList,
870
	 *      UpdateListStrategy, UpdateListStrategy)
871
	 */
872
	public final Binding bindList(DataBindingContext dbc,
873
			IObservableList targetObservableList,
874
			IObservableList modelObservableList,
875
			UpdateListStrategy t2mUpdateStrategy,
876
			UpdateListStrategy m2tUpdateStrategy) {
877
		return dbc.bindList(targetObservableList, modelObservableList,
878
				applyToT2MListStrategy(t2mUpdateStrategy),
879
				applyToM2TListStrategy(m2tUpdateStrategy));
880
	}
881
882
	/**
883
	 * Creates a binding between a target and model observable set on the given
884
	 * binding context by creating new update strategies which will be both
885
	 * configured with the state of this editing object before passing them to
886
	 * the binding.
887
	 * 
888
	 * <p>
889
	 * The target-to-model and model-to-target update strategies for the binding
890
	 * will be created by the methods {@link #createT2MSetStrategy()} and
891
	 * {@link #createM2TSetStrategy()}, respectively.
892
	 * </p>
893
	 * 
894
	 * @param dbc
895
	 *            The binding context on which to create the set binding.
896
	 * @param targetObservableSet
897
	 *            The target observable set of the binding.
898
	 * @param modelObservableSet
899
	 *            The model observable set of the binding.
900
	 * @return The new set binding.
901
	 * 
902
	 * @see #createT2MSetStrategy()
903
	 * @see #createM2TSetStrategy()
904
	 * @see DataBindingContext#bindSet(IObservableSet, IObservableSet,
905
	 *      UpdateSetStrategy, UpdateSetStrategy)
906
	 */
907
	public final Binding bindSet(DataBindingContext dbc,
908
			IObservableSet targetObservableSet,
909
			IObservableSet modelObservableSet) {
910
		return dbc.bindSet(targetObservableSet, modelObservableSet,
911
				createT2MSetStrategy(), createM2TSetStrategy());
912
	}
913
914
	/**
915
	 * Creates a binding between a target and model observable set on the given
916
	 * binding context by creating new update strategies with the provided
917
	 * update policies which will be both configured with the state of this
918
	 * editing object before passing them to the binding.
919
	 * 
920
	 * @param dbc
921
	 *            The binding context on which to create the set binding.
922
	 * @param targetObservableSet
923
	 *            The target observable set of the binding.
924
	 * @param modelObservableSet
925
	 *            The model observable set of the binding.
926
	 * @param t2mUpdatePolicy
927
	 *            The update policy for the target-to-model
928
	 *            {@link UpdateSetStrategy} which is
929
	 *            {@link #createT2MSetStrategy(int) created} and passed to the
930
	 *            new binding.
931
	 * @param m2tUpdatePolicy
932
	 *            The update policy for the model-to-target
933
	 *            {@link UpdateSetStrategy} which is
934
	 *            {@link #createM2TSetStrategy(int) created} and passed to the
935
	 *            new binding.
936
	 * @return The new set binding.
937
	 * 
938
	 * @see #createT2MSetStrategy(int)
939
	 * @see #createM2TSetStrategy(int)
940
	 * @see DataBindingContext#bindSet(IObservableSet, IObservableSet,
941
	 *      UpdateSetStrategy, UpdateSetStrategy)
942
	 */
943
	public final Binding bindSet(DataBindingContext dbc,
944
			IObservableSet targetObservableSet,
945
			IObservableSet modelObservableSet, int t2mUpdatePolicy,
946
			int m2tUpdatePolicy) {
947
		return dbc.bindSet(targetObservableSet, modelObservableSet,
948
				createT2MSetStrategy(t2mUpdatePolicy),
949
				createM2TSetStrategy(m2tUpdatePolicy));
950
	}
951
952
	/**
953
	 * Creates a binding between a target and model observable set on the given
954
	 * binding context by using the provided update strategies which will be
955
	 * both configured with the state of this editing object before passing them
956
	 * to the binding.
957
	 * 
958
	 * @param dbc
959
	 *            The binding context on which to create the set binding.
960
	 * @param targetObservableSet
961
	 *            The target observable set of the binding.
962
	 * @param modelObservableSet
963
	 *            The model observable set of the binding.
964
	 * @param t2mUpdateStrategy
965
	 *            The target-to-model {@link UpdateSetStrategy} of the binding
966
	 *            to be {@link #applyToT2MSetStrategy(UpdateSetStrategy)
967
	 *            configured} with the state of this editing object before
968
	 *            passing it to the binding.
969
	 * @param m2tUpdateStrategy
970
	 *            The model-to-target {@link UpdateSetStrategy} of the binding
971
	 *            to be {@link #applyToM2TSetStrategy(UpdateSetStrategy)
972
	 *            configured} with the state of this editing object before
973
	 *            passing it to the binding.
974
	 * @return The new set binding.
975
	 * 
976
	 * @see #applyToT2MSetStrategy(UpdateSetStrategy)
977
	 * @see #applyToM2TSetStrategy(UpdateSetStrategy)
978
	 * @see DataBindingContext#bindSet(IObservableSet, IObservableSet,
979
	 *      UpdateSetStrategy, UpdateSetStrategy)
980
	 */
981
	public final Binding bindSet(DataBindingContext dbc,
982
			IObservableSet targetObservableSet,
983
			IObservableSet modelObservableSet,
984
			UpdateSetStrategy t2mUpdateStrategy,
985
			UpdateSetStrategy m2tUpdateStrategy) {
986
		return dbc.bindSet(targetObservableSet, modelObservableSet,
987
				applyToT2MSetStrategy(t2mUpdateStrategy),
988
				applyToM2TSetStrategy(m2tUpdateStrategy));
989
	}
990
991
	private static IValidator createValidator(Constraints constraints) {
992
		return constraints != null ? constraints.createValidator() : null;
993
	}
994
995
	private static boolean applyValidator(IValidator validator, Object value,
996
			MultiStatus aggregateStatus) {
997
		if (validator != null) {
998
			IStatus validationStatus = validator.validate(value);
999
			if (!validationStatus.isOK()) {
1000
				aggregateStatus.merge(validationStatus);
1001
			}
1002
			return isValid(validationStatus);
1003
		}
1004
		return true;
1005
	}
1006
1007
	private static boolean isValid(IStatus status) {
1008
		return status.isOK() || status.matches(IStatus.INFO | IStatus.WARNING);
1009
	}
1010
}
(-)src/org/eclipse/core/databinding/editing/DateEditing.java (+254 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Ovidio Mallo 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
 *     Ovidio Mallo - initial API and implementation (bug 183055)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.editing;
13
14
import java.util.Date;
15
16
import org.eclipse.core.databinding.validation.constraint.Constraints;
17
import org.eclipse.core.databinding.validation.constraint.DateConstraints;
18
import org.eclipse.core.databinding.validation.constraint.StringConstraints;
19
import org.eclipse.core.internal.databinding.conversion.DateToStringConverter;
20
import org.eclipse.core.internal.databinding.conversion.StringToDateConverter;
21
import org.eclipse.core.internal.databinding.validation.StringToDateValidator;
22
23
import com.ibm.icu.text.DateFormat;
24
25
/**
26
 * @since 1.3
27
 */
28
public final class DateEditing extends Editing {
29
30
	private final DateFormat displayFormat;
31
32
	private DateEditing(DateFormat[] inputFormats, String parseErrorMessage,
33
			DateFormat displayFormat) {
34
		this.displayFormat = displayFormat;
35
36
		StringToDateConverter targetConverter;
37
		if (inputFormats == null) {
38
			targetConverter = new StringToDateConverter();
39
		} else {
40
			targetConverter = new StringToDateConverter(inputFormats);
41
		}
42
43
		targetConstraints().addValidator(
44
				new StringToDateValidator(targetConverter, parseErrorMessage));
45
		setTargetConverter(targetConverter);
46
		setModelConverter(displayFormat == null ? new DateToStringConverter()
47
				: new DateToStringConverter(displayFormat));
48
	}
49
50
	/**
51
	 * Creates a new editing object which defaults the validations and
52
	 * conversions used for editing. Uses the default validation message.
53
	 * 
54
	 * @return The new editing object using the default validations and
55
	 *         conversions for editing.
56
	 */
57
	public static DateEditing withDefaults() {
58
		return withDefaults(null);
59
	}
60
61
	/**
62
	 * Creates a new editing object which defaults the validations and
63
	 * conversions used for editing. Uses the specified custom validation
64
	 * message.
65
	 * 
66
	 * @param parseErrorMessage
67
	 *            The validation message issued in case the input string cannot
68
	 *            be parsed to a date.
69
	 * @return The new editing object using the default validations and
70
	 *         conversions for editing.
71
	 */
72
	public static DateEditing withDefaults(String parseErrorMessage) {
73
		return new DateEditing(null, parseErrorMessage, null);
74
	}
75
76
	/**
77
	 * Creates a new editing object which supports all the given date input
78
	 * formats and which uses the specified format for displaying a date. Uses
79
	 * the default validation message.
80
	 * 
81
	 * @param inputFormats
82
	 *            The date formats supported for reading in dates.
83
	 * @param displayFormat
84
	 *            The date format for displaying dates.
85
	 * @return The new editing object configured by the given date formats.
86
	 */
87
	public static DateEditing forFormats(DateFormat[] inputFormats,
88
			DateFormat displayFormat) {
89
		return new DateEditing(inputFormats, null, displayFormat);
90
	}
91
92
	/**
93
	 * Creates a new editing object which supports all the given date input
94
	 * formats and which uses the specified format for displaying a date. Uses
95
	 * the specified custom validation message.
96
	 * 
97
	 * @param inputFormats
98
	 *            The date formats supported for reading in dates.
99
	 * @param parseErrorMessage
100
	 *            The validation message issued in case the input string cannot
101
	 *            be parsed to a date.
102
	 * @param displayFormat
103
	 *            The date format for displaying dates.
104
	 * @return The new editing object configured by the given date formats.
105
	 */
106
	public static DateEditing forFormats(DateFormat[] inputFormats,
107
			String parseErrorMessage, DateFormat displayFormat) {
108
		return new DateEditing(inputFormats, parseErrorMessage, displayFormat);
109
	}
110
111
	/**
112
	 * Returns the target constraints to apply.
113
	 * 
114
	 * <p>
115
	 * This method provides a typesafe access to the {@link StringConstraints
116
	 * string target constraints} of this editing object and is equivalent to
117
	 * {@code (StringConstraints) targetConstraints()}.
118
	 * </p>
119
	 * 
120
	 * @return The target constraints to apply.
121
	 * 
122
	 * @see #targetConstraints()
123
	 * @see StringConstraints
124
	 */
125
	public StringConstraints targetStringConstraints() {
126
		return (StringConstraints) targetConstraints();
127
	}
128
129
	/**
130
	 * Returns the model constraints to apply.
131
	 * 
132
	 * <p>
133
	 * This method provides a typesafe access to the {@link DateConstraints date
134
	 * model constraints} of this editing object and is equivalent to {@code
135
	 * (DateConstraints) modelConstraints()}.
136
	 * </p>
137
	 * 
138
	 * @return The target constraints to apply.
139
	 * 
140
	 * @see #modelConstraints()
141
	 * @see DateConstraints
142
	 */
143
	public DateConstraints modelDateConstraints() {
144
		return (DateConstraints) modelConstraints();
145
	}
146
147
	/**
148
	 * Returns the before-set model constraints to apply.
149
	 * 
150
	 * <p>
151
	 * This method provides a typesafe access to the {@link DateConstraints date
152
	 * before-set model constraints} of this editing object and is equivalent to
153
	 * {@code (DateConstraints) beforeSetModelConstraints()}.
154
	 * </p>
155
	 * 
156
	 * @return The target constraints to apply.
157
	 * 
158
	 * @see #beforeSetModelConstraints()
159
	 * @see DateConstraints
160
	 */
161
	public DateConstraints beforeSetModelDateConstraints() {
162
		return (DateConstraints) beforeSetModelConstraints();
163
	}
164
165
	protected Constraints createTargetConstraints() {
166
		return new StringConstraints();
167
	}
168
169
	protected Constraints createModelConstraints() {
170
		return new DateConstraints(displayFormat);
171
	}
172
173
	protected Constraints createBeforeSetModelConstraints() {
174
		return new DateConstraints(displayFormat);
175
	}
176
177
	/**
178
	 * Convenience method which adds a {@link DateConstraints#required()
179
	 * required constraint} to the set of {@link #modelDateConstraints()}.
180
	 * 
181
	 * @return This editing instance for method chaining.
182
	 * 
183
	 * @see DateConstraints#required()
184
	 * @see #modelDateConstraints()
185
	 */
186
	public DateEditing required() {
187
		modelDateConstraints().required();
188
		return this;
189
	}
190
191
	/**
192
	 * Convenience method which adds a {@link DateConstraints#after(Date) after
193
	 * constraint} to the set of {@link #modelDateConstraints()}.
194
	 * 
195
	 * @param date
196
	 *            The date of the after constraint.
197
	 * @return This editing instance for method chaining.
198
	 * 
199
	 * @see DateConstraints#after(Date)
200
	 * @see #modelDateConstraints()
201
	 */
202
	public DateEditing after(Date date) {
203
		modelDateConstraints().after(date);
204
		return this;
205
	}
206
207
	/**
208
	 * Convenience method which adds a {@link DateConstraints#afterEqual(Date)
209
	 * after-equal constraint} to the set of {@link #modelDateConstraints()}.
210
	 * 
211
	 * @param date
212
	 *            The date of the after-equal constraint.
213
	 * @return This editing instance for method chaining.
214
	 * 
215
	 * @see DateConstraints#afterEqual(Date)
216
	 * @see #modelDateConstraints()
217
	 */
218
	public DateEditing afterEqual(Date date) {
219
		modelDateConstraints().afterEqual(date);
220
		return this;
221
	}
222
223
	/**
224
	 * Convenience method which adds a {@link DateConstraints#before(Date)
225
	 * before constraint} to the set of {@link #modelDateConstraints()}.
226
	 * 
227
	 * @param date
228
	 *            The date of the before constraint.
229
	 * @return This editing instance for method chaining.
230
	 * 
231
	 * @see DateConstraints#before(Date)
232
	 * @see #modelDateConstraints()
233
	 */
234
	public DateEditing before(Date date) {
235
		modelDateConstraints().before(date);
236
		return this;
237
	}
238
239
	/**
240
	 * Convenience method which adds a {@link DateConstraints#beforeEqual(Date)
241
	 * after-equal constraint} to the set of {@link #modelDateConstraints()}.
242
	 * 
243
	 * @param date
244
	 *            The date of the after-equal constraint.
245
	 * @return This editing instance for method chaining.
246
	 * 
247
	 * @see DateConstraints#afterEqual(Date)
248
	 * @see #modelDateConstraints()
249
	 */
250
	public DateEditing beforeEqual(Date date) {
251
		modelDateConstraints().beforeEqual(date);
252
		return this;
253
	}
254
}
(-)src/org/eclipse/core/internal/databinding/conversion/StringStripConverter.java (+61 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Ovidio Mallo 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
 *     Ovidio Mallo - initial API and implementation (bug 183055)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.conversion;
13
14
import org.eclipse.core.databinding.conversion.Converter;
15
16
/**
17
 * @since 1.3
18
 */
19
public class StringStripConverter extends Converter {
20
21
	private final boolean stripToNull;
22
23
	/**
24
	 * 
25
	 * @param stripToNull
26
	 */
27
	public StringStripConverter(boolean stripToNull) {
28
		super(String.class, String.class);
29
		this.stripToNull = stripToNull;
30
	}
31
32
	public Object convert(Object fromObject) {
33
		String string = (String) fromObject;
34
35
		if (string != null && string.length() != 0) {
36
			int stripStart = 0;
37
			while (stripStart < string.length()
38
					&& Character.isWhitespace(string.charAt(stripStart))) {
39
				stripStart++;
40
			}
41
42
			int stripEnd = string.length() - 1;
43
			while (stripEnd >= 0
44
					&& Character.isWhitespace(string.charAt(stripEnd))) {
45
				stripEnd--;
46
			}
47
48
			if (stripStart <= stripEnd) {
49
				string = string.substring(stripStart, stripEnd + 1);
50
			} else {
51
				string = ""; //$NON-NLS-1$
52
			}
53
		}
54
55
		if (stripToNull && string != null && string.length() == 0) {
56
			string = null;
57
		}
58
59
		return string;
60
	}
61
}
(-)src/org/eclipse/core/internal/databinding/validation/DateRangeValidator.java (+184 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Ovidio Mallo 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
 *     Ovidio Mallo - initial API and implementation (bug 183055)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.validation;
13
14
import java.text.MessageFormat;
15
import java.util.Date;
16
17
import org.eclipse.core.databinding.validation.IValidator;
18
import org.eclipse.core.databinding.validation.ValidationStatus;
19
import org.eclipse.core.runtime.IStatus;
20
21
import com.ibm.icu.text.DateFormat;
22
23
/**
24
 * @since 1.3
25
 */
26
public class DateRangeValidator implements IValidator {
27
28
	private static final int UNDEFINED = -1;
29
	private static final int AFTER = 0;
30
	private static final int AFTER_EQUAL = 1;
31
	private static final int BEFORE = 2;
32
	private static final int BEFORE_EQUAL = 3;
33
34
	// TODO: Externalize
35
	private static final String AFTER_MESSAGE = "The date must be after {0}."; //$NON-NLS-1$
36
	private static final String AFTER_EQUAL_MESSAGE = "The date must be after or on {0}."; //$NON-NLS-1$
37
	private static final String BEFORE_MESSAGE = "The date must be before {0}."; //$NON-NLS-1$
38
	private static final String BEFORE_EQUAL_MESSAGE = "The date must be before or on {0}."; //$NON-NLS-1$
39
	private static final String WITHIN_RANGE_MESSAGE = "The date must lie between {0} and {1}."; //$NON-NLS-1$
40
41
	private final Date min;
42
	private final Date max;
43
	private final int minConstraint;
44
	private final int maxConstraint;
45
	private final String validationMessage;
46
	private String formattedValidationMessage;
47
	private final DateFormat format;
48
49
	/**
50
	 * 
51
	 * @param min
52
	 * @param max
53
	 * @param minConstraint
54
	 * @param maxConstraint
55
	 * @param validationMessage
56
	 * @param format
57
	 */
58
	private DateRangeValidator(Date min, Date max, int minConstraint,
59
			int maxConstraint, String validationMessage, DateFormat format) {
60
		this.min = min;
61
		this.max = max;
62
		this.minConstraint = minConstraint;
63
		this.maxConstraint = maxConstraint;
64
		this.validationMessage = validationMessage;
65
		this.format = format;
66
	}
67
68
	/**
69
	 * 
70
	 * @param min
71
	 * @param validationMessage
72
	 * @param format
73
	 * @return .
74
	 */
75
	public static DateRangeValidator after(Date min, String validationMessage,
76
			DateFormat format) {
77
		return new DateRangeValidator(min, null, AFTER, UNDEFINED,
78
				defaultIfNull(validationMessage, AFTER_MESSAGE), format);
79
	}
80
81
	/**
82
	 * 
83
	 * @param min
84
	 * @param validationMessage
85
	 * @param format
86
	 * @return .
87
	 */
88
	public static DateRangeValidator afterEqual(Date min,
89
			String validationMessage, DateFormat format) {
90
		return new DateRangeValidator(min, null, AFTER_EQUAL, UNDEFINED,
91
				defaultIfNull(validationMessage, AFTER_EQUAL_MESSAGE), format);
92
	}
93
94
	/**
95
	 * 
96
	 * @param max
97
	 * @param validationMessage
98
	 * @param format
99
	 * @return .
100
	 */
101
	public static DateRangeValidator before(Date max, String validationMessage,
102
			DateFormat format) {
103
		return new DateRangeValidator(null, max, UNDEFINED, BEFORE,
104
				defaultIfNull(validationMessage, BEFORE_MESSAGE), format);
105
	}
106
107
	/**
108
	 * 
109
	 * @param max
110
	 * @param validationMessage
111
	 * @param format
112
	 * @return .
113
	 */
114
	public static DateRangeValidator beforeEqual(Date max,
115
			String validationMessage, DateFormat format) {
116
		return new DateRangeValidator(null, max, UNDEFINED, BEFORE_EQUAL,
117
				defaultIfNull(validationMessage, BEFORE_EQUAL_MESSAGE), format);
118
	}
119
120
	/**
121
	 * 
122
	 * @param min
123
	 * @param max
124
	 * @param validationMessage
125
	 * @param format
126
	 * @return .
127
	 */
128
	public static DateRangeValidator range(Date min, Date max,
129
			String validationMessage, DateFormat format) {
130
		return new DateRangeValidator(min, max, AFTER_EQUAL, BEFORE_EQUAL,
131
				defaultIfNull(validationMessage, WITHIN_RANGE_MESSAGE), format);
132
	}
133
134
	public IStatus validate(Object value) {
135
		if (value != null) {
136
			Date date = (Date) value;
137
			if ((min != null && !fulfillsConstraint(date, min, minConstraint))
138
					|| (max != null && !fulfillsConstraint(date, max,
139
							maxConstraint))) {
140
				return ValidationStatus.error(getFormattedValidationMessage());
141
			}
142
		}
143
		return ValidationStatus.ok();
144
	}
145
146
	private boolean fulfillsConstraint(Date date1, Date date2, int constraint) {
147
		switch (constraint) {
148
		case AFTER:
149
			return date1.after(date2);
150
		case AFTER_EQUAL:
151
			return date1.after(date2) || date1.equals(date2);
152
		case BEFORE:
153
			return date1.before(date2);
154
		case BEFORE_EQUAL:
155
			return date1.before(date2) || date1.equals(date2);
156
		case UNDEFINED:
157
		default:
158
			throw new IllegalArgumentException(
159
					"Unsupported constraint: " + constraint); //$NON-NLS-1$
160
		}
161
	}
162
163
	private String getFormattedValidationMessage() {
164
		if (formattedValidationMessage == null) {
165
			formattedValidationMessage = MessageFormat.format(
166
					validationMessage, getValidationMessageArguments());
167
		}
168
		return formattedValidationMessage;
169
	}
170
171
	private String[] getValidationMessageArguments() {
172
		// TODO: Synchronize formatting to make it thread safe?
173
		if (min == null) {
174
			return new String[] { format.format(max) };
175
		} else if (max == null) {
176
			return new String[] { format.format(min) };
177
		}
178
		return new String[] { format.format(min), format.format(max) };
179
	}
180
181
	private static String defaultIfNull(String string, String defaultString) {
182
		return (string != null) ? string : defaultString;
183
	}
184
}
(-)src/org/eclipse/core/databinding/validation/constraint/DateConstraints.java (+204 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Ovidio Mallo 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
 *     Ovidio Mallo - initial API and implementation (bug 183055)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.validation.constraint;
13
14
import java.util.Date;
15
16
import org.eclipse.core.internal.databinding.validation.DateRangeValidator;
17
import org.eclipse.core.internal.databinding.validation.NonNullValidator;
18
19
import com.ibm.icu.text.DateFormat;
20
21
/**
22
 * @since 1.3
23
 */
24
public final class DateConstraints extends Constraints {
25
26
	private final DateFormat displayFormat;
27
28
	private String requiredMessage = null;
29
30
	private String afterMessage = null;
31
32
	private String afterEqualMessage = null;
33
34
	private String beforeMessage = null;
35
36
	private String beforeEqualMessage = null;
37
38
	/**
39
	 * 
40
	 * @param displayFormat
41
	 */
42
	public DateConstraints(DateFormat displayFormat) {
43
		this.displayFormat = displayFormat;
44
	}
45
46
	/**
47
	 * Adds a validator ensuring that the parsed date is not <code>null</code>.
48
	 * Uses the current {@link #requiredMessage(String) validation message}.
49
	 * 
50
	 * @return This constraints instance for method chaining.
51
	 */
52
	public DateConstraints required() {
53
		addValidator(new NonNullValidator(requiredMessage));
54
		return this;
55
	}
56
57
	/**
58
	 * Sets the validation message to be issued in case the parsed date is
59
	 * <code>null</code>.
60
	 * 
61
	 * @param message
62
	 *            The validation message to be issued in case the parsed date is
63
	 *            <code>null</code>.
64
	 * @return This constraints instance for method chaining.
65
	 * 
66
	 * @see #required()
67
	 */
68
	public DateConstraints requiredMessage(String message) {
69
		this.requiredMessage = message;
70
		return this;
71
	}
72
73
	/**
74
	 * Adds a validator ensuring that the parsed date is after the given date.
75
	 * Uses the current {@link #afterMessage(String) validation message}.
76
	 * 
77
	 * @param date
78
	 *            The date which must be before or on the parsed date.
79
	 * @return This constraints instance for method chaining.
80
	 * 
81
	 * @see Date#after(Date)
82
	 */
83
	public DateConstraints after(Date date) {
84
		addValidator(DateRangeValidator
85
				.after(date, afterMessage, displayFormat));
86
		return this;
87
	}
88
89
	/**
90
	 * Sets the validation message to be issued in case the parsed date is not
91
	 * after a given date.
92
	 * 
93
	 * @param message
94
	 *            The validation message to be issued in case the parsed date is
95
	 *            not after a given date.
96
	 * @return This constraints instance for method chaining.
97
	 * 
98
	 * @see #after(Date)
99
	 */
100
	public DateConstraints afterMessage(String message) {
101
		this.afterMessage = message;
102
		return this;
103
	}
104
105
	/**
106
	 * Adds a validator ensuring that the parsed date is after or on the given
107
	 * date. Uses the current {@link #afterEqualMessage(String) validation
108
	 * message}.
109
	 * 
110
	 * @param date
111
	 *            The date which must be before the parsed date.
112
	 * @return This constraints instance for method chaining.
113
	 * 
114
	 * @see Date#after(Date)
115
	 * @see Date#equals(Object)
116
	 */
117
	public DateConstraints afterEqual(Date date) {
118
		addValidator(DateRangeValidator.afterEqual(date, afterEqualMessage,
119
				displayFormat));
120
		return this;
121
	}
122
123
	/**
124
	 * Sets the validation message to be issued in case the parsed date is not
125
	 * after or on a given date.
126
	 * 
127
	 * @param message
128
	 *            The validation message to be issued in case the parsed date is
129
	 *            not after or on a given date.
130
	 * @return This constraints instance for method chaining.
131
	 * 
132
	 * @see #afterEqual(Date)
133
	 */
134
	public DateConstraints afterEqualMessage(String message) {
135
		this.afterEqualMessage = message;
136
		return this;
137
	}
138
139
	/**
140
	 * Adds a validator ensuring that the parsed date is before the given date.
141
	 * Uses the current {@link #beforeMessage(String) validation message}.
142
	 * 
143
	 * @param date
144
	 *            The date which must be after or on the parsed date.
145
	 * @return This constraints instance for method chaining.
146
	 * 
147
	 * @see Date#before(Date)
148
	 */
149
	public DateConstraints before(Date date) {
150
		addValidator(DateRangeValidator.before(date, beforeMessage,
151
				displayFormat));
152
		return this;
153
	}
154
155
	/**
156
	 * Sets the validation message to be issued in case the parsed date is not
157
	 * before a given date.
158
	 * 
159
	 * @param message
160
	 *            The validation message to be issued in case the parsed date is
161
	 *            not before a given date.
162
	 * @return This constraints instance for method chaining.
163
	 * 
164
	 * @see #before(Date)
165
	 */
166
	public DateConstraints beforeMessage(String message) {
167
		this.beforeMessage = message;
168
		return this;
169
	}
170
171
	/**
172
	 * Adds a validator ensuring that the parsed date is before or on the given
173
	 * date. Uses the current {@link #beforeEqualMessage(String) validation
174
	 * message}.
175
	 * 
176
	 * @param date
177
	 *            The date which must be after the parsed date.
178
	 * @return This constraints instance for method chaining.
179
	 * 
180
	 * @see Date#before(Date)
181
	 * @see Date#equals(Object)
182
	 */
183
	public DateConstraints beforeEqual(Date date) {
184
		addValidator(DateRangeValidator.beforeEqual(date, beforeEqualMessage,
185
				displayFormat));
186
		return this;
187
	}
188
189
	/**
190
	 * Sets the validation message to be issued in case the parsed date is not
191
	 * before or on a given date.
192
	 * 
193
	 * @param message
194
	 *            The validation message to be issued in case the parsed date is
195
	 *            not before or on a given date.
196
	 * @return This constraints instance for method chaining.
197
	 * 
198
	 * @see #beforeEqual(Date)
199
	 */
200
	public DateConstraints beforeEqualMessage(String message) {
201
		this.beforeEqualMessage = message;
202
		return this;
203
	}
204
}
(-)src/org/eclipse/core/internal/databinding/validation/NonNullValidator.java (+47 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Ovidio Mallo 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
 *     Ovidio Mallo - initial API and implementation (bug 183055)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.validation;
13
14
import org.eclipse.core.databinding.validation.IValidator;
15
import org.eclipse.core.databinding.validation.ValidationStatus;
16
import org.eclipse.core.runtime.IStatus;
17
18
/**
19
 * @since 1.3
20
 */
21
public class NonNullValidator implements IValidator {
22
23
	private final String validationMessage;
24
25
	/**
26
	 * 
27
	 */
28
	public NonNullValidator() {
29
		this(null);
30
	}
31
32
	/**
33
	 * @param validationMessage
34
	 */
35
	public NonNullValidator(String validationMessage) {
36
		// TODO: Externalize
37
		this.validationMessage = validationMessage != null ? validationMessage
38
				: "The value must not be empty."; //$NON-NLS-1$
39
	}
40
41
	public IStatus validate(Object value) {
42
		if (value == null) {
43
			return ValidationStatus.error(validationMessage);
44
		}
45
		return ValidationStatus.ok();
46
	}
47
}
(-)src/org/eclipse/core/internal/databinding/validation/IntegerRangeValidator.java (+140 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Ovidio Mallo 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
 *     Ovidio Mallo - initial API and implementation (bug 183055)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.validation;
13
14
import com.ibm.icu.text.NumberFormat;
15
16
/**
17
 * @since 1.3
18
 */
19
public class IntegerRangeValidator extends NumberRangeValidator {
20
21
	private static final Integer ZERO = new Integer(0);
22
	private static final Integer ONE = new Integer(1);
23
24
	/**
25
	 * @param min
26
	 * @param max
27
	 * @param minConstraint
28
	 * @param maxConstraint
29
	 * @param validationMessage
30
	 * @param format
31
	 */
32
	private IntegerRangeValidator(Number min, Number max, int minConstraint,
33
			int maxConstraint, String validationMessage, NumberFormat format) {
34
		super(min, max, minConstraint, maxConstraint, validationMessage, format);
35
	}
36
37
	/**
38
	 * 
39
	 * @param min
40
	 * @param validationMessage
41
	 * @param format
42
	 * @return .
43
	 */
44
	public static IntegerRangeValidator greater(int min,
45
			String validationMessage, NumberFormat format) {
46
		return new IntegerRangeValidator(new Integer(min), null, GREATER,
47
				UNDEFINED, defaultIfNull(validationMessage, GREATER_MESSAGE),
48
				format);
49
	}
50
51
	/**
52
	 * 
53
	 * @param min
54
	 * @param validationMessage
55
	 * @param format
56
	 * @return .
57
	 */
58
	public static IntegerRangeValidator greaterEqual(int min,
59
			String validationMessage, NumberFormat format) {
60
		return new IntegerRangeValidator(new Integer(min), null, GREATER_EQUAL,
61
				UNDEFINED, defaultIfNull(validationMessage,
62
						GREATER_EQUAL_MESSAGE), format);
63
	}
64
65
	/**
66
	 * 
67
	 * @param max
68
	 * @param validationMessage
69
	 * @param format
70
	 * @return .
71
	 */
72
	public static IntegerRangeValidator less(int max, String validationMessage,
73
			NumberFormat format) {
74
		return new IntegerRangeValidator(null, new Integer(max), UNDEFINED,
75
				LESS, defaultIfNull(validationMessage, LESS_MESSAGE), format);
76
	}
77
78
	/**
79
	 * 
80
	 * @param max
81
	 * @param validationMessage
82
	 * @param format
83
	 * @return .
84
	 */
85
	public static IntegerRangeValidator lessEqual(int max,
86
			String validationMessage, NumberFormat format) {
87
		return new IntegerRangeValidator(null, new Integer(max), UNDEFINED,
88
				LESS_EQUAL,
89
				defaultIfNull(validationMessage, LESS_EQUAL_MESSAGE), format);
90
	}
91
92
	/**
93
	 * 
94
	 * @param min
95
	 * @param max
96
	 * @param validationMessage
97
	 * @param format
98
	 * @return .
99
	 */
100
	public static IntegerRangeValidator range(int min, int max,
101
			String validationMessage, NumberFormat format) {
102
		return new IntegerRangeValidator(new Integer(min), new Integer(max),
103
				GREATER_EQUAL, LESS_EQUAL, defaultIfNull(validationMessage,
104
						WITHIN_RANGE_MESSAGE), format);
105
	}
106
107
	/**
108
	 * 
109
	 * @param validationMessage
110
	 * @param format
111
	 * @return .
112
	 */
113
	public static IntegerRangeValidator positive(String validationMessage,
114
			NumberFormat format) {
115
		return new IntegerRangeValidator(ONE, null, GREATER_EQUAL, UNDEFINED,
116
				defaultIfNull(validationMessage, POSITIVE_MESSAGE), format);
117
	}
118
119
	/**
120
	 * 
121
	 * @param validationMessage
122
	 * @param format
123
	 * @return .
124
	 */
125
	public static IntegerRangeValidator nonNegative(String validationMessage,
126
			NumberFormat format) {
127
		return new IntegerRangeValidator(ZERO, null, GREATER_EQUAL, UNDEFINED,
128
				defaultIfNull(validationMessage, NON_NEGATIVE_MESSAGE), format);
129
	}
130
131
	protected int compare(Number number1, Number number2) {
132
		Integer integer1 = (Integer) number1;
133
		Integer integer2 = (Integer) number2;
134
		return integer1.compareTo(integer2);
135
	}
136
137
	private static String defaultIfNull(String string, String defaultString) {
138
		return (string != null) ? string : defaultString;
139
	}
140
}
(-)src/org/eclipse/core/internal/databinding/validation/StringRegexValidator.java (+71 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Ovidio Mallo 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
 *     Ovidio Mallo - initial API and implementation (bug 183055)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.validation;
13
14
import java.text.MessageFormat;
15
import java.util.regex.Matcher;
16
import java.util.regex.Pattern;
17
18
import org.eclipse.core.databinding.validation.IValidator;
19
import org.eclipse.core.databinding.validation.ValidationStatus;
20
import org.eclipse.core.runtime.IStatus;
21
22
/**
23
 * @since 1.3
24
 */
25
public class StringRegexValidator implements IValidator {
26
27
	// TODO: Externalize
28
	private static final String REGEX_VALIDATION_MESSAGE = "The string must match the following pattern: {0}."; //$NON-NLS-1$
29
30
	private final Pattern pattern;
31
	private final String validationMessage;
32
	private String formattedValidationMessage;
33
34
	/**
35
	 * 
36
	 * @param regex
37
	 */
38
	public StringRegexValidator(String regex) {
39
		this(regex, null);
40
	}
41
42
	/**
43
	 * 
44
	 * @param regex
45
	 * @param validationMessage
46
	 */
47
	public StringRegexValidator(String regex, String validationMessage) {
48
		this.pattern = Pattern.compile(regex);
49
		this.validationMessage = validationMessage != null ? validationMessage
50
				: REGEX_VALIDATION_MESSAGE;
51
	}
52
53
	public IStatus validate(Object value) {
54
		String input = (String) value;
55
		if (input != null) {
56
			Matcher matcher = pattern.matcher(input);
57
			if (!matcher.matches()) {
58
				return ValidationStatus.error(getFormattedValidationMessage());
59
			}
60
		}
61
		return ValidationStatus.ok();
62
	}
63
64
	private String getFormattedValidationMessage() {
65
		if (formattedValidationMessage == null) {
66
			formattedValidationMessage = MessageFormat.format(
67
					validationMessage, new String[] { pattern.pattern() });
68
		}
69
		return formattedValidationMessage;
70
	}
71
}
(-)src/org/eclipse/core/databinding/validation/constraint/StringConstraints.java (+226 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Ovidio Mallo 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
 *     Ovidio Mallo - initial API and implementation (bug 183055)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.validation.constraint;
13
14
import java.util.regex.Pattern;
15
16
import org.eclipse.core.internal.databinding.validation.NonEmptyStringValidator;
17
import org.eclipse.core.internal.databinding.validation.NonNullValidator;
18
import org.eclipse.core.internal.databinding.validation.StringLengthValidator;
19
import org.eclipse.core.internal.databinding.validation.StringRegexValidator;
20
21
import com.ibm.icu.text.NumberFormat;
22
23
/**
24
 * @since 1.3
25
 */
26
public final class StringConstraints extends Constraints {
27
28
	// TODO: Support custom NumberFormat.
29
	private final NumberFormat integerDisplayFormat = NumberFormat
30
			.getIntegerInstance();
31
32
	private String requiredMessage = null;
33
34
	private String nonEmptyMessage = null;
35
36
	private String minLengthMessage = null;
37
38
	private String maxLengthMessage = null;
39
40
	private String lengthRangeMessage = null;
41
42
	private String matchesMessage = null;
43
44
	/**
45
	 * Adds a validator ensuring that the parsed integer is not
46
	 * <code>null</code>. Uses the current {@link #requiredMessage(String)
47
	 * validation message}.
48
	 * 
49
	 * @return This constraints instance for method chaining.
50
	 */
51
	public StringConstraints required() {
52
		addValidator(new NonNullValidator(requiredMessage));
53
		return this;
54
	}
55
56
	/**
57
	 * Sets the validation message to be issued in case the input string is
58
	 * <code>null</code>.
59
	 * 
60
	 * @param message
61
	 *            The validation message to be issued in case the input string
62
	 *            is <code>null</code>.
63
	 * @return This constraints instance for method chaining.
64
	 * 
65
	 * @see #required()
66
	 */
67
	public StringConstraints requiredMessage(String message) {
68
		this.requiredMessage = message;
69
		return this;
70
	}
71
72
	/**
73
	 * Adds a validator ensuring that the parsed integer is not empty. Uses the
74
	 * current {@link #nonEmptyMessage(String) validation message}.
75
	 * 
76
	 * @return This constraints instance for method chaining.
77
	 */
78
	public StringConstraints nonEmpty() {
79
		addValidator(new NonEmptyStringValidator(nonEmptyMessage));
80
		return this;
81
	}
82
83
	/**
84
	 * Sets the validation message to be issued in case the input string is
85
	 * empty.
86
	 * 
87
	 * @param message
88
	 *            The validation message to be issued in case the input string
89
	 *            is empty.
90
	 * @return This constraints instance for method chaining.
91
	 * 
92
	 * @see #nonEmpty()
93
	 */
94
	public StringConstraints nonEmptyMessage(String message) {
95
		this.nonEmptyMessage = message;
96
		return this;
97
	}
98
99
	/**
100
	 * Adds a validator ensuring that the input string has at least the
101
	 * specified amount of characters. Uses the current
102
	 * {@link #minLengthMessage(String) validation message}.
103
	 * 
104
	 * @param minLength
105
	 *            The minimal length to be enforced on the input string.
106
	 * @return This constraints instance for method chaining.
107
	 */
108
	public StringConstraints minLength(int minLength) {
109
		addValidator(StringLengthValidator.minLength(minLength,
110
				minLengthMessage, integerDisplayFormat));
111
		return this;
112
	}
113
114
	/**
115
	 * Sets the validation message to be issued in case the input string does
116
	 * not have at least a given number of characters.
117
	 * 
118
	 * @param message
119
	 *            The validation message to be issued in case the input string
120
	 *            does not have at least a given number of characters.
121
	 * @return This constraints instance for method chaining.
122
	 * 
123
	 * @see #minLength(int)
124
	 */
125
	public StringConstraints minLengthMessage(String message) {
126
		this.minLengthMessage = message;
127
		return this;
128
	}
129
130
	/**
131
	 * Adds a validator ensuring that the input string has not more than the
132
	 * specified amount of characters. Uses the current
133
	 * {@link #maxLengthMessage(String) validation message}.
134
	 * 
135
	 * @param maxLength
136
	 *            The maximum length to be enforced on the input string.
137
	 * @return This constraints instance for method chaining.
138
	 */
139
	public StringConstraints maxLength(int maxLength) {
140
		addValidator(StringLengthValidator.maxLength(maxLength,
141
				maxLengthMessage, integerDisplayFormat));
142
		return this;
143
	}
144
145
	/**
146
	 * Sets the validation message to be issued in case the input string has
147
	 * more than a given number of characters.
148
	 * 
149
	 * @param message
150
	 *            The validation message to be issued in case the input string
151
	 *            has more than a given number of characters.
152
	 * @return This constraints instance for method chaining.
153
	 * 
154
	 * @see #maxLength(int)
155
	 */
156
	public StringConstraints maxLengthMessage(String message) {
157
		this.maxLengthMessage = message;
158
		return this;
159
	}
160
161
	/**
162
	 * Adds a validator ensuring that the length of the input string is between
163
	 * the given bounds. Uses the current {@link #lengthRangeMessage(String)
164
	 * validation message}.
165
	 * 
166
	 * @param minLength
167
	 *            The minimal length to be enforced on the input string.
168
	 * @param maxLength
169
	 *            The maximum length to be enforced on the input string.
170
	 * @return This constraints instance for method chaining.
171
	 */
172
	public StringConstraints lengthRange(int minLength, int maxLength) {
173
		addValidator(StringLengthValidator.lengthRange(minLength, maxLength,
174
				lengthRangeMessage, integerDisplayFormat));
175
		return this;
176
	}
177
178
	/**
179
	 * Sets the validation message to be issued in case the length of the input
180
	 * is not between the given bounds.
181
	 * 
182
	 * @param message
183
	 *            The validation message to be issued in case the length of the
184
	 *            input is not between the given bounds.
185
	 * @return This constraints instance for method chaining.
186
	 * 
187
	 * @see #lengthRange(int, int)
188
	 */
189
	public StringConstraints lengthRangeMessage(String message) {
190
		this.lengthRangeMessage = message;
191
		return this;
192
	}
193
194
	/**
195
	 * Adds a validator ensuring that the input string
196
	 * {@link Pattern#matches(String, CharSequence) matches} the given regular
197
	 * expression. Uses the current {@link #matchesMessage(String) validation
198
	 * message}.
199
	 * 
200
	 * @param regex
201
	 *            The regular expression which the input string must match.
202
	 * @return This constraints instance for method chaining.
203
	 * 
204
	 * @see Pattern#matches(String, CharSequence)
205
	 */
206
	public StringConstraints matches(String regex) {
207
		addValidator(new StringRegexValidator(regex, matchesMessage));
208
		return this;
209
	}
210
211
	/**
212
	 * Sets the validation message to be issued in case the input string does
213
	 * not match a given regular expression.
214
	 * 
215
	 * @param message
216
	 *            The validation message to be issued in case the input string
217
	 *            does not match a given regular expression.
218
	 * @return This constraints instance for method chaining.
219
	 * 
220
	 * @see #matches(String)
221
	 */
222
	public StringConstraints matchesMessage(String message) {
223
		this.matchesMessage = message;
224
		return this;
225
	}
226
}
(-)src/org/eclipse/core/internal/databinding/validation/StringLengthValidator.java (+128 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Ovidio Mallo 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
 *     Ovidio Mallo - initial API and implementation (bug 183055)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.validation;
13
14
import java.text.MessageFormat;
15
16
import org.eclipse.core.databinding.validation.IValidator;
17
import org.eclipse.core.databinding.validation.ValidationStatus;
18
import org.eclipse.core.runtime.IStatus;
19
20
import com.ibm.icu.text.NumberFormat;
21
22
/**
23
 * @since 1.3
24
 */
25
public class StringLengthValidator implements IValidator {
26
27
	// TODO: Externalize
28
	private static final String MIN_LENGTH_MESSAGE = "The string must have at least {0} characters."; //$NON-NLS-1$
29
	private static final String MAX_LENGTH_MESSAGE = "The string must not have more than {0} characters."; //$NON-NLS-1$
30
	private static final String LENGTH_RANGE_MESSAGE = "The string must have between {0} and {1} characters."; //$NON-NLS-1$
31
32
	private final Integer minLength;
33
	private final Integer maxLength;
34
	private final String validationMessage;
35
	private String formattedValidationMessage;
36
	private final NumberFormat format;
37
38
	/**
39
	 * 
40
	 * @param minLength
41
	 * @param maxLength
42
	 * @param validationMessage
43
	 * @param format
44
	 */
45
	private StringLengthValidator(Integer minLength, Integer maxLength,
46
			String validationMessage, NumberFormat format) {
47
		this.minLength = minLength;
48
		this.maxLength = maxLength;
49
		this.validationMessage = validationMessage;
50
		this.format = format;
51
	}
52
53
	/**
54
	 * 
55
	 * @param minLength
56
	 * @param validationMessage
57
	 * @param format
58
	 * @return .
59
	 */
60
	public static StringLengthValidator minLength(int minLength,
61
			String validationMessage, NumberFormat format) {
62
		return new StringLengthValidator(new Integer(minLength), null,
63
				defaultIfNull(validationMessage, MIN_LENGTH_MESSAGE), format);
64
	}
65
66
	/**
67
	 * 
68
	 * @param maxLength
69
	 * @param validationMessage
70
	 * @param format
71
	 * @return .
72
	 */
73
	public static StringLengthValidator maxLength(int maxLength,
74
			String validationMessage, NumberFormat format) {
75
		return new StringLengthValidator(null, new Integer(maxLength),
76
				defaultIfNull(validationMessage, MAX_LENGTH_MESSAGE), format);
77
	}
78
79
	/**
80
	 * 
81
	 * @param minLength
82
	 * @param maxLength
83
	 * @param validationMessage
84
	 * @param format
85
	 * @return .
86
	 */
87
	public static StringLengthValidator lengthRange(int minLength,
88
			int maxLength, String validationMessage, NumberFormat format) {
89
		return new StringLengthValidator(new Integer(minLength), new Integer(
90
				maxLength), defaultIfNull(validationMessage,
91
				LENGTH_RANGE_MESSAGE), format);
92
	}
93
94
	public IStatus validate(Object value) {
95
		String input = (String) value;
96
		if (input != null) {
97
			int inputLength = input.length();
98
			if ((minLength != null && inputLength < minLength.intValue())
99
					|| maxLength != null && inputLength > maxLength.intValue()) {
100
				return ValidationStatus.error(getFormattedValidationMessage());
101
			}
102
		}
103
		return ValidationStatus.ok();
104
	}
105
106
	private String getFormattedValidationMessage() {
107
		if (formattedValidationMessage == null) {
108
			formattedValidationMessage = MessageFormat.format(
109
					validationMessage, getValidationMessageArguments());
110
		}
111
		return formattedValidationMessage;
112
	}
113
114
	private String[] getValidationMessageArguments() {
115
		// TODO: Synchronize formatting to make it thread safe?
116
		if (minLength == null) {
117
			return new String[] { format.format(maxLength) };
118
		} else if (maxLength == null) {
119
			return new String[] { format.format(minLength) };
120
		}
121
		return new String[] { format.format(minLength),
122
				format.format(maxLength) };
123
	}
124
125
	private static String defaultIfNull(String string, String defaultString) {
126
		return (string != null) ? string : defaultString;
127
	}
128
}
(-)src/org/eclipse/core/databinding/editing/IntegerEditing.java (+311 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Ovidio Mallo 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
 *     Ovidio Mallo - initial API and implementation (bug 183055)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.editing;
13
14
import org.eclipse.core.databinding.conversion.NumberToStringConverter;
15
import org.eclipse.core.databinding.conversion.StringToNumberConverter;
16
import org.eclipse.core.databinding.validation.constraint.Constraints;
17
import org.eclipse.core.databinding.validation.constraint.IntegerConstraints;
18
import org.eclipse.core.databinding.validation.constraint.StringConstraints;
19
import org.eclipse.core.internal.databinding.validation.StringToIntegerValidator;
20
21
import com.ibm.icu.text.NumberFormat;
22
23
/**
24
 * @since 1.3
25
 */
26
public final class IntegerEditing extends Editing {
27
28
	private final NumberFormat format;
29
30
	private IntegerEditing(NumberFormat format, String parseErrorMessage,
31
			String outOfRangeMessage) {
32
		this.format = format;
33
34
		StringToNumberConverter targetConverter = StringToNumberConverter
35
				.toInteger(format, false);
36
37
		targetConstraints().addValidator(
38
				new StringToIntegerValidator(targetConverter,
39
						parseErrorMessage, outOfRangeMessage));
40
		setTargetConverter(targetConverter);
41
		setModelConverter(NumberToStringConverter.fromInteger(format, false));
42
	}
43
44
	/**
45
	 * Creates a new editing object which defaults the validations and
46
	 * conversions used for editing based on the platform's locale. Uses the
47
	 * default validation messages.
48
	 * 
49
	 * @return The new editing object using the default validations and
50
	 *         conversions for editing.
51
	 * 
52
	 * @see NumberFormat#getIntegerInstance()
53
	 */
54
	public static IntegerEditing withDefaults() {
55
		return withDefaults(null, null);
56
	}
57
58
	/**
59
	 * Creates a new editing object which defaults the validations and
60
	 * conversions used for editing based on the platform's locale. Uses the
61
	 * specified custom validation messages.
62
	 * 
63
	 * @param parseErrorMessage
64
	 *            The validation message issued in case the input string cannot
65
	 *            be parsed to an integer.
66
	 * @param outOfRangeMessage
67
	 *            The validation message issued in case the input string
68
	 *            represents an integer whose value is out of range. Can be
69
	 *            parameterized by the <code>Integer.MIN_VALUE</code> and
70
	 *            <code>Integer.MAX_VALUE</code> values.
71
	 * @return The new editing object using the default validations and
72
	 *         conversions for editing.
73
	 * 
74
	 * @see NumberFormat#getIntegerInstance()
75
	 */
76
	public static IntegerEditing withDefaults(String parseErrorMessage,
77
			String outOfRangeMessage) {
78
		return new IntegerEditing(NumberFormat.getIntegerInstance(),
79
				parseErrorMessage, outOfRangeMessage);
80
	}
81
82
	/**
83
	 * Creates a new editing object whose validations and conversions used for
84
	 * editing are based on the given integer format. Uses the default
85
	 * validation messages.
86
	 * 
87
	 * @param format
88
	 *            The integer format defining the validations and conversions
89
	 *            used for editing.
90
	 * @return The new editing object configured by the given integer format.
91
	 */
92
	public static IntegerEditing forFormat(NumberFormat format) {
93
		return forFormat(format, null, null);
94
	}
95
96
	/**
97
	 * Creates a new editing object whose validations and conversions used for
98
	 * editing are based on the given integer format. Uses the specified custom
99
	 * validation messages.
100
	 * 
101
	 * @param format
102
	 *            The integer format defining the validations and conversions
103
	 *            used for editing.
104
	 * @param parseErrorMessage
105
	 *            The validation message issued in case the input string cannot
106
	 *            be parsed to an integer.
107
	 * @param outOfRangeMessage
108
	 *            The validation message issued in case the input string
109
	 *            represents an integer whose value is out of range. Can be
110
	 *            parameterized by the <code>Integer.MIN_VALUE</code> and
111
	 *            <code>Integer.MAX_VALUE</code> values.
112
	 * @return The new editing object configured by the given integer format.
113
	 */
114
	public static IntegerEditing forFormat(NumberFormat format,
115
			String parseErrorMessage, String outOfRangeMessage) {
116
		return new IntegerEditing(format, parseErrorMessage, outOfRangeMessage);
117
	}
118
119
	/**
120
	 * Returns the target constraints to apply.
121
	 * 
122
	 * <p>
123
	 * This method provides a typesafe access to the {@link StringConstraints
124
	 * string target constraints} of this editing object and is equivalent to
125
	 * {@code (StringConstraints) targetConstraints()}.
126
	 * </p>
127
	 * 
128
	 * @return The target constraints to apply.
129
	 * 
130
	 * @see #targetConstraints()
131
	 * @see StringConstraints
132
	 */
133
	public StringConstraints targetStringConstraints() {
134
		return (StringConstraints) targetConstraints();
135
	}
136
137
	/**
138
	 * Returns the model constraints to apply.
139
	 * 
140
	 * <p>
141
	 * This method provides a typesafe access to the {@link IntegerConstraints
142
	 * integer model constraints} of this editing object and is equivalent to
143
	 * {@code (IntegerConstraints) modelConstraints()}.
144
	 * </p>
145
	 * 
146
	 * @return The target constraints to apply.
147
	 * 
148
	 * @see #modelConstraints()
149
	 * @see IntegerConstraints
150
	 */
151
	public IntegerConstraints modelIntegerConstraints() {
152
		return (IntegerConstraints) modelConstraints();
153
	}
154
155
	/**
156
	 * Returns the before-set model constraints to apply.
157
	 * 
158
	 * <p>
159
	 * This method provides a typesafe access to the {@link IntegerConstraints
160
	 * integer before-set model constraints} of this editing object and is
161
	 * equivalent to {@code (IntegerConstraints) beforeSetModelConstraints()}.
162
	 * </p>
163
	 * 
164
	 * @return The target constraints to apply.
165
	 * 
166
	 * @see #beforeSetModelConstraints()
167
	 * @see IntegerConstraints
168
	 */
169
	public IntegerConstraints beforeSetModelIntegerConstraints() {
170
		return (IntegerConstraints) beforeSetModelConstraints();
171
	}
172
173
	protected Constraints createTargetConstraints() {
174
		return new StringConstraints();
175
	}
176
177
	protected Constraints createModelConstraints() {
178
		return new IntegerConstraints(format);
179
	}
180
181
	protected Constraints createBeforeSetModelConstraints() {
182
		return new IntegerConstraints(format);
183
	}
184
185
	/**
186
	 * Convenience method which adds a {@link IntegerConstraints#required()
187
	 * required constraint} to the set of {@link #modelIntegerConstraints()}.
188
	 * 
189
	 * @return This editing instance for method chaining.
190
	 * 
191
	 * @see IntegerConstraints#required()
192
	 * @see #modelIntegerConstraints()
193
	 */
194
	public IntegerEditing required() {
195
		modelIntegerConstraints().required();
196
		return this;
197
	}
198
199
	/**
200
	 * Convenience method which adds a {@link IntegerConstraints#greater(int)
201
	 * greater constraint} to the set of {@link #modelIntegerConstraints()}.
202
	 * 
203
	 * @param number
204
	 *            The number of the greater constraint.
205
	 * @return This editing instance for method chaining.
206
	 * 
207
	 * @see IntegerConstraints#greater(int)
208
	 * @see #modelIntegerConstraints()
209
	 */
210
	public IntegerEditing greater(int number) {
211
		modelIntegerConstraints().greater(number);
212
		return this;
213
	}
214
215
	/**
216
	 * Convenience method which adds a
217
	 * {@link IntegerConstraints#greaterEqual(int) greater-equal constraint} to
218
	 * the set of {@link #modelIntegerConstraints()}.
219
	 * 
220
	 * @param number
221
	 *            The number of the greater-equal constraint.
222
	 * @return This editing instance for method chaining.
223
	 * 
224
	 * @see IntegerConstraints#greaterEqual(int)
225
	 * @see #modelIntegerConstraints()
226
	 */
227
	public IntegerEditing greaterEqual(int number) {
228
		modelIntegerConstraints().greaterEqual(number);
229
		return this;
230
	}
231
232
	/**
233
	 * Convenience method which adds a {@link IntegerConstraints#less(int) less
234
	 * constraint} to the set of {@link #modelIntegerConstraints()}.
235
	 * 
236
	 * @param number
237
	 *            The number of the less constraint.
238
	 * @return This editing instance for method chaining.
239
	 * 
240
	 * @see IntegerConstraints#less(int)
241
	 * @see #modelIntegerConstraints()
242
	 */
243
	public IntegerEditing less(int number) {
244
		modelIntegerConstraints().less(number);
245
		return this;
246
	}
247
248
	/**
249
	 * Convenience method which adds a {@link IntegerConstraints#lessEqual(int)
250
	 * less-equal constraint} to the set of {@link #modelIntegerConstraints()}.
251
	 * 
252
	 * @param number
253
	 *            The number of the less-equal constraint.
254
	 * @return This editing instance for method chaining.
255
	 * 
256
	 * @see IntegerConstraints#lessEqual(int)
257
	 * @see #modelIntegerConstraints()
258
	 */
259
	public IntegerEditing lessEqual(int number) {
260
		modelIntegerConstraints().lessEqual(number);
261
		return this;
262
	}
263
264
	/**
265
	 * Convenience method which adds a
266
	 * {@link IntegerConstraints#range(int, int) range constraint} to the set of
267
	 * {@link #modelIntegerConstraints()}.
268
	 * 
269
	 * @param min
270
	 *            The min number of the range constraint.
271
	 * @param max
272
	 *            The max number of the range constraint.
273
	 * @return This editing instance for method chaining.
274
	 * 
275
	 * @see IntegerConstraints#range(int, int)
276
	 * @see #modelIntegerConstraints()
277
	 */
278
	public IntegerEditing range(int min, int max) {
279
		modelIntegerConstraints().range(min, max);
280
		return this;
281
	}
282
283
	/**
284
	 * Convenience method which adds a {@link IntegerConstraints#positive()
285
	 * positive constraint} to the set of {@link #modelIntegerConstraints()}.
286
	 * 
287
	 * @return This editing instance for method chaining.
288
	 * 
289
	 * @see IntegerConstraints#positive()
290
	 * @see #modelIntegerConstraints()
291
	 */
292
	public IntegerEditing positive() {
293
		modelIntegerConstraints().positive();
294
		return this;
295
	}
296
297
	/**
298
	 * Convenience method which adds a {@link IntegerConstraints#nonNegative()
299
	 * non-negative constraint} to the set of {@link #modelIntegerConstraints()}
300
	 * .
301
	 * 
302
	 * @return This editing instance for method chaining.
303
	 * 
304
	 * @see IntegerConstraints#nonNegative()
305
	 * @see #modelIntegerConstraints()
306
	 */
307
	public IntegerEditing nonNegative() {
308
		modelIntegerConstraints().nonNegative();
309
		return this;
310
	}
311
}
(-)src/org/eclipse/core/databinding/validation/constraint/IntegerConstraints.java (+288 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Ovidio Mallo 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
 *     Ovidio Mallo - initial API and implementation (bug 183055)
10
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.validation.constraint;
13
14
import org.eclipse.core.internal.databinding.validation.IntegerRangeValidator;
15
import org.eclipse.core.internal.databinding.validation.NonNullValidator;
16
17
import com.ibm.icu.text.NumberFormat;
18
19
/**
20
 * @since 1.3
21
 */
22
public final class IntegerConstraints extends Constraints {
23
24
	private final NumberFormat format;
25
26
	private String requiredMessage = null;
27
28
	private String greaterMessage = null;
29
30
	private String greaterEqualMessage = null;
31
32
	private String lessMessage = null;
33
34
	private String lessEqualMessage = null;
35
36
	private String rangeMessage = null;
37
38
	private String positiveMessage = null;
39
40
	private String nonNegativeMessage = null;
41
42
	/**
43
	 * 
44
	 * @param format
45
	 */
46
	public IntegerConstraints(NumberFormat format) {
47
		this.format = format;
48
	}
49
50
	/**
51
	 * Adds a validator ensuring that the parsed integer is not
52
	 * <code>null</code>. Uses the current {@link #requiredMessage(String)
53
	 * validation message}.
54
	 * 
55
	 * @return This constraints instance for method chaining.
56
	 */
57
	public IntegerConstraints required() {
58
		addValidator(new NonNullValidator(requiredMessage));
59
		return this;
60
	}
61
62
	/**
63
	 * Sets the validation message to be issued in case the parsed integer is
64
	 * <code>null</code>.
65
	 * 
66
	 * @param message
67
	 *            The validation message to be issued in case the parsed integer
68
	 *            is <code>null</code>.
69
	 * @return This constraints instance for method chaining.
70
	 * 
71
	 * @see #required()
72
	 */
73
	public IntegerConstraints requiredMessage(String message) {
74
		this.requiredMessage = message;
75
		return this;
76
	}
77
78
	/**
79
	 * Adds a validator ensuring that the parsed integer is greater than the
80
	 * given number. Uses the current {@link #greaterMessage(String) validation
81
	 * message}.
82
	 * 
83
	 * @param number
84
	 *            The number which the parsed integer must be greater than.
85
	 * @return This constraints instance for method chaining.
86
	 */
87
	public IntegerConstraints greater(int number) {
88
		addValidator(IntegerRangeValidator.greater(number, greaterMessage,
89
				format));
90
		return this;
91
	}
92
93
	/**
94
	 * Sets the validation message to be issued in case the parsed integer is
95
	 * not greater than a given number.
96
	 * 
97
	 * @param message
98
	 *            The validation message to be issued in case the parsed integer
99
	 *            is not greater than a given number.
100
	 * @return This constraints instance for method chaining.
101
	 * 
102
	 * @see #greater(int)
103
	 */
104
	public IntegerConstraints greaterMessage(String message) {
105
		this.greaterMessage = message;
106
		return this;
107
	}
108
109
	/**
110
	 * Adds a validator ensuring that the parsed integer is greater than or
111
	 * equal to the given number. Uses the current
112
	 * {@link #greaterEqualMessage(String) validation message}.
113
	 * 
114
	 * @param number
115
	 *            The number which the parsed integer must be greater than or
116
	 *            equal to.
117
	 * @return This constraints instance for method chaining.
118
	 */
119
	public IntegerConstraints greaterEqual(int number) {
120
		addValidator(IntegerRangeValidator.greaterEqual(number,
121
				greaterEqualMessage, format));
122
		return this;
123
	}
124
125
	/**
126
	 * Sets the validation message to be issued in case the parsed integer is
127
	 * not greater than or equal to a given number.
128
	 * 
129
	 * @param message
130
	 *            The validation message to be issued in case the parsed integer
131
	 *            is not greater than or equal to a given number.
132
	 * @return This constraints instance for method chaining.
133
	 * 
134
	 * @see #greaterEqual(int)
135
	 */
136
	public IntegerConstraints greaterEqualMessage(String message) {
137
		this.greaterEqualMessage = message;
138
		return this;
139
	}
140
141
	/**
142
	 * Adds a validator ensuring that the parsed integer is less than the given
143
	 * number. Uses the current {@link #lessMessage(String) validation message}.
144
	 * 
145
	 * @param number
146
	 *            The number which the parsed integer must be less than.
147
	 * @return This constraints instance for method chaining.
148
	 */
149
	public IntegerConstraints less(int number) {
150
		addValidator(IntegerRangeValidator.less(number, lessMessage, format));
151
		return this;
152
	}
153
154
	/**
155
	 * Sets the validation message to be issued in case the parsed integer is
156
	 * not less than a given number.
157
	 * 
158
	 * @param message
159
	 *            The validation message to be issued in case the parsed integer
160
	 *            is not less than a given number.
161
	 * @return This constraints instance for method chaining.
162
	 * 
163
	 * @see #less(int)
164
	 */
165
	public IntegerConstraints lessMessage(String message) {
166
		this.lessMessage = message;
167
		return this;
168
	}
169
170
	/**
171
	 * Adds a validator ensuring that the parsed integer is less than or equal
172
	 * to the given number. Uses the current {@link #lessEqualMessage(String)
173
	 * validation message}.
174
	 * 
175
	 * @param number
176
	 *            The number which the parsed integer must be less than or equal
177
	 *            to.
178
	 * @return This constraints instance for method chaining.
179
	 */
180
	public IntegerConstraints lessEqual(int number) {
181
		addValidator(IntegerRangeValidator.greaterEqual(number,
182
				lessEqualMessage, format));
183
		return this;
184
	}
185
186
	/**
187
	 * Sets the validation message to be issued in case the parsed integer is
188
	 * not less than or equal to a given number.
189
	 * 
190
	 * @param message
191
	 *            The validation message to be issued in case the parsed integer
192
	 *            is not less than or equal to a given number.
193
	 * @return This constraints instance for method chaining.
194
	 * 
195
	 * @see #lessEqual(int)
196
	 */
197
	public IntegerConstraints lessEqualMessage(String message) {
198
		this.lessEqualMessage = message;
199
		return this;
200
	}
201
202
	/**
203
	 * Adds a validator ensuring that the parsed integer is within the given
204
	 * range. Uses the current {@link #rangeMessage(String) validation message}.
205
	 * 
206
	 * @param min
207
	 *            The lower bound of the range (inclusive).
208
	 * @param max
209
	 *            The upper bound of the range (inclusive).
210
	 * @return This constraints instance for method chaining.
211
	 */
212
	public IntegerConstraints range(int min, int max) {
213
		addValidator(IntegerRangeValidator
214
				.range(min, max, rangeMessage, format));
215
		return this;
216
	}
217
218
	/**
219
	 * Sets the validation message to be issued in case the parsed integer is
220
	 * not within a given range.
221
	 * 
222
	 * @param message
223
	 *            The validation message to be issued in case the parsed integer
224
	 *            is not within a given range.
225
	 * @return This constraints instance for method chaining.
226
	 * 
227
	 * @see #range(int, int)
228
	 */
229
	public IntegerConstraints rangeMessage(String message) {
230
		this.rangeMessage = message;
231
		return this;
232
	}
233
234
	/**
235
	 * Adds a validator ensuring that the parsed integer is positive. Uses the
236
	 * current {@link #positiveMessage(String) validation message}.
237
	 * 
238
	 * @return This constraints instance for method chaining.
239
	 */
240
	public IntegerConstraints positive() {
241
		addValidator(IntegerRangeValidator.positive(positiveMessage, format));
242
		return this;
243
	}
244
245
	/**
246
	 * Sets the validation message to be issued in case the parsed integer is
247
	 * not positive.
248
	 * 
249
	 * @param message
250
	 *            The validation message to be issued in case the parsed integer
251
	 *            is not positive.
252
	 * @return This constraints instance for method chaining.
253
	 * 
254
	 * @see #positive()
255
	 */
256
	public IntegerConstraints positiveMessage(String message) {
257
		this.positiveMessage = message;
258
		return this;
259
	}
260
261
	/**
262
	 * Adds a validator ensuring that the parsed integer is non-negative. Uses
263
	 * the current {@link #nonNegativeMessage(String) validation message}.
264
	 * 
265
	 * @return This constraints instance for method chaining.
266
	 */
267
	public IntegerConstraints nonNegative() {
268
		addValidator(IntegerRangeValidator.nonNegative(nonNegativeMessage,
269
				format));
270
		return this;
271
	}
272
273
	/**
274
	 * Sets the validation message to be issued in case the parsed integer is
275
	 * negative.
276
	 * 
277
	 * @param message
278
	 *            The validation message to be issued in case the parsed integer
279
	 *            is negative.
280
	 * @return This constraints instance for method chaining.
281
	 * 
282
	 * @see #nonNegative()
283
	 */
284
	public IntegerConstraints nonNegativeMessage(String message) {
285
		this.nonNegativeMessage = message;
286
		return this;
287
	}
288
}
(-)src/org/eclipse/core/internal/databinding/validation/NumberRangeValidator.java (+119 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 Ovidio Mallo 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
 *     Ovidio Mallo - initial API and implementation (bug 183055)
10
 ******************************************************************************/
11
12
package org.eclipse.core.internal.databinding.validation;
13
14
import java.text.MessageFormat;
15
16
import org.eclipse.core.databinding.validation.IValidator;
17
import org.eclipse.core.databinding.validation.ValidationStatus;
18
import org.eclipse.core.runtime.IStatus;
19
20
import com.ibm.icu.text.NumberFormat;
21
22
/**
23
 * @since 1.3
24
 */
25
public abstract class NumberRangeValidator implements IValidator {
26
27
	protected static final int UNDEFINED = -1;
28
	protected static final int GREATER = 0;
29
	protected static final int GREATER_EQUAL = 1;
30
	protected static final int LESS = 2;
31
	protected static final int LESS_EQUAL = 3;
32
33
	// TODO: Externalize
34
	protected static final String GREATER_MESSAGE = "The value must be greater than {0}."; //$NON-NLS-1$
35
	protected static final String GREATER_EQUAL_MESSAGE = "The value must be greater than or equal to {0}."; //$NON-NLS-1$
36
	protected static final String LESS_MESSAGE = "The value must be less than {0}."; //$NON-NLS-1$
37
	protected static final String LESS_EQUAL_MESSAGE = "The value must be less than or equal to {0}."; //$NON-NLS-1$
38
	protected static final String WITHIN_RANGE_MESSAGE = "The value must lie between {0} and {1}."; //$NON-NLS-1$
39
	protected static final String POSITIVE_MESSAGE = "The value must be positive."; //$NON-NLS-1$
40
	protected static final String NON_NEGATIVE_MESSAGE = "The value must not be negative."; //$NON-NLS-1$
41
42
	private final Number min;
43
	private final Number max;
44
	private final int minConstraint;
45
	private final int maxConstraint;
46
	private final String validationMessage;
47
	private String formattedValidationMessage;
48
	private final NumberFormat format;
49
50
	/**
51
	 * 
52
	 * @param min
53
	 * @param max
54
	 * @param minConstraint
55
	 * @param maxConstraint
56
	 * @param validationMessage
57
	 * @param format
58
	 */
59
	protected NumberRangeValidator(Number min, Number max, int minConstraint,
60
			int maxConstraint, String validationMessage, NumberFormat format) {
61
		this.min = min;
62
		this.max = max;
63
		this.minConstraint = minConstraint;
64
		this.maxConstraint = maxConstraint;
65
		this.validationMessage = validationMessage;
66
		this.format = format;
67
	}
68
69
	public IStatus validate(Object value) {
70
		if (value != null) {
71
			Number number = (Number) value;
72
			if ((min != null && !fulfillsConstraint(number, min, minConstraint))
73
					|| (max != null && !fulfillsConstraint(number, max,
74
							maxConstraint))) {
75
				return ValidationStatus.error(getFormattedValidationMessage());
76
			}
77
		}
78
		return ValidationStatus.ok();
79
	}
80
81
	private boolean fulfillsConstraint(Number number1, Number number2,
82
			int constraint) {
83
		int compareResult = compare(number1, number2);
84
		switch (constraint) {
85
		case GREATER:
86
			return compareResult > 0;
87
		case GREATER_EQUAL:
88
			return compareResult >= 0;
89
		case LESS:
90
			return compareResult < 0;
91
		case LESS_EQUAL:
92
			return compareResult <= 0;
93
		case UNDEFINED:
94
		default:
95
			throw new IllegalArgumentException(
96
					"Unsupported constraint: " + constraint); //$NON-NLS-1$
97
		}
98
	}
99
100
	protected abstract int compare(Number number1, Number number2);
101
102
	private String getFormattedValidationMessage() {
103
		if (formattedValidationMessage == null) {
104
			formattedValidationMessage = MessageFormat.format(
105
					validationMessage, getValidationMessageArguments());
106
		}
107
		return formattedValidationMessage;
108
	}
109
110
	private String[] getValidationMessageArguments() {
111
		// TODO: Synchronize formatting to make it thread safe?
112
		if (min == null) {
113
			return new String[] { format.format(max) };
114
		} else if (max == null) {
115
			return new String[] { format.format(min) };
116
		}
117
		return new String[] { format.format(min), format.format(max) };
118
	}
119
}
(-).settings/org.eclipse.jdt.ui.prefs (-2 / +2 lines)
Lines 1-4 Link Here
1
#Tue Feb 10 16:06:02 MST 2009
1
#Fri Jun 12 23:17:33 CEST 2009
2
cleanup.add_default_serial_version_id=true
2
cleanup.add_default_serial_version_id=true
3
cleanup.add_generated_serial_version_id=false
3
cleanup.add_generated_serial_version_id=false
4
cleanup.add_missing_annotations=true
4
cleanup.add_missing_annotations=true
Lines 78-84 Link Here
78
sp_cleanup.always_use_this_for_non_static_method_access=false
78
sp_cleanup.always_use_this_for_non_static_method_access=false
79
sp_cleanup.convert_to_enhanced_for_loop=false
79
sp_cleanup.convert_to_enhanced_for_loop=false
80
sp_cleanup.correct_indentation=false
80
sp_cleanup.correct_indentation=false
81
sp_cleanup.format_source_code=true
81
sp_cleanup.format_source_code=false
82
sp_cleanup.format_source_code_changes_only=false
82
sp_cleanup.format_source_code_changes_only=false
83
sp_cleanup.make_local_variable_final=false
83
sp_cleanup.make_local_variable_final=false
84
sp_cleanup.make_parameters_final=false
84
sp_cleanup.make_parameters_final=false
(-)META-INF/MANIFEST.MF (-1 / +2 lines)
Lines 17-21 Link Here
17
 org.eclipse.jface.examples.databinding.mask.internal;x-internal:=true,
17
 org.eclipse.jface.examples.databinding.mask.internal;x-internal:=true,
18
 org.eclipse.jface.examples.databinding.model;x-internal:=false,
18
 org.eclipse.jface.examples.databinding.model;x-internal:=false,
19
 org.eclipse.jface.examples.databinding.radioGroup;x-internal:=false
19
 org.eclipse.jface.examples.databinding.radioGroup;x-internal:=false
20
Import-Package: com.ibm.icu.text
20
Import-Package: com.ibm.icu.math,
21
 com.ibm.icu.text
21
Bundle-RequiredExecutionEnvironment: J2SE-1.5
22
Bundle-RequiredExecutionEnvironment: J2SE-1.5
(-)src/org/eclipse/jface/examples/databinding/snippets/Snippet035Editing.java (+215 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006, 2009 Ovidio Mallo 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
 *     Ovidio Mallo - initial API and implementation (bug 183055)
10
 ******************************************************************************/
11
12
package org.eclipse.jface.examples.databinding.snippets;
13
14
import java.util.Calendar;
15
import java.util.Date;
16
17
import org.eclipse.core.databinding.Binding;
18
import org.eclipse.core.databinding.DataBindingContext;
19
import org.eclipse.core.databinding.editing.DateEditing;
20
import org.eclipse.core.databinding.editing.Editing;
21
import org.eclipse.core.databinding.editing.IntegerEditing;
22
import org.eclipse.core.databinding.observable.Realm;
23
import org.eclipse.core.databinding.observable.list.WritableList;
24
import org.eclipse.core.databinding.observable.value.IObservableValue;
25
import org.eclipse.core.databinding.observable.value.WritableValue;
26
import org.eclipse.core.runtime.IStatus;
27
import org.eclipse.jface.databinding.swt.ISWTObservableValue;
28
import org.eclipse.jface.databinding.swt.SWTObservables;
29
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
30
import org.eclipse.jface.examples.databinding.util.EditingFactory;
31
import org.eclipse.jface.internal.databinding.provisional.fieldassist.ControlDecorationSupport;
32
import org.eclipse.jface.layout.GridDataFactory;
33
import org.eclipse.jface.layout.GridLayoutFactory;
34
import org.eclipse.jface.viewers.LabelProvider;
35
import org.eclipse.jface.viewers.ListViewer;
36
import org.eclipse.swt.SWT;
37
import org.eclipse.swt.events.FocusAdapter;
38
import org.eclipse.swt.events.FocusEvent;
39
import org.eclipse.swt.events.SelectionAdapter;
40
import org.eclipse.swt.events.SelectionEvent;
41
import org.eclipse.swt.layout.GridLayout;
42
import org.eclipse.swt.widgets.Composite;
43
import org.eclipse.swt.widgets.Control;
44
import org.eclipse.swt.widgets.Display;
45
import org.eclipse.swt.widgets.Group;
46
import org.eclipse.swt.widgets.Label;
47
import org.eclipse.swt.widgets.Shell;
48
import org.eclipse.swt.widgets.Text;
49
50
public class Snippet035Editing {
51
52
	private DataBindingContext dbc;
53
54
	public static void main(String[] args) {
55
		Display display = new Display();
56
57
		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
58
			public void run() {
59
				Shell shell = new Snippet035Editing().createShell();
60
				Display display = Display.getCurrent();
61
				while (!shell.isDisposed()) {
62
					if (!display.readAndDispatch()) {
63
						display.sleep();
64
					}
65
				}
66
			}
67
		});
68
	}
69
70
	private Shell createShell() {
71
		Display display = Display.getCurrent();
72
		Shell shell = new Shell(display);
73
		shell.setText("Editing");
74
		shell.setLayout(new GridLayout(1, false));
75
76
		dbc = new DataBindingContext();
77
78
		createValueSection(shell);
79
		createListSection(shell);
80
81
		shell.pack();
82
		shell.open();
83
84
		return shell;
85
	}
86
87
	private void createValueSection(Composite parent) {
88
		Group section = createSectionGroup(parent, "Value bindings", false);
89
90
		// Edit an e-mail address.
91
		Text emailText = createTextField(section, "E-Mail*");
92
		Editing emailEditing = EditingFactory.forEmailString().required();
93
		bindTextField(emailText, new WritableValue(), emailEditing);
94
95
		// Edit a required, positive integer and use the default validation message.
96
		Text positiveText = createTextField(section, "Positive value*");
97
		IntegerEditing positiveEditing = EditingFactory.forInteger().required().positive();
98
		bindTextField(positiveText, new WritableValue(), positiveEditing);
99
100
		// Edit an integer within the range [1, 100] and use the default
101
		// validation message.
102
		Text rangeText = createTextField(section, "Value in [1, 100]");
103
		IntegerEditing rangeEditing = EditingFactory.forInteger().range(1, 100);
104
		bindTextField(rangeText, new WritableValue(new Integer(0), null), rangeEditing);
105
106
		// Edit a percentage value which must lie within [0, 100] and use a custom
107
		// validation message which indicates that the value actually represents
108
		// a percentage value.
109
		Text percentText = createTextField(section, "Value [%]");
110
		IntegerEditing percentEditing = EditingFactory.forInteger();
111
		percentEditing.modelIntegerConstraints().rangeMessage("Please specify a valid percentage value within [{0}, {1}].").range(0, 100);
112
		bindTextField(percentText, new WritableValue(new Integer(-1), null), percentEditing);
113
114
		// Edit a hex integer within the range [0x00, 0xff]. The range validation
115
		// message will display the range boundaries in hex format as well.
116
		Text hexText = createTextField(section, "Hex value in [0x00, 0xff]");
117
		IntegerEditing hexEditing = EditingFactory.forHexInteger(2).range(0x00, 0xff);
118
		bindTextField(hexText, new WritableValue(new Integer(0), null), hexEditing);
119
	}
120
121
	private void createListSection(Composite parent) {
122
		Group section = createSectionGroup(parent, "List bindings", true);
123
124
		// Our date should be >= 01.01.1990.
125
		Calendar year1990Calendar = Calendar.getInstance();
126
		year1990Calendar.clear();
127
		year1990Calendar.set(1990, 0, 1);
128
		Date year1990 = year1990Calendar.getTime();
129
130
		// Edit a date supporting the default input/display patterns.
131
		Text dateText = createTextField(section, "Date");
132
		DateEditing dateEditing = EditingFactory.forDate().afterEqual(year1990);
133
		final WritableValue dateObservable = new WritableValue();
134
		final Binding dateBinding = bindTextField(dateText, dateObservable, dateEditing);
135
136
		// Create a list to which the dates are added when the user hits ENTER.
137
		new Label(section, SWT.LEFT);
138
		ListViewer dateListViewer = new ListViewer(section);
139
		GridDataFactory.fillDefaults().grab(true, true).hint(150, 200).applyTo(dateListViewer.getList());
140
141
		dateListViewer.setContentProvider(new ObservableListContentProvider());
142
		dateListViewer.setLabelProvider(new LabelProvider());
143
144
		// We use the same DateEditing object as for the text field above to
145
		// create a list binding which maps the entered dates to their string
146
		// representation which is then set as input on the ListViewer.
147
		final WritableList targetDateList = new WritableList();
148
		final WritableList modelDateList = new WritableList();
149
		dbc.bindList(
150
				targetDateList,
151
				modelDateList,
152
				dateEditing.createT2MListStrategy(),
153
				dateEditing.createM2TListStrategy());
154
155
		// Set the list containing the string representation of the dates as input.
156
		dateListViewer.setInput(targetDateList);
157
158
		// Add the current date in the text field when the user hits ENTER.
159
		dateText.addSelectionListener(new SelectionAdapter() {
160
			public void widgetDefaultSelected(SelectionEvent e) {
161
				IStatus dateValidationStatus = (IStatus) dateBinding.getValidationStatus().getValue();
162
				Date date = (Date) dateObservable.getValue();
163
				if (dateValidationStatus.isOK() && date != null) {
164
					modelDateList.add(date);
165
				}
166
			}
167
		});
168
	}
169
170
	private Binding bindTextField(Text text, IObservableValue modelValue, Editing editing) {
171
		// Create the binding using the editing object.
172
		ISWTObservableValue textObservable = SWTObservables.observeText(text, SWT.Modify);
173
		Binding binding = editing.bindValue(dbc, textObservable, modelValue);
174
175
		// Decorate the control with the validation status.
176
		ControlDecorationSupport.create(binding, SWT.TOP);
177
178
		// Re-format when the text field looses the focus in order to always
179
		// display the model in the default format in case multiple input formats
180
		// are supported.
181
		formatOnFocusOut(text, binding);
182
183
		return binding;
184
	}
185
186
	private static void formatOnFocusOut(final Control control, final Binding binding) {
187
		control.addFocusListener(new FocusAdapter() {
188
			public void focusLost(FocusEvent e) {
189
				IStatus dateValidationStatus = (IStatus) binding.getValidationStatus().getValue();
190
				if (dateValidationStatus.isOK()) {
191
					binding.updateModelToTarget();
192
				}
193
			}
194
		});
195
	}
196
197
	private static Group createSectionGroup(Composite parent, String groupText, boolean grabVertical) {
198
		Group section = new Group(parent, SWT.SHADOW_ETCHED_IN);
199
		section.setText(groupText);
200
		GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(false).margins(5, 5).spacing(15, 5).applyTo(section);
201
		GridDataFactory.fillDefaults().grab(true, grabVertical).applyTo(section);
202
		return section;
203
	}
204
205
	private static Text createTextField(Composite parent, String labelText) {
206
		Label label = new Label(parent, SWT.LEFT);
207
		label.setText(labelText);
208
		GridDataFactory.fillDefaults().align(SWT.LEFT, SWT.CENTER).applyTo(label);
209
210
		Text text = new Text(parent, SWT.BORDER);
211
		GridDataFactory.fillDefaults().grab(true, false).hint(150, SWT.DEFAULT).applyTo(text);
212
213
		return text;
214
	}
215
}
(-)src/org/eclipse/jface/examples/databinding/util/EditingFactory.java (+117 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 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
12
package org.eclipse.jface.examples.databinding.util;
13
14
import org.eclipse.core.databinding.editing.DateEditing;
15
import org.eclipse.core.databinding.editing.IntegerEditing;
16
import org.eclipse.core.databinding.editing.StringEditing;
17
18
import com.ibm.icu.text.DateFormat;
19
import com.ibm.icu.text.SimpleDateFormat;
20
21
/**
22
 * @since 3.2
23
 */
24
public final class EditingFactory {
25
26
	private static final String REQUIRED_MESSAGE = "Please specify a value.";
27
28
	private static final String INTEGER_PARSE_ERROR_MESSAGE = "The input is invalid.";
29
30
	private static final String INTEGER_OUT_OF_RANGE_MESSAGE = "The value lies outside the supported range.";
31
32
	private static final String INTEGER_RANGE_MESSAGE = "The value must lie between {0} and {1}.";
33
34
	private static final String[] DATE_INPUT_PATTERNS = new String[] {
35
		"dd.MM.yy",
36
		"dd/MM/yy",
37
		"dd.MM.yyyy",
38
		"dd/MM/yyyy"
39
	};
40
41
	private static final String DATE_DISPLAY_PATTERN = "dd.MM.yyyy";
42
43
	private static final String DATE_PARSE_ERROR_MESSAGE = createDateParseErrorMessage(DATE_INPUT_PATTERNS);
44
45
	private static final String EMAIL_REGEX = "\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}\\b";
46
47
	private static final String EMAIL_ERROR_MESSAGE = "Please specify a valid e-mail address.";
48
49
	private EditingFactory() {
50
		// prevent instantiation
51
	}
52
53
	public static StringEditing forString() {
54
		return StringEditing.stripped(true);
55
	}
56
57
	public static StringEditing forEmailString() {
58
		StringEditing editing = StringEditing.stripped(true);
59
		editing.modelStringConstraints()
60
				.matchesMessage(EMAIL_ERROR_MESSAGE)
61
				.matches(EMAIL_REGEX);
62
		return editing;
63
	}
64
65
	public static IntegerEditing forInteger() {
66
		IntegerEditing editing = IntegerEditing.withDefaults(
67
				INTEGER_PARSE_ERROR_MESSAGE,
68
				INTEGER_OUT_OF_RANGE_MESSAGE);
69
		configure(editing);
70
		return editing;
71
	}
72
73
	public static IntegerEditing forHexInteger(int digits) {
74
		IntegerEditing editing = IntegerEditing.forFormat(
75
				RadixNumberFormat.getHexInstance("0x", digits),
76
				INTEGER_PARSE_ERROR_MESSAGE,
77
				INTEGER_OUT_OF_RANGE_MESSAGE);
78
		configure(editing);
79
		return editing;
80
	}
81
82
	private static void configure(IntegerEditing editing) {
83
		editing.modelIntegerConstraints()
84
				.requiredMessage(REQUIRED_MESSAGE)
85
				.rangeMessage(INTEGER_RANGE_MESSAGE);
86
	}
87
88
	public static DateEditing forDate() {
89
		DateEditing editing = DateEditing
90
				.forFormats(
91
						createDateFormats(DATE_INPUT_PATTERNS),
92
						DATE_PARSE_ERROR_MESSAGE,
93
						new SimpleDateFormat(DATE_DISPLAY_PATTERN));
94
		editing.modelDateConstraints().requiredMessage(REQUIRED_MESSAGE);
95
		return editing;
96
	}
97
98
	private static DateFormat[] createDateFormats(String[] datePatterns) {
99
		DateFormat[] dateFormats = new DateFormat[datePatterns.length];
100
		for (int i = 0; i < dateFormats.length; i++) {
101
			dateFormats[i] = new SimpleDateFormat(datePatterns[i]);
102
		}
103
		return dateFormats;
104
	}
105
106
	private static String createDateParseErrorMessage(String[] datePatterns) {
107
		StringBuffer messageSb = new StringBuffer();
108
		messageSb.append("Supported formats: ");
109
		for (int i = 0; i < datePatterns.length; i++) {
110
			if (i > 0) {
111
				messageSb.append(", ");
112
			}
113
			messageSb.append(datePatterns[i]);
114
		}
115
		return messageSb.toString();
116
	}
117
}
(-)src/org/eclipse/jface/examples/databinding/util/ObservableMapEditingSupport.java (+88 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 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
12
package org.eclipse.jface.examples.databinding.util;
13
14
import org.eclipse.core.databinding.editing.Editing;
15
import org.eclipse.core.databinding.observable.map.IObservableMap;
16
import org.eclipse.core.databinding.util.Policy;
17
import org.eclipse.core.runtime.IStatus;
18
import org.eclipse.core.runtime.MultiStatus;
19
import org.eclipse.jface.dialogs.MessageDialog;
20
import org.eclipse.jface.viewers.CellEditor;
21
import org.eclipse.jface.viewers.ColumnViewer;
22
import org.eclipse.jface.viewers.EditingSupport;
23
import org.eclipse.jface.viewers.TextCellEditor;
24
import org.eclipse.swt.widgets.Composite;
25
26
/**
27
 * @since 3.2
28
 */
29
public class ObservableMapEditingSupport extends EditingSupport {
30
31
	private final IObservableMap attributeMap;
32
33
	private final Editing editing;
34
35
	private final CellEditor cellEditor;
36
37
	public ObservableMapEditingSupport(ColumnViewer viewer, IObservableMap attributeMap, Editing editing) {
38
		super(viewer);
39
		this.attributeMap = attributeMap;
40
		this.editing = editing;
41
		this.cellEditor = new TextCellEditor((Composite) getViewer().getControl());
42
	}
43
44
	protected boolean canEdit(Object element) {
45
		return true;
46
	}
47
48
	protected CellEditor getCellEditor(Object element) {
49
		return cellEditor;
50
	}
51
52
	protected Object getValue(Object element) {
53
		return editing.convertToTarget(attributeMap.get(element));
54
	}
55
56
	protected void setValue(Object element, Object value) {
57
		MultiStatus validationStatus = new MultiStatus(Policy.JFACE_DATABINDING, 0, null, null);
58
		Object modelValue = editing.convertToModel(value, validationStatus);
59
		if (handleValidation(validationStatus)) {
60
			attributeMap.put(element, modelValue);
61
		}
62
	}
63
64
	private boolean handleValidation(IStatus validationStatus) {
65
		if (validationStatus.matches(IStatus.ERROR | IStatus.CANCEL)) {
66
			MessageDialog.openError(getViewer().getControl().getShell(), "Validation Error", getValidationMessage(validationStatus));
67
			return false;
68
		}
69
		return true;
70
	}
71
72
	private static String getValidationMessage(IStatus validationStatus) {
73
		if (!validationStatus.isMultiStatus()) {
74
			return validationStatus.getMessage();
75
		}
76
77
		MultiStatus multiStatus = (MultiStatus) validationStatus;
78
		StringBuffer sb = new StringBuffer();
79
		IStatus[] childStatus = multiStatus.getChildren();
80
		for (int i = 0; i < childStatus.length; i++) {
81
			if (i > 0) {
82
				sb.append('\n');
83
			}
84
			sb.append(getValidationMessage(childStatus[i]));
85
		}
86
		return sb.toString();
87
	}
88
}
(-)src/org/eclipse/jface/examples/databinding/snippets/Snippet036EditingTable.java (+245 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006, 2009 Ovidio Mallo 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
 *     Ovidio Mallo - initial API and implementation (bug 183055)
10
 ******************************************************************************/
11
12
package org.eclipse.jface.examples.databinding.snippets;
13
14
import java.util.Date;
15
16
import org.eclipse.core.databinding.Binding;
17
import org.eclipse.core.databinding.DataBindingContext;
18
import org.eclipse.core.databinding.beans.BeansObservables;
19
import org.eclipse.core.databinding.editing.DateEditing;
20
import org.eclipse.core.databinding.editing.Editing;
21
import org.eclipse.core.databinding.editing.IntegerEditing;
22
import org.eclipse.core.databinding.editing.StringEditing;
23
import org.eclipse.core.databinding.observable.Realm;
24
import org.eclipse.core.databinding.observable.list.WritableList;
25
import org.eclipse.core.databinding.observable.map.IObservableMap;
26
import org.eclipse.core.databinding.observable.set.IObservableSet;
27
import org.eclipse.core.databinding.observable.value.IObservableValue;
28
import org.eclipse.core.runtime.IStatus;
29
import org.eclipse.jface.databinding.swt.ISWTObservableValue;
30
import org.eclipse.jface.databinding.swt.SWTObservables;
31
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
32
import org.eclipse.jface.databinding.viewers.ViewersObservables;
33
import org.eclipse.jface.examples.databinding.ModelObject;
34
import org.eclipse.jface.examples.databinding.util.EditingFactory;
35
import org.eclipse.jface.examples.databinding.util.ObservableMapEditingCellLabelProvider;
36
import org.eclipse.jface.examples.databinding.util.ObservableMapEditingSupport;
37
import org.eclipse.jface.internal.databinding.provisional.fieldassist.ControlDecorationSupport;
38
import org.eclipse.jface.layout.GridDataFactory;
39
import org.eclipse.jface.layout.GridLayoutFactory;
40
import org.eclipse.jface.viewers.StructuredSelection;
41
import org.eclipse.jface.viewers.TableViewer;
42
import org.eclipse.jface.viewers.TableViewerColumn;
43
import org.eclipse.swt.SWT;
44
import org.eclipse.swt.events.FocusAdapter;
45
import org.eclipse.swt.events.FocusEvent;
46
import org.eclipse.swt.layout.GridLayout;
47
import org.eclipse.swt.widgets.Composite;
48
import org.eclipse.swt.widgets.Control;
49
import org.eclipse.swt.widgets.Display;
50
import org.eclipse.swt.widgets.Group;
51
import org.eclipse.swt.widgets.Label;
52
import org.eclipse.swt.widgets.Shell;
53
import org.eclipse.swt.widgets.Text;
54
55
public class Snippet036EditingTable {
56
57
	private final StringEditing nameEditing = EditingFactory.forString().required();
58
59
	private final IntegerEditing ageEditing = EditingFactory.forInteger().required().nonNegative();
60
61
	private final DateEditing bdayEditing = EditingFactory.forDate().before(new Date());
62
63
	private DataBindingContext dbc;
64
65
	private TableViewer tableViewer;
66
67
	public static void main(String[] args) {
68
		Display display = new Display();
69
70
		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
71
			public void run() {
72
				Shell shell = new Snippet036EditingTable().createShell();
73
				Display display = Display.getCurrent();
74
				while (!shell.isDisposed()) {
75
					if (!display.readAndDispatch()) {
76
						display.sleep();
77
					}
78
				}
79
			}
80
		});
81
	}
82
83
	private Shell createShell() {
84
		Display display = Display.getCurrent();
85
		Shell shell = new Shell(display);
86
		shell.setText("Editing");
87
		shell.setLayout(new GridLayout(2, false));
88
89
		dbc = new DataBindingContext();
90
91
		createTableSection(shell);
92
		createFieldSection(shell);
93
94
		shell.pack();
95
		shell.open();
96
97
		return shell;
98
	}
99
100
	private void createTableSection(Composite parent) {
101
		Group section = createSectionGroup(parent, 1);
102
103
		tableViewer = new TableViewer(section, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION);
104
		GridDataFactory.fillDefaults().grab(true, true).hint(350, 250).applyTo(tableViewer.getTable());
105
		tableViewer.getTable().setHeaderVisible(true);
106
		tableViewer.getTable().setLinesVisible(true);
107
108
		ObservableListContentProvider contentProvider = new ObservableListContentProvider();
109
		tableViewer.setContentProvider(contentProvider);
110
		IObservableSet contentElements = contentProvider.getKnownElements();
111
112
		IObservableMap nameMap = BeansObservables.observeMap(contentElements, "name");
113
		createColumn("Name*", 150, nameMap, nameEditing);
114
115
		IObservableMap ageMap = BeansObservables.observeMap(contentElements, "age");
116
		createColumn("Age*", 50, ageMap, ageEditing);
117
118
		IObservableMap bdayMap = BeansObservables.observeMap(contentElements, "birthday");
119
		createColumn("Birthday", 80, bdayMap, bdayEditing);
120
121
		WritableList people = new WritableList();
122
		people.add(new Person("John Doe", 27));
123
		people.add(new Person("Steve Northover", 33));
124
		people.add(new Person("Grant Gayed", 54));
125
		people.add(new Person("Veronika Irvine", 25));
126
		people.add(new Person("Mike Wilson", 44));
127
		people.add(new Person("Christophe Cornu", 37));
128
		people.add(new Person("Lynne Kues", 65));
129
		people.add(new Person("Silenio Quarti", 15));
130
131
		tableViewer.setInput(people);
132
133
		tableViewer.setSelection(new StructuredSelection(people.get(0)));
134
	}
135
136
	private TableViewerColumn createColumn(String text, int width, IObservableMap attributeMap, Editing modelEditing) {
137
		TableViewerColumn column = new TableViewerColumn(tableViewer, SWT.NONE);
138
		column.getColumn().setText(text);
139
		column.getColumn().setWidth(width);
140
		column.setLabelProvider(new ObservableMapEditingCellLabelProvider(attributeMap, modelEditing));
141
		column.setEditingSupport(new ObservableMapEditingSupport(tableViewer, attributeMap, modelEditing));
142
		return column;
143
	}
144
145
	private void createFieldSection(Composite parent) {
146
		final Group section = createSectionGroup(parent, 2);
147
148
		final IObservableValue personObservable = ViewersObservables.observeSingleSelection(tableViewer);
149
150
		Text nameText = createTextField(section, "Name*");
151
		IObservableValue nameObservable = BeansObservables.observeDetailValue(personObservable, "name", null);
152
		bindTextField(nameText, nameObservable, nameEditing);
153
154
		Text ageText = createTextField(section, "Age*");
155
		IObservableValue ageObservable = BeansObservables.observeDetailValue(personObservable, "age", null);
156
		bindTextField(ageText, ageObservable, ageEditing);
157
158
		Text bdayText = createTextField(section, "Birthday");
159
		IObservableValue bdayObservable = BeansObservables.observeDetailValue(personObservable, "birthday", null);
160
		bindTextField(bdayText, bdayObservable, bdayEditing);
161
	}
162
163
	private Binding bindTextField(
164
			Text text,
165
			IObservableValue modelValue,
166
			Editing editing) {
167
		// Create the binding using the editing object.
168
		ISWTObservableValue textObservable = SWTObservables.observeText(text, SWT.Modify);
169
		Binding binding = editing.bindValue(dbc, textObservable, modelValue);
170
171
		// Decorate the control with the validation status.
172
		ControlDecorationSupport.create(binding, SWT.TOP);
173
174
		formatOnFocusOut(text, binding);
175
176
		return binding;
177
	}
178
179
	private static void formatOnFocusOut(final Control control, final Binding binding) {
180
		control.addFocusListener(new FocusAdapter() {
181
			public void focusLost(FocusEvent e) {
182
				IStatus dateValidationStatus = (IStatus) binding.getValidationStatus().getValue();
183
				if (dateValidationStatus.isOK()) {
184
					binding.updateModelToTarget();
185
				}
186
			}
187
		});
188
	}
189
190
	private Group createSectionGroup(Composite parent, int numColumns) {
191
		Group section = new Group(parent, SWT.SHADOW_ETCHED_IN);
192
		GridLayoutFactory.fillDefaults().numColumns(numColumns).equalWidth(false).margins(5, 5).spacing(15, 5).applyTo(section);
193
		GridDataFactory.fillDefaults().grab(true, true).applyTo(section);
194
		return section;
195
	}
196
197
	private static Text createTextField(Composite parent, String labelText) {
198
		Label label = new Label(parent, SWT.LEFT);
199
		label.setText(labelText);
200
		GridDataFactory.fillDefaults().align(SWT.LEFT, SWT.CENTER).applyTo(label);
201
202
		Text text = new Text(parent, SWT.BORDER);
203
		GridDataFactory.fillDefaults().grab(true, false).hint(200, SWT.DEFAULT).applyTo(text);
204
205
		return text;
206
	}
207
208
	public static final class Person extends ModelObject {
209
210
		private String name;
211
212
		private int age;
213
214
		private Date birthday;
215
216
		public Person(String name, int age) {
217
			this.name = name;
218
			this.age = age;
219
		}
220
221
		public String getName() {
222
			return name;
223
		}
224
225
		public void setName(String name) {
226
			firePropertyChange("name", this.name, this.name = name);
227
		}
228
229
		public int getAge() {
230
			return age;
231
		}
232
233
		public void setAge(int age) {
234
			firePropertyChange("age", this.age, this.age = age);
235
		}
236
237
		public Date getBirthday() {
238
			return birthday;
239
		}
240
241
		public void setBirthday(Date birthday) {
242
			firePropertyChange("birthday", this.birthday, this.birthday = birthday);
243
		}
244
	}
245
}
(-)src/org/eclipse/jface/examples/databinding/util/RadixNumberFormat.java (+100 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 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
12
package org.eclipse.jface.examples.databinding.util;
13
14
import java.math.BigInteger;
15
import java.text.FieldPosition;
16
import java.text.ParsePosition;
17
18
import com.ibm.icu.math.BigDecimal;
19
import com.ibm.icu.text.NumberFormat;
20
21
/**
22
 * @since 3.2
23
 *
24
 */
25
public class RadixNumberFormat extends NumberFormat {
26
27
	private static final long serialVersionUID = 411884077848863891L;
28
29
	private final int radix;
30
31
	private final String prefix;
32
33
	private final int digits;
34
35
	private RadixNumberFormat(int radix, String prefix, int digits) {
36
		this.radix = radix;
37
		this.prefix = prefix != null ? prefix : "";
38
		this.digits = digits;
39
	}
40
41
	public static RadixNumberFormat getHexInstance() {
42
		return getHexInstance(null, 0);
43
	}
44
45
	public static RadixNumberFormat getHexInstance(String prefix, int digits) {
46
		return new RadixNumberFormat(16, prefix, digits);
47
	}
48
49
	public StringBuffer format(double number, StringBuffer toAppendTo,
50
			FieldPosition pos) {
51
		// TODO omallo: Is this necessary due to a bug in NumberFormat.format(Object, ...)?
52
		return format((long) number, toAppendTo, pos);
53
	}
54
55
	public StringBuffer format(long number, StringBuffer toAppendTo,
56
			FieldPosition pos) {
57
		return toAppendTo.append(prefix).append(addPadding(Long.toString(number, radix)));
58
	}
59
60
	public StringBuffer format(BigInteger number, StringBuffer toAppendTo,
61
			FieldPosition pos) {
62
		return toAppendTo.append(prefix).append(addPadding(number.toString(radix)));
63
	}
64
65
	public StringBuffer format(BigDecimal number, StringBuffer toAppendTo,
66
			FieldPosition pos) {
67
		throw new UnsupportedOperationException();
68
	}
69
70
	public Number parse(String text, ParsePosition parsePosition) {
71
		if (text.length() == 0) {
72
			return null;
73
		}
74
75
		parsePosition.setIndex(parsePosition.getIndex() + text.length());
76
77
		try {
78
			if (text.startsWith(prefix)) {
79
				return Integer.parseInt(text.substring(prefix.length()), radix);
80
			}
81
			return Integer.parseInt(text, radix);
82
		} catch (NumberFormatException e) {
83
			parsePosition.setErrorIndex(0);
84
			return null;
85
		}
86
	}
87
88
	private String addPadding(String numberText) {
89
		if (numberText.length() >= digits) {
90
			return numberText;
91
		}
92
93
		StringBuffer sb = new StringBuffer();
94
		for (int i = numberText.length(); i < digits; i++) {
95
			sb.append('0');
96
		}
97
		sb.append(numberText);
98
		return sb.toString();
99
	}
100
}
(-)src/org/eclipse/jface/examples/databinding/util/ObservableMapEditingCellLabelProvider.java (+40 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 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
12
package org.eclipse.jface.examples.databinding.util;
13
14
import org.eclipse.core.databinding.editing.Editing;
15
import org.eclipse.core.databinding.observable.map.IObservableMap;
16
import org.eclipse.jface.databinding.viewers.ObservableMapCellLabelProvider;
17
import org.eclipse.jface.viewers.ViewerCell;
18
19
/**
20
 * @since 3.2
21
 */
22
public class ObservableMapEditingCellLabelProvider extends
23
		ObservableMapCellLabelProvider {
24
25
	private final IObservableMap attributeMap;
26
27
	private final Editing editing;
28
29
	public ObservableMapEditingCellLabelProvider(IObservableMap attributeMap, Editing editing) {
30
		super(attributeMap);
31
		this.attributeMap = attributeMap;
32
		this.editing = editing;
33
	}
34
35
	public void update(ViewerCell cell) {
36
		Object element = cell.getElement();
37
		Object attribute = attributeMap.get(element);
38
		cell.setText((String) editing.convertToTarget(attribute));
39
	}
40
}
(-)src/org/eclipse/core/tests/internal/databinding/BindingMessagesTest.java (-2 / +2 lines)
Lines 21-33 Link Here
21
public class BindingMessagesTest extends TestCase {
21
public class BindingMessagesTest extends TestCase {
22
	public void testFormatString() throws Exception {
22
	public void testFormatString() throws Exception {
23
		String key = "Validate_NumberOutOfRangeError";
23
		String key = "Validate_NumberOutOfRangeError";
24
		String result = BindingMessages.formatString(key, new Object[] {"1", "2"});
24
		String result = BindingMessages.getFormattedString(key, new Object[] {"1", "2"});
25
		assertFalse("key should not be returned", key.equals(result));
25
		assertFalse("key should not be returned", key.equals(result));
26
	}
26
	}
27
	
27
	
28
	public void testFormatStringForKeyNotFound() throws Exception {
28
	public void testFormatStringForKeyNotFound() throws Exception {
29
		String key = "key_that_does_not_exist";
29
		String key = "key_that_does_not_exist";
30
		String result = BindingMessages.formatString(key, null);
30
		String result = BindingMessages.getFormattedString(key, null);
31
		assertTrue(key.equals(result));
31
		assertTrue(key.equals(result));
32
	}
32
	}
33
}
33
}

Return to bug 183055