Skip to content

Package: ECPAbstractCustomControlSWT$1

ECPAbstractCustomControlSWT$1

nameinstructionbranchcomplexitylinemethod
convert(Object)
M: 22 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
{...}
M: 9 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2011-2015 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 Neufeld - initial API and implementation
13: * Stefan Dirix - Add ControlProcessorService
14: *******************************************************************************/
15: package org.eclipse.emf.ecp.view.spi.custom.swt;
16:
17: import java.util.Collections;
18: import java.util.LinkedHashMap;
19: import java.util.LinkedHashSet;
20: import java.util.List;
21: import java.util.Map;
22: import java.util.Set;
23:
24: import org.eclipse.core.databinding.Binding;
25: import org.eclipse.core.databinding.DataBindingContext;
26: import org.eclipse.core.databinding.UpdateValueStrategy;
27: import org.eclipse.core.databinding.observable.IObserving;
28: import org.eclipse.core.databinding.observable.list.IObservableList;
29: import org.eclipse.core.databinding.observable.value.IObservableValue;
30: import org.eclipse.core.databinding.property.value.IValueProperty;
31: import org.eclipse.core.runtime.Platform;
32: import org.eclipse.emf.common.notify.Adapter;
33: import org.eclipse.emf.common.notify.AdapterFactory;
34: import org.eclipse.emf.common.notify.Notification;
35: import org.eclipse.emf.common.notify.impl.AdapterImpl;
36: import org.eclipse.emf.common.util.Diagnostic;
37: import org.eclipse.emf.databinding.EMFDataBindingContext;
38: import org.eclipse.emf.databinding.edit.EMFEditObservables;
39: import org.eclipse.emf.ecore.EStructuralFeature;
40: import org.eclipse.emf.ecore.EStructuralFeature.Setting;
41: import org.eclipse.emf.ecore.InternalEObject;
42: import org.eclipse.emf.ecore.util.EcoreUtil;
43: import org.eclipse.emf.ecp.edit.spi.ECPAbstractControl;
44: import org.eclipse.emf.ecp.edit.spi.ECPControlFactory;
45: import org.eclipse.emf.ecp.view.internal.custom.swt.Activator;
46: import org.eclipse.emf.ecp.view.spi.context.ViewModelContext;
47: import org.eclipse.emf.ecp.view.spi.custom.model.ECPCustomControlChangeListener;
48: import org.eclipse.emf.ecp.view.spi.custom.model.ECPHardcodedReferences;
49: import org.eclipse.emf.ecp.view.spi.custom.model.VCustomControl;
50: import org.eclipse.emf.ecp.view.spi.custom.model.VCustomDomainModelReference;
51: import org.eclipse.emf.ecp.view.spi.custom.model.impl.VCustomDomainModelReferenceImpl;
52: import org.eclipse.emf.ecp.view.spi.model.LabelAlignment;
53: import org.eclipse.emf.ecp.view.spi.model.VControl;
54: import org.eclipse.emf.ecp.view.spi.model.VDomainModelReference;
55: import org.eclipse.emf.ecp.view.spi.model.VFeaturePathDomainModelReference;
56: import org.eclipse.emf.ecp.view.spi.model.VViewFactory;
57: import org.eclipse.emf.ecp.view.spi.renderer.NoPropertyDescriptorFoundExeption;
58: import org.eclipse.emf.ecp.view.spi.renderer.NoRendererFoundException;
59: import org.eclipse.emf.ecp.view.spi.swt.reporting.RenderingFailedReport;
60: import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
61: import org.eclipse.emf.edit.domain.EditingDomain;
62: import org.eclipse.emf.edit.provider.AdapterFactoryItemDelegator;
63: import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
64: import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
65: import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
66: import org.eclipse.emfforms.spi.core.services.databinding.DatabindingFailedException;
67: import org.eclipse.emfforms.spi.core.services.databinding.DatabindingFailedReport;
68: import org.eclipse.emfforms.spi.core.services.databinding.EMFFormsDatabinding;
69: import org.eclipse.emfforms.spi.core.services.label.EMFFormsLabelProvider;
70: import org.eclipse.emfforms.spi.core.services.label.NoLabelFoundException;
71: import org.eclipse.emfforms.spi.localization.LocalizationServiceHelper;
72: import org.eclipse.emfforms.spi.swt.core.layout.GridDescriptionFactory;
73: import org.eclipse.emfforms.spi.swt.core.layout.SWTGridCell;
74: import org.eclipse.emfforms.spi.swt.core.layout.SWTGridDescription;
75: import org.eclipse.jface.databinding.swt.typed.WidgetProperties;
76: import org.eclipse.jface.databinding.viewers.ViewerSupport;
77: import org.eclipse.jface.viewers.StructuredViewer;
78: import org.eclipse.swt.SWT;
79: import org.eclipse.swt.graphics.Image;
80: import org.eclipse.swt.widgets.Composite;
81: import org.eclipse.swt.widgets.Control;
82: import org.eclipse.swt.widgets.Label;
83: import org.osgi.framework.Bundle;
84:
85: /**
86: * Extend this class in order to provide an own implementation of an {@link ECPAbstractCustomControlSWT}.
87: *
88: * @author Eugen Neufeld
89: * @since 1.2
90: *
91: */
92: @SuppressWarnings("deprecation")
93: public abstract class ECPAbstractCustomControlSWT {
94:         /**
95:          * Variant constant for indicating RAP controls.
96:          *
97:          * @since 1.3
98:          */
99:         protected static final String CUSTOM_VARIANT = "org.eclipse.rap.rwt.customVariant"; //$NON-NLS-1$
100:         /**
101:          * Constant for an validation error image.
102:          */
103:         public static final int VALIDATION_ERROR_IMAGE = 0;
104:         /**
105:          * Constant for an add image.
106:          */
107:         public static final int ADD_IMAGE = 1;
108:         /**
109:          * Constant for an delete image.
110:          */
111:         public static final int DELETE_IMAGE = 2;
112:         /**
113:          * Constant for a help image.
114:          */
115:         public static final int HELP_IMAGE = 3;
116:
117:         private final SWTCustomControlHelper swtHelper = new SWTCustomControlHelper();
118:         private ECPControlFactory controlFactory;
119:         private final Map<EStructuralFeature, ECPAbstractControl> controlMap = new LinkedHashMap<EStructuralFeature, ECPAbstractControl>();
120:         private final Map<VDomainModelReference, Adapter> adapterMap = new LinkedHashMap<VDomainModelReference, Adapter>();
121:         private ViewModelContext viewModelContext;
122:         private ComposedAdapterFactory composedAdapterFactory;
123:         private AdapterFactoryItemDelegator adapterFactoryItemDelegator;
124:         private VCustomControl customControl;
125:         private DataBindingContext dataBindingContext;
126:         private final EMFDataBindingContext viewModelDBC = new EMFDataBindingContext();
127:
128:         /**
129:          * Called by the framework to trigger an initialization.
130:          *
131:          * @param customControl the {@link VCustomControl} to use
132:          * @param viewModelContext the {@link ViewModelContext} to use
133:          * @since 1.3
134:          */
135:         public final void init(VCustomControl customControl, ViewModelContext viewModelContext) {
136:                 this.customControl = customControl;
137:                 this.viewModelContext = viewModelContext;
138:                 controlFactory = Activator.getDefault().getECPControlFactory();
139:
140:                 composedAdapterFactory = new ComposedAdapterFactory(new AdapterFactory[] {
141:                         new ReflectiveItemProviderAdapterFactory(),
142:                         new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE) });
143:                 adapterFactoryItemDelegator = new AdapterFactoryItemDelegator(composedAdapterFactory);
144:                 postInit();
145:         }
146:
147:         /**
148:          * This method is called after the initialization. Custom controls can overwrite this to execute specific
149:          * initialization steps.
150:          *
151:          * @since 1.3
152:          */
153:         protected void postInit() {
154:                 if (!VCustomDomainModelReference.class.isInstance(customControl.getDomainModelReference())) {
155:                         return;
156:                 }
157:                 final VCustomDomainModelReference customDomainModelReference = VCustomDomainModelReference.class
158:                         .cast(customControl.getDomainModelReference());
159:
160:                 final ECPHardcodedReferences hardcodedReferences = loadObject(customDomainModelReference.getBundleName(),
161:                         customDomainModelReference.getClassName());
162:                 if (!customDomainModelReference.isControlChecked()) {
163:                         // read stuff from control
164:                         final Set<VDomainModelReference> controlReferences = new LinkedHashSet<VDomainModelReference>();
165:                         controlReferences.addAll(hardcodedReferences.getNeededDomainModelReferences());
166:                         controlReferences.addAll(customDomainModelReference.getDomainModelReferences());
167:                         customDomainModelReference.getDomainModelReferences().clear();
168:                         customDomainModelReference.getDomainModelReferences().addAll(controlReferences);
169:                         customDomainModelReference.setControlChecked(true);
170:                 }
171:         }
172:
173:         private static ECPHardcodedReferences loadObject(String bundleName, String clazz) {
174:                 final Bundle bundle = Platform.getBundle(bundleName);
175:                 if (bundle == null) {
176:                         new ClassNotFoundException(String.format(LocalizationServiceHelper.getString(
177:                                 VCustomDomainModelReferenceImpl.class, "BundleNotFound_ExceptionMessage"), clazz, bundleName)); //$NON-NLS-1$
178:                         return null;
179:                 }
180:                 try {
181:                         final Class<?> loadClass = bundle.loadClass(clazz);
182:                         if (!ECPHardcodedReferences.class.isAssignableFrom(loadClass)) {
183:                                 return null;
184:                         }
185:                         return ECPHardcodedReferences.class.cast(loadClass.newInstance());
186:                 } catch (final ClassNotFoundException ex) {
187:                         return null;
188:                 } catch (final InstantiationException ex) {
189:                         return null;
190:                 } catch (final IllegalAccessException ex) {
191:                         return null;
192:                 }
193:
194:         }
195:
196:         /**
197:          * Is called by the framework to trigger a dispose of the control.
198:          */
199:         public final void dispose() {
200:                 if (composedAdapterFactory != null) {
201:                         composedAdapterFactory.dispose();
202:                 }
203:                 if (dataBindingContext != null) {
204:                         dataBindingContext.dispose();
205:                 }
206:                 viewModelDBC.dispose();
207:                 customControl = null;
208:                 if (adapterMap != null) {
209:                         for (final VDomainModelReference domainModelReference : adapterMap.keySet()) {
210:                                 final Setting setting = getFirstSetting(domainModelReference);
211:                                 setting.getEObject().eAdapters().remove(adapterMap.get(domainModelReference));
212:                         }
213:
214:                         adapterMap.clear();
215:                 }
216:                 if (controlMap != null) {
217:                         for (final ECPAbstractControl control : controlMap.values()) {
218:                                 control.dispose();
219:                         }
220:                         controlMap.clear();
221:                 }
222:                 viewModelContext = null;
223:
224:                 Activator.getDefault().ungetECPControlFactory();
225:                 controlFactory = null;
226:
227:                 disposeCustomControl();
228:         }
229:
230:         /**
231:          * This method is called during dispose and allows to dispose necessary objects.
232:          *
233:          * @since 1.3
234:          */
235:         protected abstract void disposeCustomControl();
236:
237:         /**
238:          * Return the {@link ViewModelContext}.
239:          *
240:          * @return the {@link ViewModelContext} of this control
241:          * @since 1.3
242:          */
243:         protected final ViewModelContext getViewModelContext() {
244:                 return viewModelContext;
245:         }
246:
247:         /**
248:          * Return the {@link VCustomControl}.
249:          *
250:          * @return the {@link VCustomControl} of this control
251:          * @since 1.3
252:          */
253:         protected final VCustomControl getCustomControl() {
254:                 return customControl;
255:         }
256:
257:         /**
258:          * Returns a {@link DataBindingContext} for this control.
259:          *
260:          * @return the {@link DataBindingContext}
261:          * @since 1.3
262:          */
263:         protected final DataBindingContext getDataBindingContext() {
264:                 if (dataBindingContext == null) {
265:                         dataBindingContext = new EMFDataBindingContext();
266:                 }
267:                 return dataBindingContext;
268:         }
269:
270:         private void handleCreatedControls(Diagnostic diagnostic) {
271:                 if (diagnostic.getData() == null) {
272:                         return;
273:                 }
274:                 if (diagnostic.getData().size() < 2) {
275:                         return;
276:                 }
277:                 if (!(diagnostic.getData().get(1) instanceof EStructuralFeature)) {
278:                         return;
279:                 }
280:                 final EStructuralFeature feature = (EStructuralFeature) diagnostic.getData().get(1);
281:                 final ECPAbstractControl ecpControl = controlMap.get(feature);
282:                 if (ecpControl == null) {
283:                         return;
284:                 }
285:                 ecpControl.handleValidation(diagnostic);
286:         }
287:
288:         /**
289:          * This is called so that an error can be shown by the user.
290:          *
291:          * @since 1.3
292:          */
293:         protected abstract void handleContentValidation();
294:
295:         /**
296:          * This is a helper method which provides an {@link SWTCustomControlHelper}. It allows to get an image based on the
297:          * constants defined in {@link ECPAbstractCustomControlSWT}.
298:          *
299:          * @return the {@link SWTCustomControlHelper} to use to retrieve images.
300:          * @since 1.3
301:          */
302:         protected final SWTCustomControlHelper getHelper() {
303:                 return swtHelper;
304:         }
305:
306:         private Image getImage(int imageType) {
307:                 switch (imageType) {
308:                 case VALIDATION_ERROR_IMAGE:
309:                         return Activator.getImage("icons/validation_error.png"); //$NON-NLS-1$
310:                 case HELP_IMAGE:
311:                         return Activator.getImage("icons/help.png"); //$NON-NLS-1$
312:                 case ADD_IMAGE:
313:                         return Activator.getImage("icons/add.png"); //$NON-NLS-1$
314:                 case DELETE_IMAGE:
315:                         return Activator.getImage("icons/unset_reference.png"); //$NON-NLS-1$
316:                 default:
317:                         return null;
318:                 }
319:         }
320:
321:         /**
322:          * Whether the label for this control should be rendered on the left of the control. This is the case if the
323:          * {@link VControl#getLabelAlignment()} is set to {@link LabelAlignment#LEFT} or {@link LabelAlignment#DEFAULT}.
324:          *
325:          * @return <code>true</code> if label should be on the left, <code>false</code> otherwise
326:          * @since 1.7
327:          */
328:         protected boolean hasLeftLabelAlignment() {
329:                 return getCustomControl().getLabelAlignment() == LabelAlignment.LEFT
330:                         || getCustomControl().getLabelAlignment() == LabelAlignment.DEFAULT;
331:         }
332:
333:         /**
334:          * Create the {@link Control} displaying the label of the current {@link VControl}.
335:          *
336:          * @param parent the {@link Composite} to render onto
337:          * @return the created {@link Control} or null
338:          * @throws NoPropertyDescriptorFoundExeption thrown if the {@link org.eclipse.emf.ecore.EStructuralFeature
339:          * EStructuralFeature} of the {@link VControl} doesn't have a registered {@link IItemPropertyDescriptor}
340:          * @since 1.3
341:          */
342:         protected final Control createLabel(final Composite parent)
343:                 throws NoPropertyDescriptorFoundExeption {
344:                 Label label = null;
345:                 labelRender: if (hasLeftLabelAlignment()) {
346:                         IValueProperty valueProperty;
347:                         try {
348:                                 valueProperty = getViewModelContext().getService(EMFFormsDatabinding.class)
349:                                         .getValueProperty(getCustomControl().getDomainModelReference(),
350:                                                 getViewModelContext().getDomainModel());
351:                         } catch (final DatabindingFailedException ex) {
352:                                 Activator.getDefault().getReportService().report(new DatabindingFailedReport(ex));
353:                                 break labelRender;
354:                         }
355:                         final EStructuralFeature structuralFeature = (EStructuralFeature) valueProperty.getValueType();
356:
357:                         label = new Label(parent, SWT.NONE);
358:                         label.setData(CUSTOM_VARIANT, "org_eclipse_emf_ecp_control_label"); //$NON-NLS-1$
359:                         label.setBackground(parent.getBackground());
360:
361:                         try {
362:                                 viewModelDBC.bindValue(
363:                                         WidgetProperties.text().observe(label),
364:                                         getViewModelContext().getService(EMFFormsLabelProvider.class)
365:                                                 .getDisplayName(getCustomControl().getDomainModelReference(),
366:                                                         getViewModelContext().getDomainModel()),
367:                                         null, new UpdateValueStrategy() {
368:
369:                                                 /**
370:                                                  * {@inheritDoc}
371:                                                  *
372:                                                  * @see org.eclipse.core.databinding.UpdateValueStrategy#convert(java.lang.Object)
373:                                                  */
374:                                                 @Override
375:                                                 public Object convert(Object value) {
376:                                                         final String labelText = (String) super.convert(value);
377:                                                         String extra = ""; //$NON-NLS-1$
378:•                                                        if (structuralFeature.getLowerBound() > 0) {
379:                                                                 extra = "*"; //$NON-NLS-1$
380:                                                         }
381:                                                         return labelText + extra;
382:                                                 }
383:
384:                                         });
385:                                 viewModelDBC.bindValue(
386:                                         WidgetProperties.tooltipText().observe(label),
387:                                         getViewModelContext().getService(EMFFormsLabelProvider.class)
388:                                                 .getDescription(getCustomControl().getDomainModelReference(),
389:                                                         getViewModelContext().getDomainModel()));
390:                         } catch (final NoLabelFoundException e) {
391:                                 Activator.getDefault().getReportService().report(new RenderingFailedReport(e));
392:                                 label.setText(e.getMessage());
393:                                 label.setToolTipText(e.toString());
394:                         }
395:
396:                 }
397:                 return label;
398:         }
399:
400:         /**
401:          * Creates a Label which is used to display the validation icon.
402:          *
403:          * @param composite the {@link Composite} to render onto
404:          * @return the created Label
405:          * @since 1.3
406:          */
407:         protected final Label createValidationIcon(Composite composite) {
408:                 final Label validationLabel = new Label(composite, SWT.NONE);
409:                 validationLabel.setBackground(composite.getBackground());
410:                 return validationLabel;
411:         }
412:
413:         /**
414:          * Creates a binding for a {@link StructuredViewer} based on a {@link ECPCustomControlFeature} and the array of
415:          * {@link IValueProperty IValueProperties} for labels.
416:          *
417:          * @param customControlFeature the {@link ECPCustomControlFeature} to use
418:          * @param viewer the {@link StructuredViewer} to bind
419:          * @param labelProperties the array if {@link IValueProperty IValueProperties} to use for labels
420:          */
421:         protected final void createViewerBinding(VDomainModelReference customControlFeature, StructuredViewer viewer,
422:                 IValueProperty[] labelProperties) {
423:                 try {
424:                         final IObservableList list = getViewModelContext().getService(EMFFormsDatabinding.class)
425:                                 .getObservableList(customControlFeature, getViewModelContext().getDomainModel());
426:                         ViewerSupport.bind(viewer, list, labelProperties);
427:                 } catch (final DatabindingFailedException ex) {
428:                         Activator.getDefault().getReportService().report(new DatabindingFailedReport(ex));
429:                 }
430:         }
431:
432:         /**
433:          * Return an {@link IObservableList} based on a {@link VDomainModelReference}.
434:          *
435:          * @param domainModelReference the {@link VDomainModelReference} to use
436:          * @return the {@link IObservableList}
437:          * @since 1.3
438:          * @deprecated This method is deprecated and must not be used anymore. Use the
439:          * {@link org.eclipse.emfforms.spi.core.services.databinding.EMFFormsDatabinding
440:          * databinding service} instead.
441:          */
442:         @Deprecated
443:         protected final IObservableList getObservableList(VDomainModelReference domainModelReference) {
444:                 throw new UnsupportedOperationException(
445:                         "This method is deprecated and must not be used anymore. Use the databinding service instead."); //$NON-NLS-1$
446:         }
447:
448:         /**
449:          * Returns the {@link EditingDomain} for the provided {@link Setting}.
450:          *
451:          * @param setting the provided {@link Setting}
452:          * @return the {@link EditingDomain} of this {@link Setting}
453:          * @since 1.3
454:          */
455:         protected final EditingDomain getEditingDomain(Setting setting) {
456:                 return AdapterFactoryEditingDomain.getEditingDomainFor(setting.getEObject());
457:         }
458:
459:         /**
460:          * @param modelFeature the {@link VDomainModelReference} to get the Setting for
461:          * @return the setting or throws an {@link IllegalStateException} if too many or too few elements are found.
462:          */
463:         private Setting getFirstSetting(VDomainModelReference modelFeature) {
464:                 IObservableValue observableValue;
465:                 try {
466:                         observableValue = getViewModelContext().getService(EMFFormsDatabinding.class)
467:                                 .getObservableValue(modelFeature, getViewModelContext().getDomainModel());
468:                 } catch (final DatabindingFailedException ex) {
469:                         Activator.getDefault().getReportService().report(new DatabindingFailedReport(ex));
470:                         throw new IllegalStateException("The databinding failed due to an incorrect VDomainModelReference: " //$NON-NLS-1$
471:                                 + ex.getMessage());
472:                 }
473:                 final InternalEObject internalEObject = (InternalEObject) ((IObserving) observableValue).getObserved();
474:                 final EStructuralFeature structuralFeature = (EStructuralFeature) observableValue.getValueType();
475:                 observableValue.dispose();
476:
477:                 return internalEObject.eSetting(structuralFeature);
478:         }
479:
480:         /**
481:          * Use this method to get an {@link ECPControl} which can be used inside the {@link ECPCustomControl}.
482:          *
483:          * @param clazz the {@link Class} of the {@link ECPControl} to retrieve
484:          * @param domainModelReference the {@link VDomainModelReference} to retrieve a control for
485:          * @param <T> the type of the control to retrieve
486:          * @return the {@link ECPControl} that is fitting the most for the {@link ECPCustomControlFeature}. Can also be
487:          * null.
488:          * @since 1.3
489:          */
490:         protected final <T extends ECPAbstractControl> T getControl(Class<T> clazz,
491:                 VDomainModelReference domainModelReference) {
492:                 final T createControl = controlFactory.createControl(clazz, getViewModelContext().getDomainModel(),
493:                         domainModelReference);
494:                 final VControl vControl = VViewFactory.eINSTANCE.createControl();
495:                 final VDomainModelReference modelReference = EcoreUtil.copy(domainModelReference);
496:                 vControl.setDomainModelReference(modelReference);
497:                 vControl.setDiagnostic(VViewFactory.eINSTANCE.createDiagnostic());
498:                 createControl.init(getViewModelContext(), vControl);
499:
500:                 IValueProperty valueProperty;
501:                 try {
502:                         valueProperty = getViewModelContext().getService(EMFFormsDatabinding.class)
503:                                 .getValueProperty(domainModelReference, getViewModelContext().getDomainModel());
504:                 } catch (final DatabindingFailedException ex) {
505:                         Activator.getDefault().getReportService().report(new DatabindingFailedReport(ex));
506:                         return null;
507:                 }
508:                 final EStructuralFeature structuralFeature = (EStructuralFeature) valueProperty.getValueType();
509:                 controlMap.put(structuralFeature, createControl);
510:                 return createControl;
511:         }
512:
513:         /**
514:          * Return the {@link IItemPropertyDescriptor} describing this {@link Setting}.
515:          *
516:          * @param setting the {@link Setting} to use for identifying the {@link IItemPropertyDescriptor}.
517:          * @return the {@link IItemPropertyDescriptor}
518:          * @since 1.3
519:          */
520:         protected final IItemPropertyDescriptor getItemPropertyDescriptor(Setting setting) {
521:                 return adapterFactoryItemDelegator.getPropertyDescriptor(setting.getEObject(),
522:                         setting.getEStructuralFeature());
523:         }
524:
525:         private String getHelp(VDomainModelReference domainModelReference) {
526:                 if (!getResolvedDomainModelReferences().contains(domainModelReference)) {
527:                         throw new IllegalArgumentException("The feature must have been registered before!"); //$NON-NLS-1$
528:                 }
529:                 return getItemPropertyDescriptor(getFirstSetting(domainModelReference)).getDescription(null);
530:         }
531:
532:         private String getLabel(VDomainModelReference domainModelReference) {
533:                 if (!getResolvedDomainModelReferences().contains(domainModelReference)) {
534:                         throw new IllegalArgumentException("The feature must have been registered before!"); //$NON-NLS-1$
535:                 }
536:                 return getItemPropertyDescriptor(getFirstSetting(domainModelReference)).getDisplayName(null);
537:         }
538:
539:         /**
540:          * Returns a list of all {@link VDomainModelReference VDomainModelReferences} which were already resolved and thus
541:          * can be used for binding etc.
542:          *
543:          * @return the List of {@link VDomainModelReference VDomainModelReferences}
544:          * @since 1.3
545:          */
546:         protected final List<VDomainModelReference> getResolvedDomainModelReferences() {
547:                 // final VHardcodedDomainModelReference hardcodedDomainModelReference = VHardcodedDomainModelReference.class
548:                 // .cast(getCustomControl().getDomainModelReference());
549:                 // return hardcodedDomainModelReference.getDomainModelReferences();
550:                 final VDomainModelReference domainModelReference = getCustomControl().getDomainModelReference();
551:                 if (VCustomDomainModelReference.class.isInstance(domainModelReference)) {
552:                         return VCustomDomainModelReference.class.cast(domainModelReference).getDomainModelReferences();
553:                 }
554:                 return Collections.singletonList(domainModelReference);
555:         }
556:
557:         /**
558:          * Finds the {@link VDomainModelReference} which provides a specific {@link EStructuralFeature}.
559:          *
560:          * @param feature the {@link EStructuralFeature} to find the {@link VDomainModelReference} for
561:          * @return the {@link VDomainModelReference} or null
562:          * @since 1.3
563:          */
564:         protected final VDomainModelReference getResolvedDomainModelReference(EStructuralFeature feature) {
565:                 for (final VDomainModelReference domainModelReference : getResolvedDomainModelReferences()) {
566:                         if (VFeaturePathDomainModelReference.class.isInstance(domainModelReference)) {
567:                                 final VFeaturePathDomainModelReference ref = VFeaturePathDomainModelReference.class
568:                                         .cast(domainModelReference);
569:                                 if (ref.getDomainModelEFeature() == feature) {
570:                                         return ref;
571:                                 }
572:                         }
573:                 }
574:                 return null;
575:         }
576:
577:         /**
578:          * Method for enabling databinding on the reference/attribute of the referenced object.
579:          * Throws an {@link IllegalStateException} if the {@link VDomainModelReference} doesn't resolve to exactly one
580:          * {@link Setting}.
581:          *
582:          *
583:          * @param modelFeature the {@link VDomainModelReference} to bind
584:          * @param targetValue the target observerable
585:          * @param targetToModel update strategy target to model
586:          * @param modelToTarget update strategy model to target
587:          * @return the resulting binding
588:          * @since 1.3
589:          */
590:         protected final Binding bindTargetToModel(VDomainModelReference modelFeature, IObservableValue targetValue,
591:                 UpdateValueStrategy targetToModel,
592:                 UpdateValueStrategy modelToTarget) {
593:                 final Setting setting = getFirstSetting(modelFeature);
594:                 final IObservableValue modelValue = EMFEditObservables.observeValue(
595:                         getEditingDomain(setting),
596:                         setting.getEObject(), setting.getEStructuralFeature());
597:                 return getDataBindingContext().bindValue(targetValue, modelValue, targetToModel,
598:                         modelToTarget);
599:         }
600:
601:         /**
602:          * Provides the {@link EditingDomain} for this custom control.
603:          *
604:          * @return the {@link EditingDomain} for this control
605:          * @since 1.3
606:          */
607:         protected final EditingDomain getEditingDomain() {
608:                 return getEditingDomain(getFirstSetting(getCustomControl().getDomainModelReference()));
609:         }
610:
611:         /**
612:          * Returns the current set value of the feature.
613:          * Throws an {@link IllegalStateException} if the {@link VDomainModelReference} doesn't resolve to exactly one
614:          * {@link Setting}.
615:          *
616:          * @param modelReference the {@link VDomainModelReference} to get the value for
617:          * @return the value
618:          * @since 1.3
619:          */
620:         protected final Object getValue(VDomainModelReference modelReference) {
621:                 final Setting setting = getFirstSetting(modelReference);
622:                 return setting.get(false);
623:         }
624:
625:         /**
626:          * Sets the value of the feature to the new value.
627:          * Throws an {@link IllegalStateException} if the {@link VDomainModelReference} doesn't resolve to exactly one
628:          * {@link Setting}.
629:          *
630:          * @param modelReference the {@link VDomainModelReference} to get the value for
631:          * @param newValue the value to be set
632:          * @since 1.3
633:          */
634:         protected final void setValue(VDomainModelReference modelReference, Object newValue) {
635:                 // FIXME needed?
636:                 // if (!isEditable) {
637:                 // throw new UnsupportedOperationException(
638:                 // "Set value is not supported on ECPCustomControlFeatures that are not editable.");
639:                 // }
640:                 final Setting setting = getFirstSetting(modelReference);
641:                 setting.set(newValue);
642:         }
643:
644:         /**
645:          *
646:          * Registers a change listener on the referenced object. {@link ECPCustomControlChangeListener#notifyChanged()} will
647:          * be called when a change on the referenced object is noticed.
648:          *
649:          * Throws an {@link IllegalStateException} if the {@link VDomainModelReference} doesn't resolve to exactly one
650:          * {@link Setting}.
651:          *
652:          * @param modelReference the {@link VDomainModelReference} to register a listener for
653:          * @param changeListener the change listener to register
654:          * @since 1.3
655:          */
656:         protected final void registerChangeListener(VDomainModelReference modelReference,
657:                 final ECPCustomControlChangeListener changeListener) {
658:                 if (adapterMap.containsKey(modelReference)) {
659:                         return;
660:                 }
661:                 final Setting setting = getFirstSetting(modelReference);
662:                 final Adapter newAdapter = new AdapterImpl() {
663:
664:                         @Override
665:                         public void notifyChanged(Notification msg) {
666:                                 if (msg.isTouch()) {
667:                                         return;
668:                                 }
669:                                 if (msg.getFeature().equals(setting.getEStructuralFeature())) {
670:                                         super.notifyChanged(msg);
671:                                         changeListener.notifyChanged();
672:                                 }
673:                         }
674:
675:                 };
676:                 setting.getEObject().eAdapters().add(newAdapter);
677:                 adapterMap.put(modelReference, newAdapter);
678:         }
679:
680:         /**
681:          * The {@link SWTCustomControlHelper} allows the retrieval of SWT specific elements.
682:          *
683:          * @author Eugen Neufeld
684:          *
685:          */
686:         public final class SWTCustomControlHelper {
687:
688:                 /**
689:                  * Allows to get an {@link Image} based on the constants defined in {@link ECPAbstractCustomControlSWT}.
690:                  *
691:                  * @param imageType the image type to retrieve
692:                  * @return the retrieved Image or null if an unknown imageType was provided
693:                  */
694:                 public Image getImage(int imageType) {
695:                         return ECPAbstractCustomControlSWT.this.getImage(imageType);
696:                 }
697:
698:                 /**
699:                  * This return a text providing a long helpful description of the feature. Can be used for example in a ToolTip.
700:                  *
701:                  * @param domainModelReference the {@link VDomainModelReference} to retrieve the help text for
702:                  * @return the String containing the helpful description or null if no description is found
703:                  * @since 1.3
704:                  */
705:                 public String getHelp(VDomainModelReference domainModelReference) {
706:                         return ECPAbstractCustomControlSWT.this.getHelp(domainModelReference);
707:                 }
708:
709:                 /**
710:                  * This return a text providing a short label of the feature. Can be used for example as a label in front of the
711:                  * edit field.
712:                  *
713:                  * @param domainModelReference the {@link VDomainModelReference} to retrieve the text for
714:                  * @return the String containing the label null if no label is found
715:                  * @since 1.3
716:                  */
717:                 public String getLabel(VDomainModelReference domainModelReference) {
718:                         return ECPAbstractCustomControlSWT.this.getLabel(domainModelReference);
719:                 }
720:         }
721:
722:         /**
723:          * Returns the GridDescription for this Renderer.
724:          *
725:          * @return the GridDescription
726:          * @since 1.6
727:          */
728:         public abstract SWTGridDescription getGridDescription();
729:
730:         /**
731:          * Renders the control.
732:          *
733:          * @param cell the {@link SWTGridCell} of the control to render
734:          * @param parent the {@link Composite} to render on
735:          * @return the rendered {@link Control}
736:          * @throws NoRendererFoundException this is thrown when a renderer cannot be found
737:          * @throws NoPropertyDescriptorFoundExeption this is thrown when no property descriptor can be found
738:          * @since 1.6
739:          */
740:         public abstract Control renderControl(SWTGridCell cell, Composite parent) throws NoRendererFoundException,
741:                 NoPropertyDescriptorFoundExeption;
742:
743:         /**
744:          * Called by the framework to apply validation changes.
745:          *
746:          * @since 1.3
747:          */
748:         public final void applyValidation() {
749:                 if (getCustomControl() == null || getCustomControl().getDiagnostic() == null) {
750:                         return;
751:                 }
752:                 for (final Object diagnostic : getCustomControl().getDiagnostic().getDiagnostics()) {
753:                         handleCreatedControls((Diagnostic) diagnostic);
754:                 }
755:
756:                 handleContentValidation();
757:         }
758:
759:         /**
760:          * Applies the current readOnlyState.
761:          *
762:          * @param controls the controls provided
763:          * @since 1.3
764:          */
765:         public final void applyReadOnly(Map<SWTGridCell, Control> controls) {
766:                 if (setEditable(!getCustomControl().isEffectivelyReadonly())) {
767:                         for (final SWTGridCell gridCell : controls.keySet()) {
768:                                 setControlEnabled(gridCell, controls.get(gridCell), !getCustomControl().isEffectivelyReadonly());
769:                         }
770:                 }
771:         }
772:
773:         /**
774:          * Override this to control which and how controls should be enabled/disabled.
775:          *
776:          * @param gridCell the {@link SWTGridCell} to enable/disable
777:          * @param control the {@link Control} to enable/disable
778:          * @param enabled true if the control should be enabled false otherwise
779:          * @since 1.6
780:          */
781:         protected void setControlEnabled(SWTGridCell gridCell, Control control, boolean enabled) {
782:                 // ignore labels as they are readonly per definition
783:                 if (Label.class.isInstance(control)) {
784:                         return;
785:                 }
786:                 control.setEnabled(enabled);
787:         }
788:
789:         /**
790:          * Applies the current enable state.
791:          *
792:          * @param controls the controls
793:          * @since 1.3
794:          */
795:         public final void applyEnable(Map<SWTGridCell, Control> controls) {
796:                 if (setEditable(getCustomControl().isEffectivelyEnabled())) {
797:                         for (final SWTGridCell gridCell : controls.keySet()) {
798:                                 setControlEnabled(gridCell, controls.get(gridCell), getCustomControl().isEffectivelyEnabled());
799:                         }
800:                 }
801:         }
802:
803:         /**
804:          * Allows custom controls to call specific code for setting controls editable or not. The result indicates whether
805:          * to call the default editable
806:          *
807:          * @param editable if the current state is editable
808:          * @return true if default editable modification should be executed
809:          * @since 1.3
810:          */
811:         protected boolean setEditable(boolean editable) {
812:                 return true;
813:         }
814:
815:         /**
816:          * Creates a simple grid.
817:          *
818:          * @param rows the number of rows
819:          * @param columns the number of columns
820:          * @return the {@link GridDescription}
821:          * @since 1.6
822:          */
823:         protected final SWTGridDescription createSimpleGrid(int rows, int columns) {
824:                 return GridDescriptionFactory.INSTANCE.createSimpleGrid(rows, columns, null);
825:         }
826:
827:         /**
828:          * <p>
829:          * Indicates if the given custom control takes the responsibility to call a possibly existing
830:          * {@link org.eclipse.emfforms.spi.swt.core.EMFFormsControlProcessorService EMFFormsControlProcessorService} itself.
831:          * </p>
832:          * <p>
833:          * The default implementation returns {@code false}.
834:          * </p>
835:          *
836:          * @return
837:          *                 {@code true} if the custom control can handle the
838:          * {@link org.eclipse.emfforms.spi.swt.core.EMFFormsControlProcessorService EMFFormsControlProcessorService}
839:          * itself, {@code false} otherwise.
840:          * @since 1.8
841:          */
842:         protected boolean canHandleControlProcessor() {
843:                 return false;
844:         }
845: }