Skip to content

Package: XMLDateControlSWTRenderer$DateTargetToModelUpdateStrategy

XMLDateControlSWTRenderer$DateTargetToModelUpdateStrategy

nameinstructionbranchcomplexitylinemethod
XMLDateControlSWTRenderer.DateTargetToModelUpdateStrategy(XMLDateControlSWTRenderer, EStructuralFeature, Text)
M: 32 C: 33
51%
M: 5 C: 3
38%
M: 3 C: 2
40%
M: 8 C: 12
60%
M: 0 C: 1
100%
convertValue(Object)
M: 16 C: 52
76%
M: 4 C: 6
60%
M: 4 C: 2
33%
M: 5 C: 14
74%
M: 0 C: 1
100%
revertToOldValue(Object)
M: 72 C: 0
0%
M: 10 C: 0
0%
M: 6 C: 0
0%
M: 20 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2011-2014 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.DateFormat;
17: import java.text.ParseException;
18: import java.text.SimpleDateFormat;
19: import java.util.Calendar;
20: import java.util.Date;
21: import java.util.Locale;
22: import java.util.regex.Pattern;
23:
24: import javax.inject.Inject;
25: import javax.xml.datatype.XMLGregorianCalendar;
26:
27: import org.eclipse.core.databinding.Binding;
28: import org.eclipse.core.databinding.UpdateValueStrategy;
29: import org.eclipse.core.databinding.observable.value.IObservableValue;
30: import org.eclipse.core.runtime.IStatus;
31: import org.eclipse.core.runtime.Status;
32: import org.eclipse.emf.common.util.EMap;
33: import org.eclipse.emf.ecore.EAnnotation;
34: import org.eclipse.emf.ecore.EClassifier;
35: import org.eclipse.emf.ecore.EDataType;
36: import org.eclipse.emf.ecore.EStructuralFeature;
37: import org.eclipse.emf.ecp.edit.internal.swt.util.DateUtil;
38: import org.eclipse.emf.ecp.edit.spi.swt.util.ECPDialogExecutor;
39: import org.eclipse.emf.ecp.view.internal.core.swt.MessageKeys;
40: import org.eclipse.emf.ecp.view.spi.context.ViewModelContext;
41: import org.eclipse.emf.ecp.view.spi.core.swt.renderer.TextControlSWTRenderer;
42: import org.eclipse.emf.ecp.view.spi.model.LabelAlignment;
43: import org.eclipse.emf.ecp.view.spi.model.VControl;
44: import org.eclipse.emf.ecp.view.spi.util.swt.ImageRegistryService;
45: import org.eclipse.emf.ecp.view.template.model.VTViewTemplateProvider;
46: import org.eclipse.emf.edit.command.SetCommand;
47: import org.eclipse.emfforms.spi.common.locale.EMFFormsLocaleChangeListener;
48: import org.eclipse.emfforms.spi.common.locale.EMFFormsLocaleProvider;
49: import org.eclipse.emfforms.spi.common.report.AbstractReport;
50: import org.eclipse.emfforms.spi.common.report.ReportService;
51: import org.eclipse.emfforms.spi.core.services.databinding.DatabindingFailedException;
52: import org.eclipse.emfforms.spi.core.services.databinding.EMFFormsDatabinding;
53: import org.eclipse.emfforms.spi.core.services.editsupport.EMFFormsEditSupport;
54: import org.eclipse.emfforms.spi.core.services.label.EMFFormsLabelProvider;
55: import org.eclipse.emfforms.spi.localization.EMFFormsLocalizationService;
56: import org.eclipse.emfforms.spi.localization.LocalizationServiceHelper;
57: import org.eclipse.emfforms.spi.swt.core.layout.SWTGridCell;
58: import org.eclipse.jface.databinding.swt.typed.WidgetProperties;
59: import org.eclipse.jface.dialogs.IDialogLabelKeys;
60: import org.eclipse.jface.dialogs.MessageDialog;
61: import org.eclipse.jface.layout.GridDataFactory;
62: import org.eclipse.jface.layout.GridLayoutFactory;
63: import org.eclipse.jface.resource.JFaceResources;
64: import org.eclipse.swt.SWT;
65: import org.eclipse.swt.events.SelectionAdapter;
66: import org.eclipse.swt.events.SelectionEvent;
67: import org.eclipse.swt.graphics.Color;
68: import org.eclipse.swt.graphics.Point;
69: import org.eclipse.swt.graphics.Rectangle;
70: import org.eclipse.swt.layout.GridLayout;
71: import org.eclipse.swt.widgets.Button;
72: import org.eclipse.swt.widgets.Composite;
73: import org.eclipse.swt.widgets.Control;
74: import org.eclipse.swt.widgets.DateTime;
75: import org.eclipse.swt.widgets.Shell;
76: import org.eclipse.swt.widgets.Text;
77: import org.osgi.framework.FrameworkUtil;
78:
79: /**
80: * @author Eugen
81: *
82: */
83: public class XMLDateControlSWTRenderer extends TextControlSWTRenderer {
84:
85:         private final EMFFormsLocaleProvider localeProvider;
86:         private final EMFFormsLocalizationService localizationService;
87:         private final ImageRegistryService imageRegistryService;
88:
89:         /**
90:          * Default constructor.
91:          *
92:          * @param vElement the view model element to be rendered
93:          * @param viewContext the view context
94:          * @param reportService The {@link ReportService}
95:          * @param emfFormsDatabinding The {@link EMFFormsDatabinding}
96:          * @param emfFormsLabelProvider The {@link EMFFormsLabelProvider}
97:          * @param vtViewTemplateProvider The {@link VTViewTemplateProvider}
98:          * @param emfFormsEditSupport The {@link EMFFormsEditSupport}
99:          * @param localizationService The {@link EMFFormsLocalizationService}
100:          * @param localeProvider The {@link EMFFormsLocaleProvider}
101:          * @param imageRegistryService The {@link ImageRegistryService}
102:          */
103:         @Inject
104:         public XMLDateControlSWTRenderer(VControl vElement, ViewModelContext viewContext,
105:                 ReportService reportService,
106:                 EMFFormsDatabinding emfFormsDatabinding, EMFFormsLabelProvider emfFormsLabelProvider,
107:                 VTViewTemplateProvider vtViewTemplateProvider, EMFFormsEditSupport emfFormsEditSupport,
108:                 EMFFormsLocalizationService localizationService, EMFFormsLocaleProvider localeProvider,
109:                 ImageRegistryService imageRegistryService) {
110:                 super(vElement, viewContext, reportService, emfFormsDatabinding, emfFormsLabelProvider, vtViewTemplateProvider,
111:                         emfFormsEditSupport);
112:                 this.localizationService = localizationService;
113:                 this.localeProvider = localeProvider;
114:                 this.imageRegistryService = imageRegistryService;
115:         }
116:
117:         private static final DateFormat CHECK_FORMAT = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH); //$NON-NLS-1$
118:         private static final Pattern CHECK_PATTERN = Pattern.compile("^\\d{4}-\\d{2}-\\d{2}$"); //$NON-NLS-1$
119:
120:         /**
121:          * Selection adapter for the set date button.
122:          */
123:         private final class SelectionAdapterExtension extends SelectionAdapter {
124:                 private final Control button;
125:                 private final Text text;
126:
127:                 private SelectionAdapterExtension(Text text, Button button) {
128:                         this.text = text;
129:                         this.button = button;
130:                 }
131:
132:                 @Override
133:                 public void widgetSelected(SelectionEvent e) {
134:                         if (dialog != null && !dialog.isDisposed()) {
135:                                 dialog.dispose();
136:                                 return;
137:                         }
138:                         IObservableValue modelValue;
139:                         EStructuralFeature eStructuralFeature;
140:                         try {
141:                                 modelValue = getModelValue();
142:                                 eStructuralFeature = (EStructuralFeature) modelValue.getValueType();
143:                         } catch (final DatabindingFailedException ex) {
144:                                 getReportService().report(new AbstractReport(ex));
145:                                 return;
146:                         }
147:                         dialog = new Shell(button.getShell(), SWT.NONE);
148:                         dialog.setLayout(new GridLayout(1, false));
149:
150:                         final DateTime calendar = new DateTime(dialog, SWT.CALENDAR | SWT.BORDER);
151:                         final XMLGregorianCalendar gregorianCalendar = (XMLGregorianCalendar) modelValue.getValue();
152:                         final Calendar cal = Calendar.getInstance(localeProvider.getLocale());
153:                         if (gregorianCalendar != null) {
154:                                 cal.setTime(gregorianCalendar.toGregorianCalendar().getTime());
155:                         }
156:                         calendar.setDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));
157:
158:                         final IObservableValue dateObserver = WidgetProperties.dateTimeSelection().observe(calendar);
159:                         final Binding binding = getDataBindingContext().bindValue(dateObserver, modelValue,
160:                                 new DateTargetToModelUpdateStrategy(eStructuralFeature, text),
161:                                 new DateModelToTargetUpdateStrategy(false, true));
162:                         binding.updateModelToTarget();
163:
164:                         final Button okButton = new Button(dialog, SWT.PUSH);
165:                         okButton.setText(JFaceResources.getString(IDialogLabelKeys.OK_LABEL_KEY));
166:                         GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).grab(false, false).applyTo(okButton);
167:                         okButton.addSelectionListener(new SelectionAdapter() {
168:                                 /**
169:                                  * {@inheritDoc}
170:                                  *
171:                                  * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
172:                                  */
173:                                 @Override
174:                                 public void widgetSelected(SelectionEvent e) {
175:                                         binding.updateTargetToModel();
176:                                         binding.dispose();
177:                                         dialog.close();
178:                                 }
179:                         });
180:
181:                         dialog.pack();
182:                         dialog.layout();
183:                         final Point dialogSize = dialog.getSize();
184:                         final Rectangle displayBounds = dialog.getDisplay().getBounds();
185:                         final Point buttonLocation = button.toDisplay(button.getSize().x, button.getSize().y);
186:
187:                         // TODO what if dialogsize > displaybounds? + some other cases
188:
189:                         int dialogX = buttonLocation.x - dialogSize.x;
190:                         int dialogY = buttonLocation.y;
191:                         if (dialogY + dialogSize.y > displayBounds.height) {
192:                                 dialogY = dialogY - button.getSize().y - dialogSize.y;
193:                         }
194:                         if (dialogX + dialogSize.x > displayBounds.width) {
195:                                 dialogX = dialogX - dialogSize.x;
196:                         } else if (dialogX - dialogSize.x < displayBounds.x) {
197:                                 dialogX = buttonLocation.x - button.getSize().x;
198:                         }
199:                         dialog.setLocation(dialogX, dialogY);
200:
201:                         dialog.open();
202:                 }
203:         }
204:
205:         @Override
206:         protected Object convert(Text text, EDataType attributeType, String value) throws DatabindingFailedException {
207:                 final EStructuralFeature eStructuralFeature = (EStructuralFeature) getModelValue().getValueType();
208:                 final DateTargetToModelUpdateStrategy converter = new DateTargetToModelUpdateStrategy(eStructuralFeature, text);
209:                 return converter.convert(value);
210:         }
211:
212:         /**
213:          * Model to target strategy.
214:          */
215:         private class DateModelToTargetUpdateStrategy extends ModelToTargetUpdateStrategy {
216:
217:                 private final boolean toDate;
218:
219:                 DateModelToTargetUpdateStrategy(boolean tooltip, boolean toDate) {
220:                         super(tooltip);
221:                         this.toDate = toDate;
222:                 }
223:
224:                 DateModelToTargetUpdateStrategy(boolean tooltip) {
225:                         this(tooltip, false);
226:                 }
227:
228:                 @Override
229:                 public Object convertValue(Object value) {
230:                         final DateFormat format = setupFormat();
231:                         final XMLGregorianCalendar gregorianCalendar = (XMLGregorianCalendar) value;
232:                         if (gregorianCalendar == null) {
233:                                 return null;
234:                         }
235:                         final Date date = gregorianCalendar.toGregorianCalendar().getTime();
236:                         if (toDate) {
237:                                 return date;
238:                         }
239:                         return format.format(date);
240:                 }
241:
242:                 @Override
243:                 protected IStatus doSet(IObservableValue observableValue, Object value) {
244:                         if (value == null && toDate) {
245:                                 return Status.OK_STATUS;
246:                         }
247:                         if (value == null && !toDate) {
248:                                 value = ""; //$NON-NLS-1$
249:                         }
250:                         return super.doSet(observableValue, value);
251:                 }
252:
253:         }
254:
255:         /**
256:          * Target to model strategy.
257:          */
258:         private class DateTargetToModelUpdateStrategy extends TargetToModelUpdateStrategy {
259:
260:                 private final EStructuralFeature eStructuralFeature;
261:                 private final Text text;
262:                 private final boolean isDate;
263:
264:                 DateTargetToModelUpdateStrategy(EStructuralFeature eStructuralFeature, Text text) {
265:                         super(eStructuralFeature.isUnsettable());
266:                         this.eStructuralFeature = eStructuralFeature;
267:                         this.text = text;
268:                         final EClassifier eType = eStructuralFeature.getEType();
269:•                        if (eType == null) {
270:                                 isDate = true;
271:                                 return;
272:                         }
273:                         final EAnnotation eAnnotation = eType.getEAnnotation("http:///org/eclipse/emf/ecore/util/ExtendedMetaData");//$NON-NLS-1$
274:•                        if (eAnnotation == null) {
275:                                 isDate = true;
276:                                 return;
277:                         }
278:                         final EMap<String, String> typeDetails = eAnnotation.getDetails();
279:•                        if (typeDetails.containsKey("name")) {//$NON-NLS-1$
280:                                 isDate = "date".equals(typeDetails.get("name"));//$NON-NLS-1$//$NON-NLS-2$
281:•                        } else if (typeDetails.containsKey("baseType")) {//$NON-NLS-1$
282:                                 isDate = typeDetails.get("baseType").endsWith("date");//$NON-NLS-1$//$NON-NLS-2$
283:                         } else {
284:                                 isDate = true;
285:                         }
286:
287:                 }
288:
289:                 @Override
290:                 protected Object convertValue(final Object value) {
291:                         try {
292:                                 Date date = null;
293:•                                if (String.class.isInstance(value)) {
294:                                         date = setupFormat().parse((String) value);
295:•                                } else if (Date.class.isInstance(value)) {
296:                                         date = (Date) value;
297:•                                } else if (value == null) {
298:                                         return value;
299:                                 }
300:                                 final String xmlFormat = CHECK_FORMAT.format(date);
301:•                                if (!CHECK_PATTERN.matcher(xmlFormat).matches()) {
302:                                         return revertToOldValue(value);
303:                                 }
304:                                 final String formatedDate = setupFormat().format(date);
305:                                 text.setText(formatedDate);
306:
307:                                 final Calendar targetCal = Calendar.getInstance();
308:                                 targetCal.setTime(date);
309:•                                if (isDate) {
310:                                         return DateUtil.convertOnlyDateToXMLGregorianCalendar(targetCal);
311:                                 }
312:                                 return DateUtil.convertCalendarToXMLGregorianCalendar(targetCal);
313:                         } catch (final ParseException ex) {
314:                                 return revertToOldValue(value);
315:                         }
316:                 }
317:
318:                 private Object revertToOldValue(final Object value) {
319:
320:•                        if (eStructuralFeature.getDefaultValue() == null && (value == null || value.equals(""))) { //$NON-NLS-1$
321:                                 return null;
322:                         }
323:
324:                         Object result;
325:                         try {
326:                                 result = getModelValue().getValue();
327:                         } catch (final DatabindingFailedException ex) {
328:                                 getReportService().report(new AbstractReport(ex));
329:                                 return null;
330:                         }
331:
332:                         final MessageDialog messageDialog = new MessageDialog(text.getShell(),
333:                                 LocalizationServiceHelper.getString(XMLDateControlSWTRenderer.class,
334:                                         MessageKeys.XmlDateControlText_InvalidNumber),
335:                                 null,
336:                                 LocalizationServiceHelper.getString(XMLDateControlSWTRenderer.class,
337:                                         MessageKeys.XmlDateControlText_NumberInvalidValueWillBeUnset),
338:                                 MessageDialog.ERROR,
339:                                 new String[] { JFaceResources.getString(IDialogLabelKeys.OK_LABEL_KEY) }, 0);
340:
341:                         new ECPDialogExecutor(messageDialog) {
342:                                 @Override
343:                                 public void handleResult(int codeResult) {
344:
345:                                 }
346:                         }.execute();
347:
348:                         getDataBindingContext().updateTargets();
349:
350:•                        if (eStructuralFeature.isUnsettable() && result == null) {
351:                                 return SetCommand.UNSET_VALUE;
352:                         }
353:                         return result;
354:                 }
355:         }
356:
357:         private Shell dialog;
358:         private EMFFormsLocaleChangeListener emfFormsLocaleChangeListener;
359:         private Text text;
360:
361:         @Override
362:         protected Control createSWTControl(Composite parent) {
363:                 final Composite main = new Composite(parent, SWT.NONE);
364:                 main.setBackground(parent.getBackground());
365:                 GridLayoutFactory.fillDefaults().numColumns(2).applyTo(main);
366:                 GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.BEGINNING).applyTo(main);
367:                 final Control control = super.createSWTControl(main);
368:                 GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.CENTER).applyTo(control);
369:                 final Button bDate = new Button(main, SWT.PUSH);
370:                 GridDataFactory.fillDefaults().grab(false, false).align(SWT.CENTER, SWT.CENTER).applyTo(bDate);
371:                 bDate.setImage(
372:                         imageRegistryService.getImage(FrameworkUtil.getBundle(XMLDateControlSWTRenderer.class), "icons/date.png")); //$NON-NLS-1$
373:                 bDate.setData(CUSTOM_VARIANT, "org_eclipse_emf_ecp_control_xmldate"); //$NON-NLS-1$
374:                 text = (Text) Composite.class.cast(control).getChildren()[0];
375:                 bDate.addSelectionListener(new SelectionAdapterExtension(text, bDate));
376:                 return main;
377:         }
378:
379:         @Override
380:         protected String getTextMessage() {
381:                 return ((SimpleDateFormat) setupFormat()).toPattern();
382:         }
383:
384:         @Override
385:         protected String getTextVariantID() {
386:                 return "org_eclipse_emf_ecp_control_xmldate"; //$NON-NLS-1$
387:         }
388:
389:         @Override
390:         protected Binding[] createBindings(Control control) throws DatabindingFailedException {
391:                 final EStructuralFeature structuralFeature = (EStructuralFeature) getModelValue().getValueType();
392:                 final Text text = (Text) Composite.class.cast(Composite.class.cast(control).getChildren()[0]).getChildren()[0];
393:
394:                 final IObservableValue value = WidgetProperties.text(SWT.FocusOut).observe(text);
395:
396:                 final UpdateValueStrategy targetToModelUpdateStrategy = withPreSetValidation(
397:                         new DateTargetToModelUpdateStrategy(structuralFeature, text));
398:
399:                 final DateModelToTargetUpdateStrategy modelToTargetUpdateStrategy = new DateModelToTargetUpdateStrategy(false);
400:
401:                 final Binding binding = getDataBindingContext().bindValue(value, getModelValue(),
402:                         targetToModelUpdateStrategy, modelToTargetUpdateStrategy);
403:
404:                 final Binding tooltipBinding = createTooltipBinding(control, getModelValue(), getDataBindingContext(),
405:                         new UpdateValueStrategy(UpdateValueStrategy.POLICY_NEVER), new DateModelToTargetUpdateStrategy(true));
406:
407:                 emfFormsLocaleChangeListener = new EMFFormsLocaleChangeListener() {
408:
409:                         /**
410:                          * {@inheritDoc}
411:                          *
412:                          * @see org.eclipse.emfforms.spi.common.locale.EMFFormsLocaleChangeListener#notifyLocaleChange()
413:                          */
414:                         @Override
415:                         public void notifyLocaleChange() {
416:                                 text.setMessage(getTextMessage());
417:                                 binding.updateModelToTarget();
418:                         }
419:                 };
420:                 localeProvider.addEMFFormsLocaleChangeListener(emfFormsLocaleChangeListener);
421:
422:                 return new Binding[] { binding, tooltipBinding };
423:         }
424:
425:         /**
426:          * Setups the {@link DateFormat}.
427:          *
428:          * @return the {@link DateFormat}
429:          */
430:         protected DateFormat setupFormat() {
431:                 final DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, localeProvider.getLocale());
432:                 df.setLenient(false);
433:                 return df;
434:         }
435:
436:         /**
437:          * {@inheritDoc}
438:          *
439:          * @see org.eclipse.emf.ecp.view.spi.core.swt.SimpleControlSWTControlSWTRenderer#setValidationColor(org.eclipse.swt.widgets.Control,
440:          * org.eclipse.swt.graphics.Color)
441:          */
442:         @Override
443:         protected void setValidationColor(Control control, Color validationColor) {
444:                 super.setValidationColor(getControlCompositeFromControl(control), validationColor);
445:         }
446:
447:         @Override
448:         protected void setValidationForegroundColor(Control control, Color validationColor) {
449:                 super.setValidationForegroundColor(getControlCompositeFromControl(control), validationColor);
450:         }
451:
452:         @Override
453:         protected void setControlEnabled(SWTGridCell gridCell, Control control, boolean enabled) {
454:                 if (getVElement().getLabelAlignment() == LabelAlignment.NONE && gridCell.getColumn() == 1
455:                         || hasLeftLabelAlignment() && gridCell.getColumn() == 2) {
456:                         if (isUnsetButtonLeftOfControlComposite()) {
457:                                 super.setControlEnabled(gridCell, control, enabled);
458:                                 ((Button) ((Composite) control).getChildren()[0]).setVisible(enabled);
459:                         } else {
460:                                 super.setControlEnabled(gridCell, control, enabled);
461:                                 ((Button) ((Composite) control).getChildren()[1]).setVisible(enabled);
462:                         }
463:                 } else {
464:                         super.setControlEnabled(gridCell, control, enabled);
465:                 }
466:         }
467:
468:         /**
469:          * {@inheritDoc}
470:          *
471:          * @see org.eclipse.emf.ecp.view.spi.core.swt.renderer.TextControlSWTRenderer#getUnsetText()
472:          */
473:         @Override
474:         protected String getUnsetText() {
475:                 return localizationService
476:                         .getString(getClass(), MessageKeys.XmlDateControlText_NoDateSetClickToSetDate);
477:         }
478:
479:         /**
480:          * {@inheritDoc}
481:          *
482:          * @see org.eclipse.emf.ecp.view.spi.core.swt.SimpleControlSWTRenderer#dispose()
483:          */
484:         @Override
485:         protected void dispose() {
486:                 if (dialog != null && !dialog.isDisposed()) {
487:                         dialog.dispose();
488:                 }
489:                 localeProvider.removeEMFFormsLocaleChangeListener(emfFormsLocaleChangeListener);
490:                 super.dispose();
491:         }
492:
493: }