Skip to content

Package: NumberControlSWTRenderer$NumericalTargetToModelUpdateStrategy

NumberControlSWTRenderer$NumericalTargetToModelUpdateStrategy

nameinstructionbranchcomplexitylinemethod
NumberControlSWTRenderer.NumericalTargetToModelUpdateStrategy(NumberControlSWTRenderer, EStructuralFeature, IObservableValue, DataBindingContext, Text)
M: 0 C: 21
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 7
100%
M: 0 C: 1
100%
convertValue(Object)
M: 24 C: 108
82%
M: 2 C: 18
90%
M: 2 C: 9
82%
M: 10 C: 26
72%
M: 0 C: 1
100%
doSet(IObservableValue, Object)
M: 0 C: 10
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getFormat()
M: 0 C: 11
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getInstanceMaxValue(Class)
M: 30 C: 14
32%
M: 10 C: 2
17%
M: 6 C: 1
14%
M: 7 C: 3
30%
M: 0 C: 1
100%
getInstanceMinValue(Class)
M: 30 C: 14
32%
M: 10 C: 2
17%
M: 6 C: 1
14%
M: 7 C: 3
30%
M: 0 C: 1
100%
getOldValue(Object)
M: 66 C: 0
0%
M: 10 C: 0
0%
M: 6 C: 0
0%
M: 14 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2011-2016 EclipseSource Muenchen GmbH and others.
3: *
4: * All rights reserved. This program and the accompanying materials
5: * are made available under the terms of the Eclipse Public License 2.0
6: * which accompanies this distribution, and is available at
7: * https://www.eclipse.org/legal/epl-2.0/
8: *
9: * SPDX-License-Identifier: EPL-2.0
10: *
11: * Contributors:
12: * Eugen - initial API and implementation
13: ******************************************************************************/
14: package org.eclipse.emf.ecp.view.internal.core.swt.renderer;
15:
16: import java.text.DecimalFormat;
17: import java.text.ParseException;
18: import java.text.ParsePosition;
19:
20: import javax.inject.Inject;
21:
22: import org.eclipse.core.databinding.Binding;
23: import org.eclipse.core.databinding.DataBindingContext;
24: import org.eclipse.core.databinding.UpdateValueStrategy;
25: import org.eclipse.core.databinding.observable.value.IObservableValue;
26: import org.eclipse.core.databinding.property.value.IValueProperty;
27: import org.eclipse.core.runtime.IStatus;
28: import org.eclipse.emf.ecore.EDataType;
29: import org.eclipse.emf.ecore.EStructuralFeature;
30: import org.eclipse.emf.ecp.edit.internal.swt.controls.NumericalHelper;
31: import org.eclipse.emf.ecp.edit.spi.swt.util.ECPDialogExecutor;
32: import org.eclipse.emf.ecp.view.internal.core.swt.Activator;
33: import org.eclipse.emf.ecp.view.internal.core.swt.MessageKeys;
34: import org.eclipse.emf.ecp.view.spi.context.ViewModelContext;
35: import org.eclipse.emf.ecp.view.spi.core.swt.renderer.TextControlSWTRenderer;
36: import org.eclipse.emf.ecp.view.spi.model.VControl;
37: import org.eclipse.emf.ecp.view.template.model.VTViewTemplateProvider;
38: import org.eclipse.emf.edit.command.SetCommand;
39: import org.eclipse.emfforms.spi.common.locale.EMFFormsLocaleChangeListener;
40: import org.eclipse.emfforms.spi.common.locale.EMFFormsLocaleProvider;
41: import org.eclipse.emfforms.spi.common.report.ReportService;
42: import org.eclipse.emfforms.spi.core.services.databinding.DatabindingFailedException;
43: import org.eclipse.emfforms.spi.core.services.databinding.DatabindingFailedReport;
44: import org.eclipse.emfforms.spi.core.services.databinding.EMFFormsDatabinding;
45: import org.eclipse.emfforms.spi.core.services.editsupport.EMFFormsEditSupport;
46: import org.eclipse.emfforms.spi.core.services.label.EMFFormsLabelProvider;
47: import org.eclipse.emfforms.spi.localization.EMFFormsLocalizationService;
48: import org.eclipse.jface.dialogs.IDialogLabelKeys;
49: import org.eclipse.jface.dialogs.MessageDialog;
50: import org.eclipse.jface.resource.JFaceResources;
51: import org.eclipse.swt.SWT;
52: import org.eclipse.swt.widgets.Composite;
53: import org.eclipse.swt.widgets.Control;
54: import org.eclipse.swt.widgets.Text;
55:
56: /**
57: * Renders numbers.
58: *
59: * @author Eugen Neufeld
60: *
61: */
62: public class NumberControlSWTRenderer extends TextControlSWTRenderer {
63:
64:         private final EMFFormsLocalizationService localizationService;
65:         private final EMFFormsLocaleProvider localeProvider;
66:         private EMFFormsLocaleChangeListener emfFormsLocaleChangeListener;
67:
68:         /**
69:          * Default constructor.
70:          *
71:          * @param vElement the view model element to be rendered
72:          * @param viewContext the view context
73:          * @param reportService The {@link ReportService}
74:          * @param emfFormsDatabinding The {@link EMFFormsDatabinding}
75:          * @param emfFormsLabelProvider The {@link EMFFormsLabelProvider}
76:          * @param vtViewTemplateProvider The {@link VTViewTemplateProvider}
77:          * @param emfFormsEditSupport The {@link EMFFormsEditSupport}
78:          * @param localizationService The {@link EMFFormsLocalizationService}
79:          * @param localeProvider The {@link EMFFormsLocaleProvider}
80:          */
81:         @Inject
82:         // CHECKSTYLE.OFF: ParameterNumber
83:         public NumberControlSWTRenderer(VControl vElement, ViewModelContext viewContext,
84:                 ReportService reportService,
85:                 EMFFormsDatabinding emfFormsDatabinding, EMFFormsLabelProvider emfFormsLabelProvider,
86:                 VTViewTemplateProvider vtViewTemplateProvider, EMFFormsEditSupport emfFormsEditSupport,
87:                 EMFFormsLocalizationService localizationService, EMFFormsLocaleProvider localeProvider) {
88:                 // CHECKSTYLE.ON: ParameterNumber
89:                 super(vElement, viewContext, reportService, emfFormsDatabinding, emfFormsLabelProvider, vtViewTemplateProvider,
90:                         emfFormsEditSupport);
91:                 this.localizationService = localizationService;
92:                 this.localeProvider = localeProvider;
93:         }
94:
95:         @Override
96:         protected int getDefaultAlignment() {
97:                 return SWT.RIGHT;
98:         }
99:
100:         /*
101:          * (non-Javadoc)
102:          * @see org.eclipse.emf.ecp.edit.internal.swt.controls.AbstractTextControl#getTextVariantID()
103:          */
104:         @Override
105:         protected String getTextVariantID() {
106:                 return "org_eclipse_emf_ecp_control_numerical"; //$NON-NLS-1$
107:         }
108:
109:         @Override
110:         protected String getTextMessage() {
111:                 try {
112:                         final IValueProperty valueProperty = getEMFFormsDatabinding()
113:                                 .getValueProperty(getVElement().getDomainModelReference(), getViewModelContext().getDomainModel());
114:                         final EStructuralFeature structuralFeature = (EStructuralFeature) valueProperty.getValueType();
115:                         // if (NumericalHelper.isInteger(getInstanceClass(structuralFeature))) {
116:                         // return localizationService.getString(getClass(), MessageKeys.NumericalControl_FormatNumerical);
117:                         // } else if (NumericalHelper.isDouble(getInstanceClass(structuralFeature))) {
118:                         // return localizationService.getString(getClass(),
119:                         // MessageKeys.NumericalControl_FormatNumericalDecimal);
120:                         // }
121:
122:                         final DecimalFormat format = NumericalHelper.setupFormat(localeProvider.getLocale(),
123:                                 getInstanceClass(structuralFeature));
124:                         if (format.getMaximumFractionDigits() > 1) {
125:                                 format.setMaximumFractionDigits(1);
126:                         }
127:                         return format.toLocalizedPattern();
128:                 } catch (final DatabindingFailedException ex) {
129:                         getReportService().report(new DatabindingFailedReport(ex));
130:                 }
131:                 return ""; //$NON-NLS-1$
132:         }
133:
134:         @Override
135:         protected Object convert(Text text, EDataType attributeType, String value) throws DatabindingFailedException {
136:                 final EStructuralFeature eStructuralFeature = (EStructuralFeature) getModelValue().getValueType();
137:                 final NumericalTargetToModelUpdateStrategy converter = new NumericalTargetToModelUpdateStrategy(
138:                         eStructuralFeature, getModelValue(), getDataBindingContext(), text);
139:                 return converter.convert(value);
140:         }
141:
142:         @Override
143:         protected Binding[] createBindings(final Control control) throws DatabindingFailedException {
144:                 final EStructuralFeature structuralFeature = (EStructuralFeature) getModelValue().getValueType();
145:
146:                 final UpdateValueStrategy targetToModelStrategy = withPreSetValidation(new NumericalTargetToModelUpdateStrategy(
147:                         structuralFeature, getModelValue(), getDataBindingContext(),
148:                         (Text) Composite.class.cast(control).getChildren()[0]));
149:                 final NumericalModelToTargetUpdateStrategy modelToTargetStrategy = new NumericalModelToTargetUpdateStrategy(
150:                         getInstanceClass(structuralFeature), false);
151:                 final Binding binding = bindValue(control, getModelValue(), getDataBindingContext(),
152:                         targetToModelStrategy, modelToTargetStrategy);
153:                 final Binding tooltipBinding = createTooltipBinding(control, getModelValue(), getDataBindingContext(),
154:                         targetToModelStrategy,
155:                         new NumericalModelToTargetUpdateStrategy(getInstanceClass(structuralFeature), true));
156:
157:                 emfFormsLocaleChangeListener = new EMFFormsLocaleChangeListener() {
158:
159:                         /**
160:                          * {@inheritDoc}
161:                          *
162:                          * @see org.eclipse.emfforms.spi.common.locale.EMFFormsLocaleChangeListener#notifyLocaleChange()
163:                          */
164:                         @Override
165:                         public void notifyLocaleChange() {
166:                                 ((Text) control).setMessage(getTextMessage());
167:                                 binding.updateModelToTarget();
168:                         }
169:                 };
170:                 localeProvider.addEMFFormsLocaleChangeListener(emfFormsLocaleChangeListener);
171:
172:                 return new Binding[] { binding, tooltipBinding };
173:         }
174:
175:         private Class<?> getInstanceClass(EStructuralFeature feature) {
176:                 return feature.getEType().getInstanceClass();
177:         }
178:
179:         @Override
180:         protected String getTextFromTextField(Text text, EDataType attributeType) {
181:                 if (!Object.class.isAssignableFrom(attributeType.getInstanceClass())) {
182:                         /* primitive types */
183:                         return super.getTextFromTextField(text, attributeType);
184:                 }
185:                 if (text.getText() != null && text.getText().isEmpty()) {
186:                         /* string is empty, but since we are a non primitive type, return null instead */
187:                         return null;
188:                 }
189:                 return super.getTextFromTextField(text, attributeType);
190:         }
191:
192:         /**
193:          * Converts the numerical value from the model to the target. Locale settings are respected,
194:          * i.e. formatting is performed according to the current locale.
195:          */
196:         private class NumericalModelToTargetUpdateStrategy extends ModelToTargetUpdateStrategy {
197:
198:                 private final Class<?> instanceClass;
199:
200:                 NumericalModelToTargetUpdateStrategy(Class<?> instanceClass, boolean tooltip) {
201:                         super(tooltip);
202:                         this.instanceClass = instanceClass;
203:                 }
204:
205:                 @Override
206:                 public Object convertValue(Object value) {
207:                         if (value == null) {
208:                                 return ""; //$NON-NLS-1$
209:                         }
210:                         final DecimalFormat format = NumericalHelper.setupFormat(localeProvider.getLocale(),
211:                                 instanceClass);
212:                         return format.format(value);
213:                 }
214:         }
215:
216:         /**
217:          * More specific target to model update strategy that convert the string
218:          * in the text field to a number. If the string is a invalid number,
219:          * for instance because of the current locale, the value is reset to
220:          * the last valid value found in the mode.
221:          */
222:         private class NumericalTargetToModelUpdateStrategy extends TargetToModelUpdateStrategy {
223:
224:                 private final Text text;
225:                 private final IObservableValue modelValue;
226:                 private final EStructuralFeature eStructuralFeature;
227:                 private final DataBindingContext dataBindingContext;
228:
229:                 NumericalTargetToModelUpdateStrategy(EStructuralFeature eStructuralFeature,
230:                         IObservableValue modelValue, DataBindingContext dataBindingContext, Text text) {
231:                         super(eStructuralFeature.isUnsettable());
232:                         this.eStructuralFeature = eStructuralFeature;
233:                         this.modelValue = modelValue;
234:                         this.dataBindingContext = dataBindingContext;
235:                         this.text = text;
236:                 }
237:
238:                 private DecimalFormat getFormat() {
239:                         return NumericalHelper.setupFormat(localeProvider.getLocale(), getInstanceClass(eStructuralFeature));
240:                 }
241:
242:                 @Override
243:                 protected Object convertValue(final Object value) {
244:                         final DecimalFormat format = getFormat();
245:                         try {
246:                                 Number number = null;
247:•                                if (value == null) {
248:                                         number = NumericalHelper.getDefaultValue(getInstanceClass(eStructuralFeature));
249:                                 } else {
250:                                         final ParsePosition pp = new ParsePosition(0);
251:                                         number = format.parse((String) value, pp);
252:•                                        if (pp.getErrorIndex() != -1 || pp.getIndex() != ((String) value).length()) {
253:                                                 return getOldValue(value);
254:                                         }
255:•                                        if (NumericalHelper.isInteger(getInstanceClass(eStructuralFeature))) {
256:                                                 boolean maxValue = false;
257:                                                 boolean minValue = false;
258:                                                 final Class<?> instanceClass = getInstanceClass(eStructuralFeature);
259:                                                 try {
260:•                                                        if (number.doubleValue() >= getInstanceMaxValue(instanceClass)) {
261:                                                                 maxValue = true;
262:•                                                        } else if (number.doubleValue() <= getInstanceMinValue(instanceClass)) {
263:                                                                 minValue = true;
264:                                                         }
265:                                                 } catch (final IllegalArgumentException ex) {
266:                                                         Activator.logException(ex);
267:                                                 } catch (final SecurityException ex) {
268:                                                         Activator.logException(ex);
269:                                                 } catch (final IllegalAccessException ex) {
270:                                                         Activator.logException(ex);
271:                                                 } catch (final NoSuchFieldException ex) {
272:                                                         Activator.logException(ex);
273:                                                 }
274:
275:•                                                if (maxValue || minValue) {
276:                                                         return NumericalHelper.numberToInstanceClass(number, getInstanceClass(eStructuralFeature));
277:                                                 }
278:                                         }
279:                                 }
280:                                 String formatedNumber = ""; //$NON-NLS-1$
281:•                                if (number != null) {
282:                                         formatedNumber = format.format(number);
283:                                 }
284:•                                if (formatedNumber.length() == 0) {
285:                                         return null;
286:                                 }
287:                                 return NumericalHelper.numberToInstanceClass(format.parse(formatedNumber),
288:                                         getInstanceClass(eStructuralFeature));
289:                         } catch (final ParseException ex) {
290:                                 return getOldValue(value);
291:                         }
292:                 }
293:
294:                 private double getInstanceMinValue(Class<?> instanceClass)
295:                         throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
296:•                        if (Integer.class.isAssignableFrom(instanceClass)
297:•                                || Integer.class.getField("TYPE").get(null).equals(instanceClass)) { //$NON-NLS-1$
298:                                 return Integer.MIN_VALUE;
299:                         }
300:•                        if (Long.class.isAssignableFrom(instanceClass)
301:•                                || Long.class.getField("TYPE").get(null).equals(instanceClass)) { //$NON-NLS-1$
302:                                 return Long.MIN_VALUE;
303:                         }
304:•                        if (Short.class.isAssignableFrom(instanceClass)
305:•                                || Short.class.getField("TYPE").get(null).equals(instanceClass)) { //$NON-NLS-1$
306:                                 return Short.MIN_VALUE;
307:                         }
308:
309:                         return Double.NaN;
310:                 }
311:
312:                 private double getInstanceMaxValue(Class<?> instanceClass)
313:                         throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
314:•                        if (Integer.class.isAssignableFrom(instanceClass)
315:•                                || Integer.class.getField("TYPE").get(null).equals(instanceClass)) { //$NON-NLS-1$
316:                                 return Integer.MAX_VALUE;
317:                         }
318:•                        if (Long.class.isAssignableFrom(instanceClass)
319:•                                || Long.class.getField("TYPE").get(null).equals(instanceClass)) { //$NON-NLS-1$
320:                                 return Long.MAX_VALUE;
321:                         }
322:•                        if (Short.class.isAssignableFrom(instanceClass)
323:•                                || Short.class.getField("TYPE").get(null).equals(instanceClass)) { //$NON-NLS-1$
324:                                 return Short.MAX_VALUE;
325:                         }
326:
327:                         return Double.NaN;
328:                 }
329:
330:                 @Override
331:                 protected IStatus doSet(IObservableValue observableValue, Object value) {
332:                         final IStatus status = super.doSet(observableValue, value);
333:                         // update targets after a model change triggered by the target to model databinding
334:                         dataBindingContext.updateTargets();
335:                         return status;
336:                 }
337:
338:                 private Object getOldValue(final Object value) {
339:•                        if (eStructuralFeature.getDefaultValue() == null && (value == null || value.equals(""))) { //$NON-NLS-1$
340:                                 return null;
341:                         }
342:                         final Object result = modelValue.getValue();
343:
344:                         final MessageDialog messageDialog = new MessageDialog(text.getShell(),
345:                                 localizationService.getString(getClass(), MessageKeys.NumericalControl_InvalidNumber), null,
346:                                 localizationService.getString(getClass(), MessageKeys.NumericalControl_InvalidNumberWillBeUnset),
347:                                 MessageDialog.ERROR,
348:                                 new String[] { JFaceResources.getString(IDialogLabelKeys.OK_LABEL_KEY) }, 0);
349:
350:                         new ECPDialogExecutor(messageDialog) {
351:                                 @Override
352:                                 public void handleResult(int codeResult) {
353:
354:                                 }
355:                         }.execute();
356:
357:                         dataBindingContext.updateTargets();
358:•                        if (eStructuralFeature.isUnsettable() && result == null) {
359:                                 // showUnsetLabel();
360:                                 return SetCommand.UNSET_VALUE;
361:                         }
362:                         return result;
363:                 }
364:         }
365:
366:         /**
367:          * {@inheritDoc}
368:          *
369:          * @see org.eclipse.emf.ecp.view.spi.core.swt.renderer.TextControlSWTRenderer#getUnsetText()
370:          */
371:         @Override
372:         protected String getUnsetText() {
373:                 return localizationService.getString(getClass(), MessageKeys.NumericalControl_NoNumberClickToSetNumber);
374:         }
375:
376:         /**
377:          * {@inheritDoc}
378:          *
379:          * @see org.eclipse.emf.ecp.view.spi.core.swt.SimpleControlSWTRenderer#dispose()
380:          */
381:         @Override
382:         protected void dispose() {
383:                 super.dispose();
384:                 localeProvider.removeEMFFormsLocaleChangeListener(emfFormsLocaleChangeListener);
385:         }
386:
387: }