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 (-4 / +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 formatString(String key, Object[] arguments) {
137
		try {
137
		try {
138
			return MessageFormat.format(bundle.getString(key), arguments);
138
			return formatStringValue(getString(key), arguments);
139
		} catch (MissingResourceException e) {
139
		} catch (MissingResourceException e) {
140
			return key;
140
			return key;
141
		}
141
		}
142
	}
142
	}
143
144
	/**
145
	 * Returns a formatted string with the given key in the resource bundle for
146
	 * JFace Data Binding.
147
	 * 
148
	 * @param pattern
149
	 * @param arguments
150
	 * @return formatted string, the key if the key is invalid
151
	 */
152
	public static String formatStringValue(String pattern, Object[] arguments) {
153
		return MessageFormat.format(pattern, arguments);
154
	}
143
}
155
}
(-)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 (-45 / +68 lines)
Lines 31-115 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
57
	 * first successful run.
73
	 * the 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
60
	 * @return The parsed date, or null, if no available formatter could interpret the input string
76
	 *            A string specifying a date according to the default locale or
77
	 *            in raw milliseconds
78
	 * @return The parsed date, or null, if no available formatter could
79
	 *         interpret the input string
61
	 */
80
	 */
62
	protected Date parse(String str) {
81
	protected Date parse(String str) {
63
		for (int formatterIdx = 0; formatterIdx < formatters.length; formatterIdx++) {
82
		for (int formatterIdx = 0; formatterIdx < formatters.length; formatterIdx++) {
64
			Date parsed=parse(str,formatterIdx);
83
			Date parsed = parse(str, formatterIdx);
65
			if(parsed!=null) {
84
			if (parsed != null) {
66
				return parsed;
85
				return parsed;
67
			}
86
			}
68
		}
87
		}
69
		return null;
88
		return null;
70
	}
89
	}
71
90
72
	protected Date parse(String str,int formatterIdx) {
91
	protected Date parse(String str, int formatterIdx) {
73
		if(formatterIdx>=0) {
92
		if (formatterIdx >= 0) {
74
				ParsePosition pos=new ParsePosition(0);
93
			ParsePosition pos = new ParsePosition(0);
75
				if (str == null) {
94
			if (str == null) {
76
					return null;
95
				return null;
77
				}
96
			}
78
				Date date=formatters[formatterIdx].parse(str,pos);
97
			Date date = formatters[formatterIdx].parse(str, pos);
79
				if(pos.getErrorIndex()!=-1||pos.getIndex()!=str.length()) {
98
			if (pos.getErrorIndex() != -1 || pos.getIndex() != str.length()) {
80
					return null;
99
				return null;
81
				}
100
			}
82
				return date;
101
			return date;
83
		}
102
		}
84
		try {
103
		try {
85
			long millisecs=Long.parseLong(str);
104
			long millisecs = Long.parseLong(str);
86
			return new Date(millisecs);
105
			return new Date(millisecs);
87
		}
106
		} catch (NumberFormatException exc) {
88
		catch(NumberFormatException exc) {
89
		}
107
		}
90
		return null;
108
		return null;
91
	}
109
	}
92
110
93
	/**
111
	/**
94
	 * Formats the given date with the default formatter according to the default locale.
112
	 * Formats the given date with the default formatter according to the
95
	 * @param date a date
113
	 * default locale.
96
	 * @return a string representation of the given date according to the default locale
114
	 * 
115
	 * @param date
116
	 *            a date
117
	 * @return a string representation of the given date according to the
118
	 *         default locale
97
	 */
119
	 */
98
	protected String format(Date date) {
120
	protected String format(Date date) {
99
		return format(date,DEFAULT_FORMATTER_INDEX);
121
		return format(date, DEFAULT_FORMATTER_INDEX);
100
	}
122
	}
101
123
102
	protected String format(Date date,int formatterIdx) {
124
	protected String format(Date date, int formatterIdx) {
103
		if (date == null)
125
		if (date == null)
104
			return null;
126
			return null;
105
		if(formatterIdx>=0) {
127
		if (formatterIdx >= 0) {
106
			return formatters[formatterIdx].format(date);
128
			return formatters[formatterIdx].format(date);
107
		}
129
		}
108
		return String.valueOf(date.getTime());
130
		return String.valueOf(date.getTime());
109
	}
131
	}
110
132
111
	protected int numFormatters() {
133
	protected int numFormatters() {
112
		return formatters.length+NUM_VIRTUAL_FORMATTERS;
134
		return formatters.length + NUM_VIRTUAL_FORMATTERS;
113
	}
135
	}
114
136
115
	/**
137
	/**
Lines 118-130 Link Here
118
	 * This is for testing purposes only and should not be a part of the API if
140
	 * This is for testing purposes only and should not be a part of the API if
119
	 * this class was to be exposed.
141
	 * this class was to be exposed.
120
	 * </p>
142
	 * </p>
121
	 *
143
	 * 
122
	 * @param index
144
	 * @param index
123
	 * @return date format
145
	 * @return date format
124
	 */
146
	 */
125
	protected DateFormat getDateFormat(int index) {
147
	protected DateFormat getDateFormat(int index) {
126
		if (index < 0 || index >= formatters.length) {
148
		if (index < 0 || index >= formatters.length) {
127
			throw new IllegalArgumentException("'index' [" + index + "] is out of bounds.");  //$NON-NLS-1$//$NON-NLS-2$
149
			throw new IllegalArgumentException(
150
					"'index' [" + index + "] is out of bounds."); //$NON-NLS-1$//$NON-NLS-2$
128
		}
151
		}
129
152
130
		return formatters[index];
153
		return formatters[index];
(-)src/org/eclipse/core/internal/databinding/conversion/StringToNumberParser.java (-35 / +58 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-138 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.formatString(
119
					new Object[] { value, new Integer(errorIndex + 1),
119
					BindingMessages.VALIDATE_NUMBER_PARSE_ERROR, new Object[] {
120
							value, new Integer(errorIndex + 1),
120
							new Character(value.charAt(errorIndex)) });
121
							new Character(value.charAt(errorIndex)) });
121
		}
122
		}
122
		return BindingMessages.formatString(BindingMessages.VALIDATE_NUMBER_PARSE_ERROR_NO_CHARACTER,
123
		return BindingMessages.formatString(
124
				BindingMessages.VALIDATE_NUMBER_PARSE_ERROR_NO_CHARACTER,
123
				new Object[] { value, new Integer(errorIndex + 1) });
125
				new Object[] { value, new Integer(errorIndex + 1) });
124
	}
126
	}
125
127
126
	/**
128
	/**
127
	 * Formats an appropriate message for an out of range error.
129
	 * Formats an appropriate message for an out of range error.
128
	 *
130
	 * 
129
	 * @param minValue
131
	 * @param minValue
130
	 * @param maxValue
132
	 * @param maxValue
131
	 * @param numberFormat when accessed method synchronizes on instance
133
	 * @param numberFormat
134
	 *            when accessed method synchronizes on instance
132
	 * @return message
135
	 * @return message
133
	 */
136
	 */
134
	public static String createOutOfRangeMessage(Number minValue,
137
	public static String createOutOfRangeMessage(Number minValue,
135
			Number maxValue, NumberFormat numberFormat) {
138
			Number maxValue, NumberFormat numberFormat) {
139
		return createOutOfRangeMessage(
140
				BindingMessages.getString("Validate_NumberOutOfRangeError"), minValue, maxValue, numberFormat); //$NON-NLS-1$
141
	}
142
143
	/**
144
	 * Formats an appropriate message for an out of range error.
145
	 * 
146
	 * @param message
147
	 * @param minValue
148
	 * @param maxValue
149
	 * @param numberFormat
150
	 *            when accessed method synchronizes on instance
151
	 * @return message
152
	 */
153
	public static String createOutOfRangeMessage(String message,
154
			Number minValue, Number maxValue, NumberFormat numberFormat) {
136
		String min = null;
155
		String min = null;
137
		String max = null;
156
		String max = null;
138
157
Lines 141-154 Link Here
141
			max = numberFormat.format(maxValue);
160
			max = numberFormat.format(maxValue);
142
		}
161
		}
143
162
144
		return BindingMessages.formatString(
163
		return BindingMessages.formatStringValue(message, new Object[] { min,
145
				"Validate_NumberOutOfRangeError", new Object[] { min, max }); //$NON-NLS-1$
164
				max });
146
	}
165
	}
147
166
148
	/**
167
	/**
149
	 * Returns <code>true</code> if the provided <code>number</code> is in
168
	 * Returns <code>true</code> if the provided <code>number</code> is in the
150
	 * the range of a integer.
169
	 * range of a integer.
151
	 *
170
	 * 
152
	 * @param number
171
	 * @param number
153
	 * @return <code>true</code> if a valid integer
172
	 * @return <code>true</code> if a valid integer
154
	 * @throws IllegalArgumentException
173
	 * @throws IllegalArgumentException
Lines 160-168 Link Here
160
179
161
	/**
180
	/**
162
	 * Validates the range of the provided <code>number</code>.
181
	 * Validates the range of the provided <code>number</code>.
163
	 *
182
	 * 
164
	 * @param number
183
	 * @param number
165
	 * @param bitLength number of bits allowed to be in range
184
	 * @param bitLength
185
	 *            number of bits allowed to be in range
166
	 * @return <code>true</code> if in range
186
	 * @return <code>true</code> if in range
167
	 */
187
	 */
168
	private static boolean checkInteger(Number number, int bitLength) {
188
	private static boolean checkInteger(Number number, int bitLength) {
Lines 202-210 Link Here
202
	}
222
	}
203
223
204
	/**
224
	/**
205
	 * Returns <code>true</code> if the provided <code>number</code> is in
225
	 * Returns <code>true</code> if the provided <code>number</code> is in the
206
	 * the range of a long.
226
	 * range of a long.
207
	 *
227
	 * 
208
	 * @param number
228
	 * @param number
209
	 * @return <code>true</code> if in range
229
	 * @return <code>true</code> if in range
210
	 * @throws IllegalArgumentException
230
	 * @throws IllegalArgumentException
Lines 215-233 Link Here
215
	}
235
	}
216
236
217
	/**
237
	/**
218
	 * Returns <code>true</code> if the provided <code>number</code> is in
238
	 * Returns <code>true</code> if the provided <code>number</code> is in the
219
	 * the range of a float.
239
	 * range of a float.
220
	 *
240
	 * 
221
	 * @param number
241
	 * @param number
222
	 * @return <code>true</code> if in range
242
	 * @return <code>true</code> if in range
223
	 * @throws IllegalArgumentException
243
	 * @throws IllegalArgumentException
224
	 *             if the number type is unsupported
244
	 *             if the number type is unsupported
225
	 */
245
	 */
226
	public static boolean inFloatRange(Number number) {
246
	public static boolean inFloatRange(Number number) {
227
		return checkDecimal(number, FLOAT_MIN_BIG_DECIMAL, FLOAT_MAX_BIG_DECIMAL);
247
		return checkDecimal(number, FLOAT_MIN_BIG_DECIMAL,
248
				FLOAT_MAX_BIG_DECIMAL);
228
	}
249
	}
229
250
230
	private static boolean checkDecimal(Number number, BigDecimal min, BigDecimal max) {
251
	private static boolean checkDecimal(Number number, BigDecimal min,
252
			BigDecimal max) {
231
		BigDecimal bigDecimal = null;
253
		BigDecimal bigDecimal = null;
232
		if (number instanceof Integer || number instanceof Long) {
254
		if (number instanceof Integer || number instanceof Long) {
233
			bigDecimal = new BigDecimal(number.doubleValue());
255
			bigDecimal = new BigDecimal(number.doubleValue());
Lines 265-286 Link Here
265
	}
287
	}
266
288
267
	/**
289
	/**
268
	 * Returns <code>true</code> if the provided <code>number</code> is in
290
	 * Returns <code>true</code> if the provided <code>number</code> is in the
269
	 * the range of a double.
291
	 * range of a double.
270
	 *
292
	 * 
271
	 * @param number
293
	 * @param number
272
	 * @return <code>true</code> if in range
294
	 * @return <code>true</code> if in range
273
	 * @throws IllegalArgumentException
295
	 * @throws IllegalArgumentException
274
	 *             if the number type is unsupported
296
	 *             if the number type is unsupported
275
	 */
297
	 */
276
	public static boolean inDoubleRange(Number number) {
298
	public static boolean inDoubleRange(Number number) {
277
		return checkDecimal(number, DOUBLE_MIN_BIG_DECIMAL, DOUBLE_MAX_BIG_DECIMAL);
299
		return checkDecimal(number, DOUBLE_MIN_BIG_DECIMAL,
300
				DOUBLE_MAX_BIG_DECIMAL);
278
	}
301
	}
279
302
280
	/**
303
	/**
281
	 * Returns <code>true</code> if the provided <code>number</code> is in
304
	 * Returns <code>true</code> if the provided <code>number</code> is in the
282
	 * the range of a short.
305
	 * range of a short.
283
	 *
306
	 * 
284
	 * @param number
307
	 * @param number
285
	 * @return <code>true</code> if in range
308
	 * @return <code>true</code> if in range
286
	 */
309
	 */
Lines 289-297 Link Here
289
	}
312
	}
290
313
291
	/**
314
	/**
292
	 * Returns <code>true</code> if the provided <code>number</code> is in
315
	 * Returns <code>true</code> if the provided <code>number</code> is in the
293
	 * the range of a byte.
316
	 * range of a byte.
294
	 *
317
	 * 
295
	 * @param number
318
	 * @param number
296
	 * @return <code>true</code> if in range
319
	 * @return <code>true</code> if in range
297
	 */
320
	 */
(-)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 (-3 / +15 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-38 Link Here
31
		super(converter, MIN, MAX);
30
		super(converter, MIN, MAX);
32
	}
31
	}
33
32
34
	/* (non-Javadoc)
33
	/**
35
	 * @see org.eclipse.core.internal.databinding.validation.AbstractStringToNumberValidator#inRange(java.lang.Number)
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
43
	/*
44
	 * (non-Javadoc)
45
	 * 
46
	 * @seeorg.eclipse.core.internal.databinding.validation.
47
	 * AbstractStringToNumberValidator#inRange(java.lang.Number)
36
	 */
48
	 */
37
	protected boolean isInRange(Number number) {
49
	protected boolean isInRange(Number number) {
38
		return StringToNumberParser.inIntegerRange(number);
50
		return StringToNumberParser.inIntegerRange(number);
(-)src/org/eclipse/core/internal/databinding/validation/StringToDateValidator.java (-14 / +40 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
54
	 * org.eclipse.core.databinding.validation.IValidator#validate(java.lang
55
	 * .Object)
42
	 */
56
	 */
43
	public IStatus validate(Object value) {
57
	public IStatus validate(Object value) {
44
		if (value instanceof String && ((String)value).trim().length()==0) {
58
		if (value instanceof String && ((String) value).trim().length() == 0) {
45
			return Status.OK_STATUS;
59
			return Status.OK_STATUS;
46
		}
60
		}
47
		Object convertedValue = converter.convert(value);
61
		Object convertedValue = converter.convert(value);
48
		//The StringToDateConverter returns null if it can't parse the date.
62
		// The StringToDateConverter returns null if it can't parse the date.
49
		if (convertedValue == null) {
63
		if (convertedValue == null) {
50
			return ValidationStatus.error(getErrorMessage());
64
			return ValidationStatus.error(getErrorMessage());
51
		}
65
		}
Lines 55-64 Link Here
55
69
56
	/*
70
	/*
57
	 * (non-Javadoc)
71
	 * (non-Javadoc)
58
	 *
72
	 * 
59
	 * @see org.eclipse.core.internal.databinding.validation.WrappedConverterValidator#getErrorMessage()
73
	 * @see
74
	 * org.eclipse.core.internal.databinding.validation.WrappedConverterValidator
75
	 * #getErrorMessage()
60
	 */
76
	 */
61
	protected String getErrorMessage() {
77
	protected String getErrorMessage() {
78
		if (parseErrorMessage != null) {
79
			return parseErrorMessage;
80
		}
81
62
		Date sampleDate = new Date();
82
		Date sampleDate = new Date();
63
83
64
		// FIXME We need to use the information from the
84
		// FIXME We need to use the information from the
Lines 73-86 Link Here
73
		samples.append('\'');
93
		samples.append('\'');
74
		samples.append(util.format(sampleDate, 0));
94
		samples.append(util.format(sampleDate, 0));
75
		samples.append('\'');
95
		samples.append('\'');
76
		return BindingMessages.getString(BindingMessages.EXAMPLES) + ": " + samples + ",..."; //$NON-NLS-1$//$NON-NLS-2$
96
		return BindingMessages.getString(BindingMessages.EXAMPLES)
97
				+ ": " + samples + ",..."; //$NON-NLS-1$//$NON-NLS-2$
77
	}
98
	}
78
99
79
	private static class FormatUtil extends DateConversionSupport {
100
	private static class FormatUtil extends DateConversionSupport {
80
		/*
101
		/*
81
		 * (non-Javadoc)
102
		 * (non-Javadoc)
82
		 *
103
		 * 
83
		 * @see org.eclipse.core.internal.databinding.conversion.DateConversionSupport#numFormatters()
104
		 * @see
105
		 * org.eclipse.core.internal.databinding.conversion.DateConversionSupport
106
		 * #numFormatters()
84
		 */
107
		 */
85
		protected int numFormatters() {
108
		protected int numFormatters() {
86
			return super.numFormatters();
109
			return super.numFormatters();
Lines 88-95 Link Here
88
111
89
		/*
112
		/*
90
		 * (non-Javadoc)
113
		 * (non-Javadoc)
91
		 *
114
		 * 
92
		 * @see org.eclipse.core.internal.databinding.conversion.DateConversionSupport#format(java.util.Date)
115
		 * @see
116
		 * org.eclipse.core.internal.databinding.conversion.DateConversionSupport
117
		 * #format(java.util.Date)
93
		 */
118
		 */
94
		protected String format(Date date) {
119
		protected String format(Date date) {
95
			return super.format(date);
120
			return super.format(date);
Lines 97-105 Link Here
97
122
98
		/*
123
		/*
99
		 * (non-Javadoc)
124
		 * (non-Javadoc)
100
		 *
125
		 * 
101
		 * @see org.eclipse.core.internal.databinding.conversion.DateConversionSupport#format(java.util.Date,
126
		 * @see
102
		 *      int)
127
		 * org.eclipse.core.internal.databinding.conversion.DateConversionSupport
128
		 * #format(java.util.Date, int)
103
		 */
129
		 */
104
		protected String format(Date date, int formatterIdx) {
130
		protected String format(Date date, int formatterIdx) {
105
			return super.format(date, formatterIdx);
131
			return super.format(date, formatterIdx);
(-)src/org/eclipse/core/internal/databinding/validation/AbstractStringToNumberValidator.java (-14 / +59 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 19-26 Link Here
19
import org.eclipse.core.runtime.Status;
21
import org.eclipse.core.runtime.Status;
20
22
21
/**
23
/**
22
 * Validates a number that is to be converted by a {@link NumberFormatConverter}.
24
 * Validates a number that is to be converted by a {@link NumberFormatConverter}
23
 * Validation is comprised of parsing the String and range checks.
25
 * . Validation is comprised of parsing the String and range checks.
24
 * 
26
 * 
25
 * @since 1.0
27
 * @since 1.0
26
 */
28
 */
Lines 31-50 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.
38
	 * 
43
	 * 
39
	 * @param converter converter and thus formatter to be used in validation
44
	 * @param converter
40
	 * @param min minimum value, used for reporting a range error to the user
45
	 *            converter and thus formatter to be used in validation
41
	 * @param max maximum value, used for reporting a range error to the user
46
	 * @param min
47
	 *            minimum value, used for reporting a range error to the user
48
	 * @param max
49
	 *            maximum value, used for reporting a range error to the user
42
	 */
50
	 */
43
	protected AbstractStringToNumberValidator(NumberFormatConverter converter,
51
	protected AbstractStringToNumberValidator(NumberFormatConverter converter,
44
			Number min, Number max) {
52
			Number min, Number max) {
53
		this(converter, min, max, null, null);
54
	}
55
56
	/**
57
	 * Constructs a new instance.
58
	 * 
59
	 * @param converter
60
	 *            converter and thus formatter to be used in validation
61
	 * @param min
62
	 *            minimum value, used for reporting a range error to the user
63
	 * @param max
64
	 *            maximum value, used for reporting a range error to the user
65
	 * @param parseErrorMessage
66
	 * @param outOfRangeMessage
67
	 */
68
	protected AbstractStringToNumberValidator(NumberFormatConverter converter,
69
			Number min, Number max, String parseErrorMessage,
70
			String outOfRangeMessage) {
45
		this.converter = converter;
71
		this.converter = converter;
46
		this.min = min;
72
		this.min = min;
47
		this.max = max;
73
		this.max = max;
74
		this.parseErrorMessage = parseErrorMessage;
75
		this.outOfRangeMessage = outOfRangeMessage;
48
76
49
		if (converter.getToType() instanceof Class) {
77
		if (converter.getToType() instanceof Class) {
50
			Class clazz = (Class) converter.getToType();
78
			Class clazz = (Class) converter.getToType();
Lines 55-61 Link Here
55
	}
83
	}
56
84
57
	/**
85
	/**
58
	 * Validates the provided <code>value</code>.  An error status is returned if:
86
	 * Validates the provided <code>value</code>. An error status is returned
87
	 * if:
59
	 * <ul>
88
	 * <ul>
60
	 * <li>The value cannot be parsed.</li>
89
	 * <li>The value cannot be parsed.</li>
61
	 * <li>The value is out of range.</li>
90
	 * <li>The value is out of range.</li>
Lines 69-85 Link Here
69
98
70
		if (result.getNumber() != null) {
99
		if (result.getNumber() != null) {
71
			if (!isInRange(result.getNumber())) {
100
			if (!isInRange(result.getNumber())) {
72
				if (outOfRangeMessage == null) {
101
				if (formattedOutOfRangeMessage == null) {
73
					outOfRangeMessage = StringToNumberParser
102
					formattedOutOfRangeMessage = createOutOfRangeMessage();
74
							.createOutOfRangeMessage(min, max, converter
75
									.getNumberFormat());
76
				}
103
				}
77
104
78
				return ValidationStatus.error(outOfRangeMessage);
105
				return ValidationStatus.error(formattedOutOfRangeMessage);
79
			}
106
			}
80
		} else if (result.getPosition() != null) {
107
		} else if (result.getPosition() != null) {
81
			String parseErrorMessage = StringToNumberParser.createParseErrorMessage(
108
			String parseErrorMessage = createParseErrorMessage((String) value,
82
					(String) value, result.getPosition());
109
					result.getPosition());
83
110
84
			return ValidationStatus.error(parseErrorMessage);
111
			return ValidationStatus.error(parseErrorMessage);
85
		}
112
		}
Lines 94-97 Link Here
94
	 * @return <code>true</code> if in range
121
	 * @return <code>true</code> if in range
95
	 */
122
	 */
96
	protected abstract boolean isInRange(Number number);
123
	protected abstract boolean isInRange(Number number);
124
125
	private String createParseErrorMessage(String input,
126
			ParsePosition parsePosition) {
127
		if (parseErrorMessage == null) {
128
			return StringToNumberParser.createParseErrorMessage(input,
129
					parsePosition);
130
		}
131
		return parseErrorMessage;
132
	}
133
134
	private String createOutOfRangeMessage() {
135
		if (outOfRangeMessage == null) {
136
			return StringToNumberParser.createOutOfRangeMessage(min, max,
137
					converter.getNumberFormat());
138
		}
139
		return StringToNumberParser.createOutOfRangeMessage(outOfRangeMessage,
140
				min, max, converter.getNumberFormat());
141
	}
97
}
142
}
(-)META-INF/MANIFEST.MF (+1 lines)
Lines 8-13 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,
12
 org.eclipse.core.internal.databinding;x-friends:="org.eclipse.core.databinding.beans",
13
 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",
14
 org.eclipse.core.internal.databinding.conversion;x-friends:="org.eclipse.jface.tests.databinding",
(-)src/org/eclipse/core/internal/databinding/validation/DateRangeValidator.java (+177 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.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 final DateFormat format;
47
48
	/**
49
	 * 
50
	 * @param min
51
	 * @param max
52
	 * @param minConstraint
53
	 * @param maxConstraint
54
	 * @param validationMessage
55
	 * @param format
56
	 */
57
	private DateRangeValidator(Date min, Date max, int minConstraint,
58
			int maxConstraint, String validationMessage, DateFormat format) {
59
		this.min = min;
60
		this.max = max;
61
		this.minConstraint = minConstraint;
62
		this.maxConstraint = maxConstraint;
63
		this.validationMessage = validationMessage;
64
		this.format = format;
65
	}
66
67
	/**
68
	 * 
69
	 * @param min
70
	 * @param validationMessage
71
	 * @param format
72
	 * @return .
73
	 */
74
	public static DateRangeValidator after(Date min, String validationMessage,
75
			DateFormat format) {
76
		return new DateRangeValidator(min, null, AFTER, UNDEFINED,
77
				defaultIfNull(validationMessage, AFTER_MESSAGE), format);
78
	}
79
80
	/**
81
	 * 
82
	 * @param min
83
	 * @param validationMessage
84
	 * @param format
85
	 * @return .
86
	 */
87
	public static DateRangeValidator afterEqual(Date min,
88
			String validationMessage, DateFormat format) {
89
		return new DateRangeValidator(min, null, AFTER_EQUAL, UNDEFINED,
90
				defaultIfNull(validationMessage, AFTER_EQUAL_MESSAGE), format);
91
	}
92
93
	/**
94
	 * 
95
	 * @param max
96
	 * @param validationMessage
97
	 * @param format
98
	 * @return .
99
	 */
100
	public static DateRangeValidator before(Date max, String validationMessage,
101
			DateFormat format) {
102
		return new DateRangeValidator(null, max, UNDEFINED, BEFORE,
103
				defaultIfNull(validationMessage, BEFORE_MESSAGE), format);
104
	}
105
106
	/**
107
	 * 
108
	 * @param max
109
	 * @param validationMessage
110
	 * @param format
111
	 * @return .
112
	 */
113
	public static DateRangeValidator beforeEqual(Date max,
114
			String validationMessage, DateFormat format) {
115
		return new DateRangeValidator(null, max, UNDEFINED, BEFORE_EQUAL,
116
				defaultIfNull(validationMessage, BEFORE_EQUAL_MESSAGE), format);
117
	}
118
119
	/**
120
	 * 
121
	 * @param min
122
	 * @param max
123
	 * @param validationMessage
124
	 * @param format
125
	 * @return .
126
	 */
127
	public static DateRangeValidator range(Date min, Date max,
128
			String validationMessage, DateFormat format) {
129
		return new DateRangeValidator(min, max, AFTER_EQUAL, BEFORE_EQUAL,
130
				defaultIfNull(validationMessage, WITHIN_RANGE_MESSAGE), format);
131
	}
132
133
	public IStatus validate(Object value) {
134
		if (value != null) {
135
			Date date = (Date) value;
136
			if ((min != null && !fulfillsConstraint(date, min, minConstraint))
137
					|| (max != null && !fulfillsConstraint(date, max,
138
							maxConstraint))) {
139
				// TODO: Cache message?
140
				return ValidationStatus.error(MessageFormat.format(
141
						validationMessage, getFormattedRangeExtremas()));
142
			}
143
		}
144
		return ValidationStatus.ok();
145
	}
146
147
	private boolean fulfillsConstraint(Date date1, Date date2, int constraint) {
148
		switch (constraint) {
149
		case AFTER:
150
			return date1.after(date2);
151
		case AFTER_EQUAL:
152
			return date1.after(date2) || date1.equals(date2);
153
		case BEFORE:
154
			return date1.before(date2);
155
		case BEFORE_EQUAL:
156
			return date1.before(date2) || date1.equals(date2);
157
		case UNDEFINED:
158
		default:
159
			throw new IllegalArgumentException(
160
					"Unsupported constraint: " + constraint); //$NON-NLS-1$
161
		}
162
	}
163
164
	private String[] getFormattedRangeExtremas() {
165
		// TODO: Synchronize formatting to make it thread safe?
166
		if (min == null) {
167
			return new String[] { format.format(max) };
168
		} else if (max == null) {
169
			return new String[] { format.format(min) };
170
		}
171
		return new String[] { format.format(min), format.format(max) };
172
	}
173
174
	private static String defaultIfNull(String string, String defaultString) {
175
		return (string != null) ? string : defaultString;
176
	}
177
}
(-)src/org/eclipse/core/databinding/editing/StringEditing.java (+119 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.core.databinding.editing;
13
14
import java.util.regex.Pattern;
15
16
import org.eclipse.core.databinding.conversion.IConverter;
17
import org.eclipse.core.internal.databinding.conversion.StringStripConverter;
18
import org.eclipse.core.internal.databinding.validation.NonNullValidator;
19
import org.eclipse.core.internal.databinding.validation.StringRegexValidator;
20
21
/**
22
 * @since 1.3
23
 */
24
public final class StringEditing extends Editing {
25
26
	private String requiredMessage = null;
27
28
	private String matchesMessage = null;
29
30
	private StringEditing(IConverter targetConverter) {
31
		setTargetConverter(targetConverter);
32
	}
33
34
	/**
35
	 * Creates a new editing object for strings which performs no validation or
36
	 * conversion.
37
	 * 
38
	 * @return The new editing object which performs no validation or
39
	 *         conversion.
40
	 */
41
	public static StringEditing withDefaults() {
42
		return new StringEditing(null);
43
	}
44
45
	/**
46
	 * Creates a new editing object which strips whitespace from both ends of
47
	 * the input string.
48
	 * 
49
	 * @param stripToNull
50
	 *            Whether to convert the input string to <code>null</code> in
51
	 *            case stripping the input string results in an empty string.
52
	 * @return The new editing object which strips whitespace from both ends of
53
	 *         the input string.
54
	 */
55
	public static StringEditing stripped(boolean stripToNull) {
56
		return new StringEditing(new StringStripConverter(stripToNull));
57
	}
58
59
	/**
60
	 * Adds a model validator ensuring that the parsed integer is not
61
	 * <code>null</code>. Uses the current {@link #requiredMessage(String)
62
	 * validation message}.
63
	 * 
64
	 * @return This editing instance for method chaining.
65
	 */
66
	public StringEditing required() {
67
		addModelValidator(new NonNullValidator(requiredMessage));
68
		return this;
69
	}
70
71
	/**
72
	 * Sets the validation message to be issued in case the input string is
73
	 * <code>null</code>.
74
	 * 
75
	 * @param message
76
	 *            The validation message to be issued in case the input string
77
	 *            is <code>null</code>.
78
	 * @return This editing instance for method chaining.
79
	 * 
80
	 * @see #required()
81
	 */
82
	public StringEditing requiredMessage(String message) {
83
		this.requiredMessage = message;
84
		return this;
85
	}
86
87
	/**
88
	 * Adds a model validator ensuring that the input string
89
	 * {@link Pattern#matches(String, CharSequence) matches} the given regular
90
	 * expression . Uses the current {@link #matchesMessage(String) validation
91
	 * message}.
92
	 * 
93
	 * @param regex
94
	 *            The regular expression which the input string must match.
95
	 * @return This editing instance for method chaining.
96
	 * 
97
	 * @see Pattern#matches(String, CharSequence)
98
	 */
99
	public StringEditing matches(String regex) {
100
		addModelValidator(new StringRegexValidator(regex, matchesMessage));
101
		return this;
102
	}
103
104
	/**
105
	 * Sets the validation message to be issued in case the input string does
106
	 * not match a given regular expression.
107
	 * 
108
	 * @param message
109
	 *            The validation message to be issued in case the input string
110
	 *            does not match a given regular expression.
111
	 * @return This editing instance for method chaining.
112
	 * 
113
	 * @see #matches(String)
114
	 */
115
	public StringEditing matchesMessage(String message) {
116
		this.matchesMessage = message;
117
		return this;
118
	}
119
}
(-)src/org/eclipse/core/internal/databinding/validation/NonNullValidator.java (+47 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.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/StringRegexValidator.java (+68 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.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 regular expression: {0}."; //$NON-NLS-1$
29
30
	private final String regex;
31
32
	private final Pattern pattern;
33
34
	private final String validationMessage;
35
36
	/**
37
	 * 
38
	 * @param regex
39
	 */
40
	public StringRegexValidator(String regex) {
41
		this(regex, null);
42
	}
43
44
	/**
45
	 * 
46
	 * @param regex
47
	 * @param validationMessage
48
	 */
49
	public StringRegexValidator(String regex, String validationMessage) {
50
		this.regex = regex;
51
		this.pattern = Pattern.compile(regex);
52
		this.validationMessage = validationMessage != null ? validationMessage
53
				: REGEX_VALIDATION_MESSAGE;
54
	}
55
56
	public IStatus validate(Object value) {
57
		String input = (String) value;
58
		if (input != null) {
59
			Matcher matcher = pattern.matcher(input);
60
			if (!matcher.matches()) {
61
				// TODO: Cache message?
62
				return ValidationStatus.error(MessageFormat.format(
63
						validationMessage, new String[] { regex }));
64
			}
65
		}
66
		return ValidationStatus.ok();
67
	}
68
}
(-)src/org/eclipse/core/internal/databinding/validation/IntegerRangeValidator.java (+140 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.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/CompositeValidator.java (+46 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.core.internal.databinding.validation;
13
14
import org.eclipse.core.databinding.validation.IValidator;
15
import org.eclipse.core.runtime.IStatus;
16
import org.eclipse.core.runtime.Status;
17
18
/**
19
 * @since 1.3
20
 */
21
public class CompositeValidator implements IValidator {
22
23
	private final IValidator[] validators;
24
25
	/**
26
	 * @param validators
27
	 */
28
	public CompositeValidator(IValidator[] validators) {
29
		this.validators = validators;
30
	}
31
32
	public IStatus validate(Object value) {
33
		// TODO: Define an aggregation strategy.
34
		int maxSeverity = IStatus.OK;
35
		IStatus maxStatus = Status.OK_STATUS;
36
		for (int i = 0; i < validators.length; i++) {
37
			IValidator validator = validators[i];
38
			IStatus status = validator.validate(value);
39
			if (status.getSeverity() > maxSeverity) {
40
				maxSeverity = status.getSeverity();
41
				maxStatus = status;
42
			}
43
		}
44
		return maxStatus;
45
	}
46
}
(-)src/org/eclipse/core/databinding/editing/IntegerEditing.java (+373 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.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.internal.databinding.validation.IntegerRangeValidator;
17
import org.eclipse.core.internal.databinding.validation.NonNullValidator;
18
import org.eclipse.core.internal.databinding.validation.StringToIntegerValidator;
19
20
import com.ibm.icu.text.NumberFormat;
21
22
/**
23
 * @since 1.3
24
 */
25
public final class IntegerEditing extends Editing {
26
27
	private final NumberFormat format;
28
29
	private String requiredMessage = null;
30
31
	private String greaterMessage = null;
32
33
	private String greaterEqualMessage = null;
34
35
	private String lessMessage = null;
36
37
	private String lessEqualMessage = null;
38
39
	private String rangeMessage = null;
40
41
	private String positiveMessage = null;
42
43
	private String nonNegativeMessage = null;
44
45
	private IntegerEditing(NumberFormat format, String parseErrorMessage,
46
			String outOfRangeMessage) {
47
		this.format = format;
48
49
		StringToNumberConverter targetConverter = StringToNumberConverter
50
				.toInteger(format, false);
51
52
		addTargetValidator(new StringToIntegerValidator(targetConverter,
53
				parseErrorMessage, outOfRangeMessage));
54
		setTargetConverter(targetConverter);
55
		setModelConverter(NumberToStringConverter.fromInteger(format, false));
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
	 * default validation messages.
62
	 * 
63
	 * @return The new editing object using the default validations and
64
	 *         conversions for editing.
65
	 * 
66
	 * @see NumberFormat#getIntegerInstance()
67
	 */
68
	public static IntegerEditing withDefaults() {
69
		return withDefaults(null, null);
70
	}
71
72
	/**
73
	 * Creates a new editing object which defaults the validations and
74
	 * conversions used for editing based on the platform's locale. Uses the
75
	 * specified custom validation messages.
76
	 * 
77
	 * @param parseErrorMessage
78
	 *            The validation message issued in case the input string cannot
79
	 *            be parsed to an integer.
80
	 * @param outOfRangeMessage
81
	 *            The validation message issued in case the input string
82
	 *            represents an integer whose value is out of range. Can be
83
	 *            parameterized by the <code>Integer.MIN_VALUE</code> and
84
	 *            <code>Integer.MAX_VALUE</code> values.
85
	 * @return The new editing object using the default validations and
86
	 *         conversions for editing.
87
	 */
88
	public static IntegerEditing withDefaults(String parseErrorMessage,
89
			String outOfRangeMessage) {
90
		return new IntegerEditing(NumberFormat.getIntegerInstance(),
91
				parseErrorMessage, outOfRangeMessage);
92
	}
93
94
	/**
95
	 * Creates a new editing object whose validations and conversions used for
96
	 * editing are based on the given integer format. Uses the default
97
	 * validation messages.
98
	 * 
99
	 * @param format
100
	 *            The integer format defining the validations and conversions
101
	 *            used for editing.
102
	 * @return The new editing object configured by the given integer format.
103
	 */
104
	public static IntegerEditing forFormat(NumberFormat format) {
105
		return forFormat(format, null, null);
106
	}
107
108
	/**
109
	 * Creates a new editing object whose validations and conversions used for
110
	 * editing are based on the given integer format. Uses the specified custom
111
	 * validation messages.
112
	 * 
113
	 * @param format
114
	 *            The integer format defining the validations and conversions
115
	 *            used for editing.
116
	 * @param parseErrorMessage
117
	 *            The validation message issued in case the input string cannot
118
	 *            be parsed to an integer.
119
	 * @param outOfRangeMessage
120
	 *            The validation message issued in case the input string
121
	 *            represents an integer whose value is out of range. Can be
122
	 *            parameterized by the <code>Integer.MIN_VALUE</code> and
123
	 *            <code>Integer.MAX_VALUE</code> values.
124
	 * @return The new editing object configured by the given integer format.
125
	 */
126
	public static IntegerEditing forFormat(NumberFormat format,
127
			String parseErrorMessage, String outOfRangeMessage) {
128
		return new IntegerEditing(format, parseErrorMessage, outOfRangeMessage);
129
	}
130
131
	/**
132
	 * Adds a model validator ensuring that the parsed integer is not
133
	 * <code>null</code>. Uses the current {@link #requiredMessage(String)
134
	 * validation message}.
135
	 * 
136
	 * @return This editing instance for method chaining.
137
	 */
138
	public IntegerEditing required() {
139
		addModelValidator(new NonNullValidator(requiredMessage));
140
		return this;
141
	}
142
143
	/**
144
	 * Sets the validation message to be issued in case the parsed integer is
145
	 * <code>null</code>.
146
	 * 
147
	 * @param message
148
	 *            The validation message to be issued in case the parsed integer
149
	 *            is <code>null</code>.
150
	 * @return This editing instance for method chaining.
151
	 * 
152
	 * @see #required()
153
	 */
154
	public IntegerEditing requiredMessage(String message) {
155
		this.requiredMessage = message;
156
		return this;
157
	}
158
159
	/**
160
	 * Adds a model validator ensuring that the parsed integer is greater than
161
	 * the given number. Uses the current {@link #greaterMessage(String)
162
	 * validation message}.
163
	 * 
164
	 * @param number
165
	 *            The number which the parsed integer must be greater than.
166
	 * @return This editing instance for method chaining.
167
	 */
168
	public IntegerEditing greater(int number) {
169
		addModelValidator(IntegerRangeValidator.greater(number, greaterMessage,
170
				format));
171
		return this;
172
	}
173
174
	/**
175
	 * Sets the validation message to be issued in case the parsed integer is
176
	 * not greater than a given number.
177
	 * 
178
	 * @param message
179
	 *            The validation message to be issued in case the parsed integer
180
	 *            is not greater than a given number.
181
	 * @return This editing instance for method chaining.
182
	 * 
183
	 * @see #greater(int)
184
	 */
185
	public IntegerEditing greaterMessage(String message) {
186
		this.greaterMessage = message;
187
		return this;
188
	}
189
190
	/**
191
	 * Adds a model validator ensuring that the parsed integer is greater than
192
	 * or equal to the given number. Uses the current
193
	 * {@link #greaterEqualMessage(String) validation message}.
194
	 * 
195
	 * @param number
196
	 *            The number which the parsed integer must be greater than or
197
	 *            equal to.
198
	 * @return This editing instance for method chaining.
199
	 */
200
	public IntegerEditing greaterEqual(int number) {
201
		addModelValidator(IntegerRangeValidator.greaterEqual(number,
202
				greaterEqualMessage, format));
203
		return this;
204
	}
205
206
	/**
207
	 * Sets the validation message to be issued in case the parsed integer is
208
	 * not greater than or equal to a given number.
209
	 * 
210
	 * @param message
211
	 *            The validation message to be issued in case the parsed integer
212
	 *            is not greater than or equal to a given number.
213
	 * @return This editing instance for method chaining.
214
	 * 
215
	 * @see #greaterEqual(int)
216
	 */
217
	public IntegerEditing greaterEqualMessage(String message) {
218
		this.greaterEqualMessage = message;
219
		return this;
220
	}
221
222
	/**
223
	 * Adds a model validator ensuring that the parsed integer is less than the
224
	 * given number. Uses the current {@link #lessMessage(String) validation
225
	 * message}.
226
	 * 
227
	 * @param number
228
	 *            The number which the parsed integer must be less than.
229
	 * @return This editing instance for method chaining.
230
	 */
231
	public IntegerEditing less(int number) {
232
		addModelValidator(IntegerRangeValidator.less(number, lessMessage,
233
				format));
234
		return this;
235
	}
236
237
	/**
238
	 * Sets the validation message to be issued in case the parsed integer is
239
	 * not less than a given number.
240
	 * 
241
	 * @param message
242
	 *            The validation message to be issued in case the parsed integer
243
	 *            is not less than a given number.
244
	 * @return This editing instance for method chaining.
245
	 * 
246
	 * @see #less(int)
247
	 */
248
	public IntegerEditing lessMessage(String message) {
249
		this.lessMessage = message;
250
		return this;
251
	}
252
253
	/**
254
	 * Adds a model validator ensuring that the parsed integer is less than or
255
	 * equal to the given number. Uses the current
256
	 * {@link #lessEqualMessage(String) validation message}.
257
	 * 
258
	 * @param number
259
	 *            The number which the parsed integer must be less than or equal
260
	 *            to.
261
	 * @return This editing instance for method chaining.
262
	 */
263
	public IntegerEditing lessEqual(int number) {
264
		addModelValidator(IntegerRangeValidator.greaterEqual(number,
265
				lessEqualMessage, format));
266
		return this;
267
	}
268
269
	/**
270
	 * Sets the validation message to be issued in case the parsed integer is
271
	 * not less than or equal to a given number.
272
	 * 
273
	 * @param message
274
	 *            The validation message to be issued in case the parsed integer
275
	 *            is not less than or equal to a given number.
276
	 * @return This editing instance for method chaining.
277
	 * 
278
	 * @see #lessEqual(int)
279
	 */
280
	public IntegerEditing lessEqualMessage(String message) {
281
		this.lessEqualMessage = message;
282
		return this;
283
	}
284
285
	/**
286
	 * Adds a model validator ensuring that the parsed integer is within the
287
	 * given range. Uses the current {@link #rangeMessage(String) validation
288
	 * message}.
289
	 * 
290
	 * @param min
291
	 *            The lower bound of the range (inclusive).
292
	 * @param max
293
	 *            The upper bound of the range (inclusive).
294
	 * @return This editing instance for method chaining.
295
	 */
296
	public IntegerEditing range(int min, int max) {
297
		addModelValidator(IntegerRangeValidator.range(min, max, rangeMessage,
298
				format));
299
		return this;
300
	}
301
302
	/**
303
	 * Sets the validation message to be issued in case the parsed integer is
304
	 * not within a given range.
305
	 * 
306
	 * @param message
307
	 *            The validation message to be issued in case the parsed integer
308
	 *            is not within a given range.
309
	 * @return This editing instance for method chaining.
310
	 * 
311
	 * @see #range(int, int)
312
	 */
313
	public IntegerEditing rangeMessage(String message) {
314
		this.rangeMessage = message;
315
		return this;
316
	}
317
318
	/**
319
	 * Adds a model validator ensuring that the parsed integer is positive. Uses
320
	 * the current {@link #positiveMessage(String) validation message}.
321
	 * 
322
	 * @return This editing instance for method chaining.
323
	 */
324
	public IntegerEditing positive() {
325
		addModelValidator(IntegerRangeValidator.positive(positiveMessage,
326
				format));
327
		return this;
328
	}
329
330
	/**
331
	 * Sets the validation message to be issued in case the parsed integer is
332
	 * not positive.
333
	 * 
334
	 * @param message
335
	 *            The validation message to be issued in case the parsed integer
336
	 *            is not positive.
337
	 * @return This editing instance for method chaining.
338
	 * 
339
	 * @see #positive()
340
	 */
341
	public IntegerEditing positiveMessage(String message) {
342
		this.positiveMessage = message;
343
		return this;
344
	}
345
346
	/**
347
	 * Adds a model validator ensuring that the parsed integer is non-negative.
348
	 * Uses the current {@link #nonNegativeMessage(String) validation message}.
349
	 * 
350
	 * @return This editing instance for method chaining.
351
	 */
352
	public IntegerEditing nonNegative() {
353
		addModelValidator(IntegerRangeValidator.nonNegative(nonNegativeMessage,
354
				format));
355
		return this;
356
	}
357
358
	/**
359
	 * Sets the validation message to be issued in case the parsed integer is
360
	 * negative.
361
	 * 
362
	 * @param message
363
	 *            The validation message to be issued in case the parsed integer
364
	 *            is negative.
365
	 * @return This editing instance for method chaining.
366
	 * 
367
	 * @see #nonNegative()
368
	 */
369
	public IntegerEditing nonNegativeMessage(String message) {
370
		this.nonNegativeMessage = message;
371
		return this;
372
	}
373
}
(-)src/org/eclipse/core/databinding/editing/Editing.java (+466 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.core.databinding.editing;
13
14
import java.util.ArrayList;
15
import java.util.List;
16
17
import org.eclipse.core.databinding.UpdateListStrategy;
18
import org.eclipse.core.databinding.UpdateSetStrategy;
19
import org.eclipse.core.databinding.UpdateValueStrategy;
20
import org.eclipse.core.databinding.conversion.IConverter;
21
import org.eclipse.core.databinding.validation.IValidator;
22
import org.eclipse.core.internal.databinding.validation.CompositeValidator;
23
import org.eclipse.core.runtime.IStatus;
24
import org.eclipse.core.runtime.MultiStatus;
25
26
/**
27
 * @since 1.3
28
 */
29
public class Editing {
30
31
	private final List targetValidators = new ArrayList();
32
33
	private IConverter targetConverter;
34
35
	private final List modelValidators = new ArrayList();
36
37
	private final List beforeSetModelValidators = new ArrayList();
38
39
	private IConverter modelConverter;
40
41
	/**
42
	 * Adds a custom target validator.
43
	 * 
44
	 * @param validator
45
	 *            The custom target validator to add.
46
	 * @return This editing instance for method chaining.
47
	 */
48
	public final Editing addTargetValidator(IValidator validator) {
49
		targetValidators.add(validator);
50
		return this;
51
	}
52
53
	/**
54
	 * Adds a custom model validator.
55
	 * 
56
	 * @param validator
57
	 *            The custom model validator to add.
58
	 * @return This editing instance for method chaining.
59
	 */
60
	public final Editing addModelValidator(IValidator validator) {
61
		modelValidators.add(validator);
62
		return this;
63
	}
64
65
	/**
66
	 * Adds a custom before-set model validator.
67
	 * 
68
	 * @param validator
69
	 *            The custom before-set model validator to add.
70
	 * @return This editing instance for method chaining.
71
	 */
72
	public final Editing addBeforeSetModelValidator(IValidator validator) {
73
		beforeSetModelValidators.add(validator);
74
		return this;
75
	}
76
77
	protected final void setTargetConverter(IConverter converter) {
78
		this.targetConverter = converter;
79
	}
80
81
	protected final void setModelConverter(IConverter converter) {
82
		this.modelConverter = converter;
83
	}
84
85
	/**
86
	 * Creates a new target-to-model {@link UpdateValueStrategy} with a default
87
	 * update policy configured by the current state of this editing object.
88
	 * 
89
	 * @return A new target-to-model {@link UpdateValueStrategy} configured by
90
	 *         the current state of this editing object.
91
	 * 
92
	 * @see UpdateValueStrategy#UpdateValueStrategy()
93
	 */
94
	public UpdateValueStrategy createTargetValueStrategy() {
95
		return applyToTargetValueStrategy(new UpdateValueStrategy());
96
	}
97
98
	/**
99
	 * Creates a new target-to-model {@link UpdateValueStrategy} with the given
100
	 * update policy configured by the current state of this editing object.
101
	 * 
102
	 * @param updatePolicy
103
	 *            The update policy to use.
104
	 * @return A new target-to-model {@link UpdateValueStrategy} configured by
105
	 *         the current state of this editing object.
106
	 * 
107
	 * @see UpdateValueStrategy#UpdateValueStrategy(int)
108
	 */
109
	public UpdateValueStrategy createTargetValueStrategy(int updatePolicy) {
110
		return applyToTargetValueStrategy(new UpdateValueStrategy(updatePolicy));
111
	}
112
113
	/**
114
	 * Creates a new model-to-target {@link UpdateValueStrategy} with a default
115
	 * update policy configured by the current state of this editing object.
116
	 * 
117
	 * @return A new model-to-target {@link UpdateValueStrategy} configured by
118
	 *         the current state of this editing object.
119
	 * 
120
	 * @see UpdateValueStrategy#UpdateValueStrategy()
121
	 */
122
	public UpdateValueStrategy createModelValueStrategy() {
123
		return applyToModelValueStrategy(new UpdateValueStrategy());
124
	}
125
126
	/**
127
	 * Creates a new model-to-target {@link UpdateValueStrategy} with the given
128
	 * update policy configured by the current state of this editing object.
129
	 * 
130
	 * @param updatePolicy
131
	 *            The update policy to use.
132
	 * @return A new model-to-target {@link UpdateValueStrategy} configured by
133
	 *         the current state of this editing object.
134
	 * 
135
	 * @see UpdateValueStrategy#UpdateValueStrategy(int)
136
	 */
137
	public UpdateValueStrategy createModelValueStrategy(int updatePolicy) {
138
		return applyToModelValueStrategy(new UpdateValueStrategy(updatePolicy));
139
	}
140
141
	/**
142
	 * Creates a new target-to-model {@link UpdateListStrategy} with a default
143
	 * update policy configured by the current state of this editing object.
144
	 * 
145
	 * @return A new target-to-model {@link UpdateListStrategy} configured by
146
	 *         the current state of this editing object.
147
	 * 
148
	 * @see UpdateListStrategy#UpdateListStrategy()
149
	 */
150
	public UpdateListStrategy createTargetListStrategy() {
151
		return applyToTargetListStrategy(new UpdateListStrategy());
152
	}
153
154
	/**
155
	 * Creates a new target-to-model {@link UpdateListStrategy} with the given
156
	 * update policy configured by the current state of this editing object.
157
	 * 
158
	 * @param updatePolicy
159
	 *            The update policy to use.
160
	 * @return A new target-to-model {@link UpdateListStrategy} configured by
161
	 *         the current state of this editing object.
162
	 * 
163
	 * @see UpdateListStrategy#UpdateListStrategy(int)
164
	 */
165
	public UpdateListStrategy createTargetListStrategy(int updatePolicy) {
166
		return applyToTargetListStrategy(new UpdateListStrategy(updatePolicy));
167
	}
168
169
	/**
170
	 * Creates a new model-to-target {@link UpdateListStrategy} with a default
171
	 * update policy configured by the current state of this editing object.
172
	 * 
173
	 * @return A new model-to-target {@link UpdateListStrategy} configured by
174
	 *         the current state of this editing object.
175
	 * 
176
	 * @see UpdateListStrategy#UpdateListStrategy()
177
	 */
178
	public UpdateListStrategy createModelListStrategy() {
179
		return applyToModelListStrategy(new UpdateListStrategy());
180
	}
181
182
	/**
183
	 * Creates a new model-to-target {@link UpdateListStrategy} with the given
184
	 * update policy configured by the current state of this editing object.
185
	 * 
186
	 * @param updatePolicy
187
	 *            The update policy to use.
188
	 * @return A new model-to-target {@link UpdateListStrategy} configured by
189
	 *         the current state of this editing object.
190
	 * 
191
	 * @see UpdateListStrategy#UpdateListStrategy(int)
192
	 */
193
	public UpdateListStrategy createModelListStrategy(int updatePolicy) {
194
		return applyToModelListStrategy(new UpdateListStrategy(updatePolicy));
195
	}
196
197
	/**
198
	 * Creates a new target-to-model {@link UpdateSetStrategy} with a default
199
	 * update policy configured by the current state of this editing object.
200
	 * 
201
	 * @return A new target-to-model {@link UpdateSetStrategy} configured by the
202
	 *         current state of this editing object.
203
	 * 
204
	 * @see UpdateListStrategy#UpdateListStrategy()
205
	 */
206
	public UpdateSetStrategy createTargetSetStrategy() {
207
		return applyToTargetSetStrategy(new UpdateSetStrategy());
208
	}
209
210
	/**
211
	 * Creates a new target-to-model {@link UpdateListStrategy} with the given
212
	 * update policy configured by the current state of this editing object.
213
	 * 
214
	 * @param updatePolicy
215
	 *            The update policy to use.
216
	 * @return A new target-to-model {@link UpdateListStrategy} configured by
217
	 *         the current state of this editing object.
218
	 * 
219
	 * @see UpdateSetStrategy#UpdateSetStrategy(int)
220
	 */
221
	public UpdateSetStrategy createTargetSetStrategy(int updatePolicy) {
222
		return applyToTargetSetStrategy(new UpdateSetStrategy(updatePolicy));
223
	}
224
225
	/**
226
	 * Creates a new model-to-target {@link UpdateSetStrategy} with a default
227
	 * update policy configured by the current state of this editing object.
228
	 * 
229
	 * @return A new model-to-target {@link UpdateSetStrategy} configured by the
230
	 *         current state of this editing object.
231
	 * 
232
	 * @see UpdateSetStrategy#UpdateSetStrategy()
233
	 */
234
	public UpdateSetStrategy createModelSetStrategy() {
235
		return applyToModelSetStrategy(new UpdateSetStrategy());
236
	}
237
238
	/**
239
	 * Creates a new model-to-target {@link UpdateSetStrategy} with the given
240
	 * update policy configured by the current state of this editing object.
241
	 * 
242
	 * @param updatePolicy
243
	 *            The update policy to use.
244
	 * @return A new model-to-target {@link UpdateSetStrategy} configured by the
245
	 *         current state of this editing object.
246
	 * 
247
	 * @see UpdateSetStrategy#UpdateSetStrategy(int)
248
	 */
249
	public UpdateSetStrategy createModelSetStrategy(int updatePolicy) {
250
		return applyToModelSetStrategy(new UpdateSetStrategy(updatePolicy));
251
	}
252
253
	/**
254
	 * Configures an existing target-to-model {@link UpdateValueStrategy} with
255
	 * the current state of this editing object.
256
	 * 
257
	 * @param updateStrategy
258
	 *            The {@link UpdateValueStrategy} to configure.
259
	 * @return The passed-in, configured target-to-model
260
	 *         {@link UpdateValueStrategy}.
261
	 */
262
	public UpdateValueStrategy applyToTargetValueStrategy(
263
			UpdateValueStrategy updateStrategy) {
264
		updateStrategy.setAfterGetValidator(createTargetValidator());
265
		updateStrategy.setConverter(targetConverter);
266
		updateStrategy.setAfterConvertValidator(createModelValidator());
267
		updateStrategy.setBeforeSetValidator(createBeforeSetModelValidator());
268
		return updateStrategy;
269
	}
270
271
	/**
272
	 * Configures an existing model-to-target {@link UpdateValueStrategy} with
273
	 * the current state of this editing object.
274
	 * 
275
	 * @param updateStrategy
276
	 *            The {@link UpdateValueStrategy} to configure.
277
	 * @return The passed-in, configured model-to-target
278
	 *         {@link UpdateValueStrategy}.
279
	 */
280
	public UpdateValueStrategy applyToModelValueStrategy(
281
			UpdateValueStrategy updateStrategy) {
282
		updateStrategy.setConverter(modelConverter);
283
		return updateStrategy;
284
	}
285
286
	/**
287
	 * Configures an existing target-to-model {@link UpdateListStrategy} with
288
	 * the current state of this editing object.
289
	 * 
290
	 * @param updateStrategy
291
	 *            The {@link UpdateListStrategy} to configure.
292
	 * @return The passed-in, configured target-to-model
293
	 *         {@link UpdateListStrategy}.
294
	 */
295
	public UpdateListStrategy applyToTargetListStrategy(
296
			UpdateListStrategy updateStrategy) {
297
		updateStrategy.setConverter(targetConverter);
298
		return updateStrategy;
299
	}
300
301
	/**
302
	 * Configures an existing model-to-target {@link UpdateListStrategy} with
303
	 * the current state of this editing object.
304
	 * 
305
	 * @param updateStrategy
306
	 *            The {@link UpdateListStrategy} to configure.
307
	 * @return The passed-in, configured model-to-target
308
	 *         {@link UpdateListStrategy}.
309
	 */
310
	public UpdateListStrategy applyToModelListStrategy(
311
			UpdateListStrategy updateStrategy) {
312
		updateStrategy.setConverter(modelConverter);
313
		return updateStrategy;
314
	}
315
316
	/**
317
	 * Configures an existing target-to-model {@link UpdateListStrategy} with
318
	 * the current state of this editing object.
319
	 * 
320
	 * @param updateStrategy
321
	 *            The {@link UpdateSetStrategy} to configure.
322
	 * @return The passed-in, configured target-to-model
323
	 *         {@link UpdateSetStrategy}.
324
	 */
325
	public UpdateSetStrategy applyToTargetSetStrategy(
326
			UpdateSetStrategy updateStrategy) {
327
		updateStrategy.setConverter(targetConverter);
328
		return updateStrategy;
329
	}
330
331
	/**
332
	 * Configures an existing model-to-target {@link UpdateSetStrategy} with the
333
	 * current state of this editing object.
334
	 * 
335
	 * @param updateStrategy
336
	 *            The {@link UpdateSetStrategy} to configure.
337
	 * @return The passed-in, configured model-to-target
338
	 *         {@link UpdateSetStrategy}.
339
	 */
340
	public UpdateSetStrategy applyToModelSetStrategy(
341
			UpdateSetStrategy updateStrategy) {
342
		updateStrategy.setConverter(modelConverter);
343
		return updateStrategy;
344
	}
345
346
	/**
347
	 * Converts a target value to a model value by performing the following
348
	 * steps:
349
	 * <ul>
350
	 * <li>
351
	 * Applying all the currently accumulated
352
	 * {@link #addTargetValidator(IValidator) target validators} to the given
353
	 * target value.</li>
354
	 * <li>
355
	 * {@link #setTargetConverter(IConverter) Converting} the target value to
356
	 * the model value.</li>
357
	 * <li>
358
	 * Applying all the currently accumulated
359
	 * {@link #addModelValidator(IValidator) model validators} to the converted
360
	 * model value.</li>
361
	 * <li>
362
	 * Applying all the currently accumulated
363
	 * {@link #addBeforeSetModelValidator(IValidator) before-set model
364
	 * validators} to the converted model value.</li>
365
	 * </ul>
366
	 * 
367
	 * <p>
368
	 * The conversion process will be aborted by returning <code>null</code>
369
	 * whenever any of the applied validators produces a {@link IStatus
370
	 * validation status} having {@link IStatus#getSeverity() severity}
371
	 * <code>IStatus.ERROR</code> or <code>IStatus.CANCEL</code>. During the
372
	 * conversion process, any validation status whose severity is different
373
	 * from <code>IStatus.OK</code> will be {@link MultiStatus#add(IStatus)
374
	 * added} to the given aggregate <code>validationStatus</code>.
375
	 * </p>
376
	 * 
377
	 * @param targetValue
378
	 *            The target value to be converted to a model value.
379
	 * @param validationStatus
380
	 *            Aggregate validation status to which to add the validations
381
	 *            produced during the conversion process.
382
	 * @return The converted model value or <code>null</code> in case the
383
	 *         conversion has been aborted due to a validation error.
384
	 */
385
	public final Object convertToModel(Object targetValue,
386
			MultiStatus validationStatus) {
387
		// TODO: Cache the target/model validators.
388
		IValidator targetValidator = createTargetValidator();
389
		if (!applyValidator(targetValidator, targetValue, validationStatus)) {
390
			return null;
391
		}
392
393
		Object modelValue = (targetConverter != null) ? targetConverter
394
				.convert(targetValue) : targetValue;
395
396
		IValidator modelValidator = createModelValidator();
397
		if (!applyValidator(modelValidator, modelValue, validationStatus)) {
398
			return null;
399
		}
400
401
		IValidator beforeSetModelValidator = createBeforeSetModelValidator();
402
		if (!applyValidator(beforeSetModelValidator, modelValue,
403
				validationStatus)) {
404
			return null;
405
		}
406
407
		return modelValue;
408
	}
409
410
	/**
411
	 * {@link #setModelConverter(IConverter) Converts} a model value to a target
412
	 * value.
413
	 * 
414
	 * @param modelValue
415
	 *            The target value to be converted to a model value.
416
	 * @return The converted target value.
417
	 */
418
	public final Object convertToTarget(Object modelValue) {
419
		return (modelConverter != null) ? modelConverter.convert(modelValue)
420
				: modelValue;
421
	}
422
423
	private IValidator createTargetValidator() {
424
		if (!targetValidators.isEmpty()) {
425
			CompositeValidator targetValidator = new CompositeValidator(
426
					(IValidator[]) targetValidators
427
							.toArray(new IValidator[targetValidators.size()]));
428
			return targetValidator;
429
		}
430
		return null;
431
	}
432
433
	private IValidator createModelValidator() {
434
		if (!modelValidators.isEmpty()) {
435
			return new CompositeValidator((IValidator[]) modelValidators
436
					.toArray(new IValidator[modelValidators.size()]));
437
		}
438
		return null;
439
	}
440
441
	private IValidator createBeforeSetModelValidator() {
442
		if (!beforeSetModelValidators.isEmpty()) {
443
			return new CompositeValidator(
444
					(IValidator[]) beforeSetModelValidators
445
							.toArray(new IValidator[beforeSetModelValidators
446
									.size()]));
447
		}
448
		return null;
449
	}
450
451
	private static boolean applyValidator(IValidator validator, Object value,
452
			MultiStatus aggregateStatus) {
453
		if (validator != null) {
454
			IStatus validationStatus = validator.validate(value);
455
			if (!validationStatus.isOK()) {
456
				aggregateStatus.add(validationStatus);
457
			}
458
			return isValid(validationStatus);
459
		}
460
		return true;
461
	}
462
463
	private static boolean isValid(IStatus status) {
464
		return status.isOK() || status.matches(IStatus.INFO | IStatus.WARNING);
465
	}
466
}
(-)src/org/eclipse/core/databinding/editing/DateEditing.java (+279 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.core.databinding.editing;
13
14
import java.util.Date;
15
16
import org.eclipse.core.internal.databinding.conversion.DateToStringConverter;
17
import org.eclipse.core.internal.databinding.conversion.StringToDateConverter;
18
import org.eclipse.core.internal.databinding.validation.DateRangeValidator;
19
import org.eclipse.core.internal.databinding.validation.NonNullValidator;
20
import org.eclipse.core.internal.databinding.validation.StringToDateValidator;
21
22
import com.ibm.icu.text.DateFormat;
23
24
/**
25
 * @since 1.3
26
 */
27
public final class DateEditing extends Editing {
28
29
	private final DateFormat displayFormat;
30
31
	private String requiredMessage = null;
32
33
	private String afterMessage = null;
34
35
	private String afterEqualMessage = null;
36
37
	private String beforeMessage = null;
38
39
	private String beforeEqualMessage = null;
40
41
	private DateEditing(DateFormat[] inputFormats, String parseErrorMessage,
42
			DateFormat displayFormat) {
43
		this.displayFormat = displayFormat;
44
45
		StringToDateConverter targetConverter;
46
		if (inputFormats == null) {
47
			targetConverter = new StringToDateConverter();
48
		} else {
49
			targetConverter = new StringToDateConverter(inputFormats);
50
		}
51
52
		addTargetValidator(new StringToDateValidator(targetConverter,
53
				parseErrorMessage));
54
		setTargetConverter(targetConverter);
55
		setModelConverter(displayFormat == null ? new DateToStringConverter()
56
				: new DateToStringConverter(displayFormat));
57
	}
58
59
	/**
60
	 * Creates a new editing object which defaults the validations and
61
	 * conversions used for editing. Uses the default validation message.
62
	 * 
63
	 * @return The new editing object using the default validations and
64
	 *         conversions for editing.
65
	 */
66
	public static DateEditing withDefaults() {
67
		return withDefaults(null);
68
	}
69
70
	/**
71
	 * Creates a new editing object which defaults the validations and
72
	 * conversions used for editing. Uses the specified custom validation
73
	 * message.
74
	 * 
75
	 * @param parseErrorMessage
76
	 *            The validation message issued in case the input string cannot
77
	 *            be parsed to a date.
78
	 * @return The new editing object using the default validations and
79
	 *         conversions for editing.
80
	 */
81
	public static DateEditing withDefaults(String parseErrorMessage) {
82
		return new DateEditing(null, parseErrorMessage, null);
83
	}
84
85
	/**
86
	 * Creates a new editing object which supports all the given date input
87
	 * formats and which uses the specified format for displaying a date. Uses
88
	 * the default validation message.
89
	 * 
90
	 * @param inputFormats
91
	 *            The date formats supported for reading in dates.
92
	 * @param displayFormat
93
	 *            The date format for displaying dates.
94
	 * @return The new editing object configured by the given date formats.
95
	 */
96
	public static DateEditing forFormats(DateFormat[] inputFormats,
97
			DateFormat displayFormat) {
98
		return new DateEditing(inputFormats, null, displayFormat);
99
	}
100
101
	/**
102
	 * Creates a new editing object which supports all the given date input
103
	 * formats and which uses the specified format for displaying a date. Uses
104
	 * the specified custom validation message.
105
	 * 
106
	 * @param inputFormats
107
	 *            The date formats supported for reading in dates.
108
	 * @param parseErrorMessage
109
	 *            The validation message issued in case the input string cannot
110
	 *            be parsed to a date.
111
	 * @param displayFormat
112
	 *            The date format for displaying dates.
113
	 * @return The new editing object configured by the given date formats.
114
	 */
115
	public static DateEditing forFormats(DateFormat[] inputFormats,
116
			String parseErrorMessage, DateFormat displayFormat) {
117
		return new DateEditing(inputFormats, parseErrorMessage, displayFormat);
118
	}
119
120
	/**
121
	 * Adds a model validator ensuring that the parsed date is not
122
	 * <code>null</code>. Uses the current {@link #requiredMessage(String)
123
	 * validation message}.
124
	 * 
125
	 * @return This editing instance for method chaining.
126
	 */
127
	public DateEditing required() {
128
		addModelValidator(new NonNullValidator(requiredMessage));
129
		return this;
130
	}
131
132
	/**
133
	 * Sets the validation message to be issued in case the parsed date is
134
	 * <code>null</code>.
135
	 * 
136
	 * @param message
137
	 *            The validation message to be issued in case the parsed date is
138
	 *            <code>null</code>.
139
	 * @return This editing instance for method chaining.
140
	 * 
141
	 * @see #required()
142
	 */
143
	public DateEditing requiredMessage(String message) {
144
		this.requiredMessage = message;
145
		return this;
146
	}
147
148
	/**
149
	 * Adds a model validator ensuring that the parsed date is after the given
150
	 * date. Uses the current {@link #afterMessage(String) validation message}.
151
	 * 
152
	 * @param date
153
	 *            The date which must be before or on the parsed date.
154
	 * @return This editing instance for method chaining.
155
	 * 
156
	 * @see Date#after(Date)
157
	 */
158
	public DateEditing after(Date date) {
159
		addModelValidator(DateRangeValidator.after(date, afterMessage,
160
				displayFormat));
161
		return this;
162
	}
163
164
	/**
165
	 * Sets the validation message to be issued in case the parsed date is not
166
	 * after a given date.
167
	 * 
168
	 * @param message
169
	 *            The validation message to be issued in case the parsed date is
170
	 *            not after a given date.
171
	 * @return This editing instance for method chaining.
172
	 * 
173
	 * @see #after(Date)
174
	 */
175
	public DateEditing afterMessage(String message) {
176
		this.afterMessage = message;
177
		return this;
178
	}
179
180
	/**
181
	 * Adds a model validator ensuring that the parsed date is after or on the
182
	 * given date. Uses the current {@link #afterEqualMessage(String) validation
183
	 * message}.
184
	 * 
185
	 * @param date
186
	 *            The date which must be before the parsed date.
187
	 * @return This editing instance for method chaining.
188
	 * 
189
	 * @see Date#after(Date)
190
	 * @see Date#equals(Object)
191
	 */
192
	public DateEditing afterEqual(Date date) {
193
		addModelValidator(DateRangeValidator.afterEqual(date,
194
				afterEqualMessage, displayFormat));
195
		return this;
196
	}
197
198
	/**
199
	 * Sets the validation message to be issued in case the parsed date is not
200
	 * after or on a given date.
201
	 * 
202
	 * @param message
203
	 *            The validation message to be issued in case the parsed date is
204
	 *            not after or on a given date.
205
	 * @return This editing instance for method chaining.
206
	 * 
207
	 * @see #afterEqual(Date)
208
	 */
209
	public DateEditing afterEqualMessage(String message) {
210
		this.afterEqualMessage = message;
211
		return this;
212
	}
213
214
	/**
215
	 * Adds a model validator ensuring that the parsed date is before the given
216
	 * date. Uses the current {@link #beforeMessage(String) validation message}.
217
	 * 
218
	 * @param date
219
	 *            The date which must be after or on the parsed date.
220
	 * @return This editing instance for method chaining.
221
	 * 
222
	 * @see Date#before(Date)
223
	 */
224
	public DateEditing before(Date date) {
225
		addModelValidator(DateRangeValidator.before(date, beforeMessage,
226
				displayFormat));
227
		return this;
228
	}
229
230
	/**
231
	 * Sets the validation message to be issued in case the parsed date is not
232
	 * before a given date.
233
	 * 
234
	 * @param message
235
	 *            The validation message to be issued in case the parsed date is
236
	 *            not before a given date.
237
	 * @return This editing instance for method chaining.
238
	 * 
239
	 * @see #before(Date)
240
	 */
241
	public DateEditing beforeMessage(String message) {
242
		this.beforeMessage = message;
243
		return this;
244
	}
245
246
	/**
247
	 * Adds a model validator ensuring that the parsed date is before or on the
248
	 * given date. Uses the current {@link #beforeEqualMessage(String)
249
	 * validation message}.
250
	 * 
251
	 * @param date
252
	 *            The date which must be after the parsed date.
253
	 * @return This editing instance for method chaining.
254
	 * 
255
	 * @see Date#before(Date)
256
	 * @see Date#equals(Object)
257
	 */
258
	public DateEditing beforeEqual(Date date) {
259
		addModelValidator(DateRangeValidator.beforeEqual(date,
260
				beforeEqualMessage, displayFormat));
261
		return this;
262
	}
263
264
	/**
265
	 * Sets the validation message to be issued in case the parsed date is not
266
	 * before or on a given date.
267
	 * 
268
	 * @param message
269
	 *            The validation message to be issued in case the parsed date is
270
	 *            not before or on a given date.
271
	 * @return This editing instance for method chaining.
272
	 * 
273
	 * @see #beforeEqual(Date)
274
	 */
275
	public DateEditing beforeEqualMessage(String message) {
276
		this.beforeEqualMessage = message;
277
		return this;
278
	}
279
}
(-)src/org/eclipse/core/internal/databinding/conversion/StringStripConverter.java (+61 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.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 = null;
52
			}
53
		}
54
55
		if (string == null || string.length() == 0) {
56
			string = stripToNull ? null : ""; //$NON-NLS-1$
57
		}
58
59
		return string;
60
	}
61
}
(-)src/org/eclipse/core/internal/databinding/validation/NumberRangeValidator.java (+112 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.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 final NumberFormat format;
48
49
	/**
50
	 * 
51
	 * @param min
52
	 * @param max
53
	 * @param minConstraint
54
	 * @param maxConstraint
55
	 * @param validationMessage
56
	 * @param format
57
	 */
58
	protected NumberRangeValidator(Number min, Number max, int minConstraint,
59
			int maxConstraint, String validationMessage, NumberFormat 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
	public IStatus validate(Object value) {
69
		if (value != null) {
70
			Number number = (Number) value;
71
			if ((min != null && !fulfillsConstraint(number, min, minConstraint))
72
					|| (max != null && !fulfillsConstraint(number, max,
73
							maxConstraint))) {
74
				// TODO: Cache message?
75
				return ValidationStatus.error(MessageFormat.format(
76
						validationMessage, getFormattedRangeExtremas()));
77
			}
78
		}
79
		return ValidationStatus.ok();
80
	}
81
82
	private boolean fulfillsConstraint(Number number1, Number number2,
83
			int constraint) {
84
		int compareResult = compare(number1, number2);
85
		switch (constraint) {
86
		case GREATER:
87
			return compareResult > 0;
88
		case GREATER_EQUAL:
89
			return compareResult >= 0;
90
		case LESS:
91
			return compareResult < 0;
92
		case LESS_EQUAL:
93
			return compareResult <= 0;
94
		case UNDEFINED:
95
		default:
96
			throw new IllegalArgumentException(
97
					"Unsupported constraint: " + constraint); //$NON-NLS-1$
98
		}
99
	}
100
101
	protected abstract int compare(Number number1, Number number2);
102
103
	private String[] getFormattedRangeExtremas() {
104
		// TODO: Synchronize formatting to make it thread safe?
105
		if (min == null) {
106
			return new String[] { format.format(max) };
107
		} else if (max == null) {
108
			return new String[] { format.format(min) };
109
		}
110
		return new String[] { format.format(min), format.format(max) };
111
	}
112
}
(-)META-INF/MANIFEST.MF (-1 / +2 lines)
Lines 11-17 Link Here
11
 org.eclipse.core.runtime,
11
 org.eclipse.core.runtime,
12
 org.eclipse.core.databinding.beans,
12
 org.eclipse.core.databinding.beans,
13
 org.eclipse.jface.databinding,
13
 org.eclipse.jface.databinding,
14
 org.eclipse.core.databinding.property
14
 org.eclipse.core.databinding.property,
15
 com.ibm.icu;bundle-version="3.8.1"
15
Export-Package: org.eclipse.jface.examples.databinding;x-internal:=false,
16
Export-Package: org.eclipse.jface.examples.databinding;x-internal:=false,
16
 org.eclipse.jface.examples.databinding.mask;x-internal:=false,
17
 org.eclipse.jface.examples.databinding.mask;x-internal:=false,
17
 org.eclipse.jface.examples.databinding.mask.internal;x-internal:=true,
18
 org.eclipse.jface.examples.databinding.mask.internal;x-internal:=true,
(-)src/org/eclipse/jface/examples/databinding/snippets/Snippet035Editing.java (+218 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006, 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.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.Editing;
20
import org.eclipse.core.databinding.observable.Realm;
21
import org.eclipse.core.databinding.observable.list.WritableList;
22
import org.eclipse.core.databinding.observable.value.IObservableValue;
23
import org.eclipse.core.databinding.observable.value.WritableValue;
24
import org.eclipse.core.runtime.IStatus;
25
import org.eclipse.jface.databinding.swt.ISWTObservableValue;
26
import org.eclipse.jface.databinding.swt.SWTObservables;
27
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
28
import org.eclipse.jface.examples.databinding.util.EditingFactory;
29
import org.eclipse.jface.internal.databinding.provisional.fieldassist.ControlDecorationSupport;
30
import org.eclipse.jface.layout.GridDataFactory;
31
import org.eclipse.jface.layout.GridLayoutFactory;
32
import org.eclipse.jface.viewers.LabelProvider;
33
import org.eclipse.jface.viewers.ListViewer;
34
import org.eclipse.swt.SWT;
35
import org.eclipse.swt.events.FocusAdapter;
36
import org.eclipse.swt.events.FocusEvent;
37
import org.eclipse.swt.events.SelectionAdapter;
38
import org.eclipse.swt.events.SelectionEvent;
39
import org.eclipse.swt.layout.GridLayout;
40
import org.eclipse.swt.widgets.Composite;
41
import org.eclipse.swt.widgets.Control;
42
import org.eclipse.swt.widgets.Display;
43
import org.eclipse.swt.widgets.Group;
44
import org.eclipse.swt.widgets.Label;
45
import org.eclipse.swt.widgets.Shell;
46
import org.eclipse.swt.widgets.Text;
47
48
public class Snippet035Editing {
49
50
	private static final String EMAIL_REGEX = "\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}\\b";
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.forString().required().matches(EMAIL_REGEX);
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
		Editing 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
		Editing 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
		Editing percentEditing = EditingFactory.forInteger().rangeMessage("Please specify a valid percentage value within [{0}, {1}].").range(0, 100);
111
		bindTextField(percentText, new WritableValue(new Integer(-1), null), percentEditing);
112
113
		// Edit a hex integer within the range [0x00, 0xff]. The range validation
114
		// message will display the range boundaries in hex format as well.
115
		Text hexText = createTextField(section, "Hex value in [0x00, 0xff]");
116
		Editing hexEditing = EditingFactory.forHexInteger(2).range(0x00, 0xff);
117
		bindTextField(hexText, new WritableValue(new Integer(0), null), hexEditing);
118
	}
119
120
	private void createListSection(Composite parent) {
121
		Group section = createSectionGroup(parent, "List bindings", true);
122
123
		// Our date should be >= 01.01.1990.
124
		Calendar year1990Calendar = Calendar.getInstance();
125
		year1990Calendar.clear();
126
		year1990Calendar.set(1990, 0, 1);
127
		Date year1990 = year1990Calendar.getTime();
128
129
		// Edit a date supporting the default input/display patterns.
130
		Text dateText = createTextField(section, "Date");
131
		Editing dateEditing = EditingFactory.forDate().afterEqual(year1990);
132
		final WritableValue dateObservable = new WritableValue();
133
		final Binding dateBinding = bindTextField(dateText, dateObservable, dateEditing);
134
135
		// Create a list to which the dates are added when the user hits ENTER.
136
		new Label(section, SWT.LEFT);
137
		ListViewer dateListViewer = new ListViewer(section);
138
		GridDataFactory.fillDefaults().grab(true, true).hint(150, 200).applyTo(dateListViewer.getList());
139
140
		dateListViewer.setContentProvider(new ObservableListContentProvider());
141
		dateListViewer.setLabelProvider(new LabelProvider());
142
143
		// We use the same DateEditing object as for the text field above to
144
		// create a list binding which maps the entered dates to their string
145
		// representation which is then set as input on the ListViewer.
146
		final WritableList targetDateList = new WritableList();
147
		final WritableList modelDateList = new WritableList();
148
		dbc.bindList(
149
				targetDateList,
150
				modelDateList,
151
				dateEditing.createTargetListStrategy(),
152
				dateEditing.createModelListStrategy());
153
154
		// Set the list containing the string representation of the dates as input.
155
		dateListViewer.setInput(targetDateList);
156
157
		// Add the current date in the text field when the user hits ENTER.
158
		dateText.addSelectionListener(new SelectionAdapter() {
159
			public void widgetDefaultSelected(SelectionEvent e) {
160
				IStatus dateValidationStatus = (IStatus) dateBinding.getValidationStatus().getValue();
161
				Date date = (Date) dateObservable.getValue();
162
				if (dateValidationStatus.isOK() && date != null) {
163
					modelDateList.add(date);
164
				}
165
			}
166
		});
167
	}
168
169
	private Binding bindTextField(Text text, IObservableValue modelValue, Editing editing) {
170
		// Create the binding using the editing object.
171
		ISWTObservableValue textObservable = SWTObservables.observeText(text, SWT.Modify);
172
		Binding binding = dbc.bindValue(
173
				textObservable,
174
				modelValue,
175
				editing.createTargetValueStrategy(),
176
				editing.createModelValueStrategy());
177
178
		// Decorate the control with the validation status.
179
		ControlDecorationSupport.create(binding, SWT.TOP);
180
181
		// Re-format when the text field looses the focus in order to always
182
		// display the model in the default format in case multiple input formats
183
		// are supported.
184
		formatOnFocusOut(text, binding);
185
186
		return binding;
187
	}
188
189
	private static void formatOnFocusOut(final Control control, final Binding binding) {
190
		control.addFocusListener(new FocusAdapter() {
191
			public void focusLost(FocusEvent e) {
192
				IStatus dateValidationStatus = (IStatus) binding.getValidationStatus().getValue();
193
				if (dateValidationStatus.isOK()) {
194
					binding.updateModelToTarget();
195
				}
196
			}
197
		});
198
	}
199
200
	private static Group createSectionGroup(Composite parent, String groupText, boolean grabVertical) {
201
		Group section = new Group(parent, SWT.SHADOW_ETCHED_IN);
202
		section.setText(groupText);
203
		GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(false).margins(5, 5).spacing(15, 5).applyTo(section);
204
		GridDataFactory.fillDefaults().grab(true, grabVertical).applyTo(section);
205
		return section;
206
	}
207
208
	private static Text createTextField(Composite parent, String labelText) {
209
		Label label = new Label(parent, SWT.LEFT);
210
		label.setText(labelText);
211
		GridDataFactory.fillDefaults().align(SWT.LEFT, SWT.CENTER).applyTo(label);
212
213
		Text text = new Text(parent, SWT.BORDER);
214
		GridDataFactory.fillDefaults().grab(true, false).hint(150, SWT.DEFAULT).applyTo(text);
215
216
		return text;
217
	}
218
}
(-)src/org/eclipse/jface/examples/databinding/util/EditingFactory.java (+95 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 EditingFactory() {
46
		// prevent instantiation
47
	}
48
49
	public static StringEditing forString() {
50
		return StringEditing.stripped(true);
51
	}
52
53
	public static IntegerEditing forInteger() {
54
		return IntegerEditing
55
				.withDefaults(INTEGER_PARSE_ERROR_MESSAGE, INTEGER_OUT_OF_RANGE_MESSAGE)
56
				.requiredMessage(REQUIRED_MESSAGE)
57
				.rangeMessage(INTEGER_RANGE_MESSAGE);
58
	}
59
60
	public static IntegerEditing forHexInteger(int digits) {
61
		return IntegerEditing
62
				.forFormat(RadixNumberFormat.getHexInstance("0x", digits), INTEGER_PARSE_ERROR_MESSAGE, INTEGER_OUT_OF_RANGE_MESSAGE)
63
				.requiredMessage(REQUIRED_MESSAGE)
64
				.rangeMessage(INTEGER_RANGE_MESSAGE);
65
	}
66
67
	public static DateEditing forDate() {
68
		return DateEditing
69
				.forFormats(
70
						createDateFormats(DATE_INPUT_PATTERNS),
71
						DATE_PARSE_ERROR_MESSAGE,
72
						new SimpleDateFormat(DATE_DISPLAY_PATTERN))
73
				.requiredMessage(REQUIRED_MESSAGE);
74
	}
75
76
	private static DateFormat[] createDateFormats(String[] datePatterns) {
77
		DateFormat[] dateFormats = new DateFormat[datePatterns.length];
78
		for (int i = 0; i < dateFormats.length; i++) {
79
			dateFormats[i] = new SimpleDateFormat(datePatterns[i]);
80
		}
81
		return dateFormats;
82
	}
83
84
	private static String createDateParseErrorMessage(String[] datePatterns) {
85
		StringBuffer messageSb = new StringBuffer();
86
		messageSb.append("Supported formats: ");
87
		for (int i = 0; i < datePatterns.length; i++) {
88
			if (i > 0) {
89
				messageSb.append(", ");
90
			}
91
			messageSb.append(datePatterns[i]);
92
		}
93
		return messageSb.toString();
94
	}
95
}
(-)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 (+246 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006, 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.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.Editing;
20
import org.eclipse.core.databinding.observable.Realm;
21
import org.eclipse.core.databinding.observable.list.WritableList;
22
import org.eclipse.core.databinding.observable.map.IObservableMap;
23
import org.eclipse.core.databinding.observable.set.IObservableSet;
24
import org.eclipse.core.databinding.observable.value.IObservableValue;
25
import org.eclipse.core.runtime.IStatus;
26
import org.eclipse.jface.databinding.swt.ISWTObservableValue;
27
import org.eclipse.jface.databinding.swt.SWTObservables;
28
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
29
import org.eclipse.jface.databinding.viewers.ViewersObservables;
30
import org.eclipse.jface.examples.databinding.ModelObject;
31
import org.eclipse.jface.examples.databinding.util.EditingFactory;
32
import org.eclipse.jface.examples.databinding.util.ObservableMapEditingCellLabelProvider;
33
import org.eclipse.jface.examples.databinding.util.ObservableMapEditingSupport;
34
import org.eclipse.jface.internal.databinding.provisional.fieldassist.ControlDecorationSupport;
35
import org.eclipse.jface.layout.GridDataFactory;
36
import org.eclipse.jface.layout.GridLayoutFactory;
37
import org.eclipse.jface.viewers.StructuredSelection;
38
import org.eclipse.jface.viewers.TableViewer;
39
import org.eclipse.jface.viewers.TableViewerColumn;
40
import org.eclipse.swt.SWT;
41
import org.eclipse.swt.events.FocusAdapter;
42
import org.eclipse.swt.events.FocusEvent;
43
import org.eclipse.swt.layout.GridLayout;
44
import org.eclipse.swt.widgets.Composite;
45
import org.eclipse.swt.widgets.Control;
46
import org.eclipse.swt.widgets.Display;
47
import org.eclipse.swt.widgets.Group;
48
import org.eclipse.swt.widgets.Label;
49
import org.eclipse.swt.widgets.Shell;
50
import org.eclipse.swt.widgets.Text;
51
52
public class Snippet036EditingTable {
53
54
	private final Editing nameEditing = EditingFactory.forString().required();
55
56
	private final Editing ageEditing = EditingFactory.forInteger().required().nonNegative();
57
58
	private final Editing bdayEditing = EditingFactory.forDate().before(new Date());
59
60
	private DataBindingContext dbc;
61
62
	private TableViewer tableViewer;
63
64
	public static void main(String[] args) {
65
		Display display = new Display();
66
67
		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
68
			public void run() {
69
				Shell shell = new Snippet036EditingTable().createShell();
70
				Display display = Display.getCurrent();
71
				while (!shell.isDisposed()) {
72
					if (!display.readAndDispatch()) {
73
						display.sleep();
74
					}
75
				}
76
			}
77
		});
78
	}
79
80
	private Shell createShell() {
81
		Display display = Display.getCurrent();
82
		Shell shell = new Shell(display);
83
		shell.setText("Editing");
84
		shell.setLayout(new GridLayout(2, false));
85
86
		dbc = new DataBindingContext();
87
88
		createTableSection(shell);
89
		createFieldSection(shell);
90
91
		shell.pack();
92
		shell.open();
93
94
		return shell;
95
	}
96
97
	private void createTableSection(Composite parent) {
98
		Group section = createSectionGroup(parent, 1);
99
100
		tableViewer = new TableViewer(section, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION);
101
		GridDataFactory.fillDefaults().grab(true, true).hint(350, 250).applyTo(tableViewer.getTable());
102
		tableViewer.getTable().setHeaderVisible(true);
103
		tableViewer.getTable().setLinesVisible(true);
104
105
		ObservableListContentProvider contentProvider = new ObservableListContentProvider();
106
		tableViewer.setContentProvider(contentProvider);
107
		IObservableSet contentElements = contentProvider.getKnownElements();
108
109
		IObservableMap nameMap = BeansObservables.observeMap(contentElements, "name");
110
		createColumn("Name*", 150, nameMap, nameEditing);
111
112
		IObservableMap ageMap = BeansObservables.observeMap(contentElements, "age");
113
		createColumn("Age*", 50, ageMap, ageEditing);
114
115
		IObservableMap bdayMap = BeansObservables.observeMap(contentElements, "birthday");
116
		createColumn("Birthday", 80, bdayMap, bdayEditing);
117
118
		WritableList people = new WritableList();
119
		people.add(new Person("John Doe", 27));
120
		people.add(new Person("Steve Northover", 33));
121
		people.add(new Person("Grant Gayed", 54));
122
		people.add(new Person("Veronika Irvine", 25));
123
		people.add(new Person("Mike Wilson", 44));
124
		people.add(new Person("Christophe Cornu", 37));
125
		people.add(new Person("Lynne Kues", 65));
126
		people.add(new Person("Silenio Quarti", 15));
127
128
		tableViewer.setInput(people);
129
130
		tableViewer.setSelection(new StructuredSelection(people.get(0)));
131
	}
132
133
	private TableViewerColumn createColumn(String text, int width, IObservableMap attributeMap, Editing modelEditing) {
134
		TableViewerColumn column = new TableViewerColumn(tableViewer, SWT.NONE);
135
		column.getColumn().setText(text);
136
		column.getColumn().setWidth(width);
137
		column.setLabelProvider(new ObservableMapEditingCellLabelProvider(attributeMap, modelEditing));
138
		column.setEditingSupport(new ObservableMapEditingSupport(tableViewer, attributeMap, modelEditing));
139
		return column;
140
	}
141
142
	private void createFieldSection(Composite parent) {
143
		final Group section = createSectionGroup(parent, 2);
144
145
		final IObservableValue personObservable = ViewersObservables.observeSingleSelection(tableViewer);
146
147
		Text nameText = createTextField(section, "Name*");
148
		IObservableValue nameObservable = BeansObservables.observeDetailValue(personObservable, "name", null);
149
		bindTextField(nameText, nameObservable, nameEditing);
150
151
		Text ageText = createTextField(section, "Age*");
152
		IObservableValue ageObservable = BeansObservables.observeDetailValue(personObservable, "age", null);
153
		bindTextField(ageText, ageObservable, ageEditing);
154
155
		Text bdayText = createTextField(section, "Birthday");
156
		IObservableValue bdayObservable = BeansObservables.observeDetailValue(personObservable, "birthday", null);
157
		bindTextField(bdayText, bdayObservable, bdayEditing);
158
	}
159
160
	private Binding bindTextField(
161
			Text text,
162
			IObservableValue modelValue,
163
			Editing editing) {
164
		// Create the binding using the editing object.
165
		ISWTObservableValue textObservable = SWTObservables.observeText(text, SWT.Modify);
166
		Binding binding = dbc.bindValue(
167
				textObservable,
168
				modelValue,
169
				editing.createTargetValueStrategy(),
170
				editing.createModelValueStrategy());
171
172
		// Decorate the control with the validation status.
173
		ControlDecorationSupport.create(binding, SWT.TOP);
174
175
		formatOnFocusOut(text, binding);
176
177
		return binding;
178
	}
179
180
	private static void formatOnFocusOut(final Control control, final Binding binding) {
181
		control.addFocusListener(new FocusAdapter() {
182
			public void focusLost(FocusEvent e) {
183
				IStatus dateValidationStatus = (IStatus) binding.getValidationStatus().getValue();
184
				if (dateValidationStatus.isOK()) {
185
					binding.updateModelToTarget();
186
				}
187
			}
188
		});
189
	}
190
191
	private Group createSectionGroup(Composite parent, int numColumns) {
192
		Group section = new Group(parent, SWT.SHADOW_ETCHED_IN);
193
		GridLayoutFactory.fillDefaults().numColumns(numColumns).equalWidth(false).margins(5, 5).spacing(15, 5).applyTo(section);
194
		GridDataFactory.fillDefaults().grab(true, true).applyTo(section);
195
		return section;
196
	}
197
198
	private static Text createTextField(Composite parent, String labelText) {
199
		Label label = new Label(parent, SWT.LEFT);
200
		label.setText(labelText);
201
		GridDataFactory.fillDefaults().align(SWT.LEFT, SWT.CENTER).applyTo(label);
202
203
		Text text = new Text(parent, SWT.BORDER);
204
		GridDataFactory.fillDefaults().grab(true, false).hint(200, SWT.DEFAULT).applyTo(text);
205
206
		return text;
207
	}
208
209
	private static final class Person extends ModelObject {
210
211
		private String name;
212
213
		private int age;
214
215
		private Date birthday;
216
217
		public Person(String name, int age) {
218
			this.name = name;
219
			this.age = age;
220
		}
221
222
		public String getName() {
223
			return name;
224
		}
225
226
		public void setName(String name) {
227
			firePropertyChange("name", this.name, this.name = name);
228
		}
229
230
		public int getAge() {
231
			return age;
232
		}
233
234
		public void setAge(int age) {
235
			firePropertyChange("age", this.age, this.age = age);
236
		}
237
238
		public Date getBirthday() {
239
			return birthday;
240
		}
241
242
		public void setBirthday(Date birthday) {
243
			firePropertyChange("birthday", this.birthday, this.birthday = birthday);
244
		}
245
	}
246
}
(-)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
}

Return to bug 183055