Skip to content

Package: SettingToControlMapperImpl

SettingToControlMapperImpl

nameinstructionbranchcomplexitylinemethod
SettingToControlMapperImpl(EMFFormsMappingProviderManager, EMFFormsViewContext)
M: 0 C: 75
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 18
100%
M: 0 C: 1
100%
checkAndUpdateSettingToControlMapping(EObject)
M: 1 C: 14
93%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 1 C: 5
83%
M: 0 C: 1
100%
childContextAdded(EMFFormsViewContext, VElement, EMFFormsViewContext)
M: 0 C: 44
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 9
100%
M: 0 C: 1
100%
childContextRemoved(EMFFormsViewContext, VElement, EMFFormsViewContext)
M: 1 C: 52
98%
M: 1 C: 5
83%
M: 1 C: 3
75%
M: 1 C: 14
93%
M: 0 C: 1
100%
contextDisposed(EMFFormsViewContext)
M: 0 C: 36
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 11
100%
M: 0 C: 1
100%
deleteOldMapping(VControl)
M: 0 C: 66
100%
M: 0 C: 8
100%
M: 0 C: 5
100%
M: 0 C: 12
100%
M: 0 C: 1
100%
getControlsFor(EStructuralFeature.Setting)
M: 31 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
getControlsFor(UniqueSetting)
M: 0 C: 93
100%
M: 0 C: 16
100%
M: 0 C: 9
100%
M: 0 C: 22
100%
M: 0 C: 1
100%
getEObjectsWithSettings()
M: 0 C: 12
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getEObjectsWithSettings(VElement)
M: 0 C: 39
100%
M: 1 C: 5
83%
M: 1 C: 3
75%
M: 0 C: 7
100%
M: 0 C: 1
100%
getSettingsForControl(VControl)
M: 0 C: 16
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
handleAddForEObjectMapping(UniqueSetting)
M: 0 C: 25
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
handleRemoveForEObjectMapping(UniqueSetting)
M: 0 C: 21
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 5
100%
M: 0 C: 1
100%
hasControlsFor(EObject)
M: 0 C: 9
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
hasMapping(UniqueSetting, VElement)
M: 0 C: 16
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
resolveDMR(VControl, EMFFormsViewContext)
M: 0 C: 14
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
updateControlMapping(VControl)
M: 9 C: 111
93%
M: 3 C: 13
81%
M: 3 C: 6
67%
M: 2 C: 22
92%
M: 0 C: 1
100%
vControlAdded(VControl)
M: 1 C: 33
97%
M: 1 C: 3
75%
M: 1 C: 2
67%
M: 1 C: 9
90%
M: 0 C: 1
100%
vControlParentsRemoved(EMFFormsViewContext, VControl)
M: 1 C: 43
98%
M: 1 C: 5
83%
M: 1 C: 3
75%
M: 1 C: 9
90%
M: 0 C: 1
100%
vControlRemoved(VControl)
M: 0 C: 31
100%
M: 1 C: 3
75%
M: 1 C: 2
67%
M: 0 C: 7
100%
M: 0 C: 1
100%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2011-2019 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: * Lucas Koehler- initial API and implementation
13: * Christian W. Damus - bugs 533522, 527686
14: ******************************************************************************/
15: package org.eclipse.emfforms.internal.core.services.controlmapper;
16:
17: import java.util.AbstractSet;
18: import java.util.ArrayList;
19: import java.util.Collection;
20: import java.util.Collections;
21: import java.util.Iterator;
22: import java.util.LinkedHashMap;
23: import java.util.LinkedHashSet;
24: import java.util.List;
25: import java.util.Map;
26: import java.util.Set;
27:
28: import org.eclipse.emf.common.notify.Notifier;
29: import org.eclipse.emf.common.util.TreeIterator;
30: import org.eclipse.emf.ecore.EObject;
31: import org.eclipse.emf.ecore.EStructuralFeature.Setting;
32: import org.eclipse.emf.ecore.util.EcoreUtil;
33: import org.eclipse.emf.ecp.common.spi.UniqueSetting;
34: import org.eclipse.emf.ecp.view.spi.model.ModelChangeAddRemoveListener;
35: import org.eclipse.emf.ecp.view.spi.model.ModelChangeNotification;
36: import org.eclipse.emf.ecp.view.spi.model.VControl;
37: import org.eclipse.emf.ecp.view.spi.model.VDomainModelReference;
38: import org.eclipse.emf.ecp.view.spi.model.VDomainModelReferenceSegment;
39: import org.eclipse.emf.ecp.view.spi.model.VElement;
40: import org.eclipse.emfforms.spi.core.services.controlmapper.EMFFormsSettingToControlMapper;
41: import org.eclipse.emfforms.spi.core.services.controlmapper.SubControlMapper;
42: import org.eclipse.emfforms.spi.core.services.mappingprovider.EMFFormsMappingProviderManager;
43: import org.eclipse.emfforms.spi.core.services.view.EMFFormsContextTracker;
44: import org.eclipse.emfforms.spi.core.services.view.EMFFormsViewContext;
45:
46: /**
47: * Implementation of {@link EMFFormsSettingToControlMapper}.
48: *
49: * @author Lucas Koehler
50: *
51: */
52: public class SettingToControlMapperImpl
53:         implements EMFFormsSettingToControlMapper, SubControlMapper {
54:         /**
55:          * Used to get View model changes.
56:          *
57:          * @author Eugen Neufeld
58:          *
59:          */
60:         private final class ModelChangeAddRemoveListenerImplementation implements ModelChangeAddRemoveListener {
61:                 @Override
62:                 public void notifyChange(ModelChangeNotification notification) {
63:                 }
64:
65:                 @Override
66:                 public void notifyAdd(Notifier notifier) {
67:                         if (VDomainModelReference.class.isInstance(notifier)
68:                                 && !VDomainModelReference.class.isInstance(EObject.class.cast(notifier).eContainer())
69:                                 && !VDomainModelReferenceSegment.class.isInstance(EObject.class.cast(notifier).eContainer())) {
70:                                 final VDomainModelReference domainModelReference = VDomainModelReference.class.cast(notifier);
71:
72:                                 final VControl control = findControl(domainModelReference);
73:                                 if (control != null) {
74:                                         vControlAdded(control);
75:                                 }
76:                         }
77:                 }
78:
79:                 private VControl findControl(VDomainModelReference dmr) {
80:                         EObject parent = dmr.eContainer();
81:                         while (!VControl.class.isInstance(parent) && parent != null) {
82:                                 parent = parent.eContainer();
83:                         }
84:                         return (VControl) parent;
85:                 }
86:
87:                 @Override
88:                 public void notifyRemove(Notifier notifier) {
89:                         if (VControl.class.isInstance(notifier)) {
90:                                 vControlRemoved((VControl) notifier);
91:                         }
92:                 }
93:         }
94:
95:         private final EMFFormsViewContext viewModelContext;
96:         private final ViewModelListener dataModelListener;
97:
98:         private final Map<EObject, Set<UniqueSetting>> eObjectToMappedSettings = new LinkedHashMap<EObject, Set<UniqueSetting>>();
99:
100:         /**
101:          * A mapping between settings and controls.
102:          */
103:         private final Map<UniqueSetting, List<VElement>> settingToControlMap = new LinkedHashMap<UniqueSetting, List<VElement>>();
104:         private final Map<VElement, List<UniqueSetting>> controlToSettingMap = new LinkedHashMap<VElement, List<UniqueSetting>>();
105:         private final EMFFormsMappingProviderManager mappingManager;
106:         private final Map<VControl, EMFFormsViewContext> controlContextMap = new LinkedHashMap<VControl, EMFFormsViewContext>();
107:         private final Map<EMFFormsViewContext, VElement> contextParentMap = new LinkedHashMap<EMFFormsViewContext, VElement>();
108:         private final Map<EMFFormsViewContext, ViewModelListener> contextListenerMap = new LinkedHashMap<EMFFormsViewContext, ViewModelListener>();
109:         private final ModelChangeAddRemoveListenerImplementation viewModelChangeListener;
110:         private final EMFFormsContextTracker contextTracker;
111:         private boolean disposed;
112:
113:         /**
114:          * Creates a new instance of {@link SettingToControlMapperImpl}.
115:          *
116:          * @param mappingManager The {@link EMFFormsMappingProviderManager}
117:          * @param viewModelContext The {@link EMFFormsViewContext} that created this instance
118:          */
119:         public SettingToControlMapperImpl(EMFFormsMappingProviderManager mappingManager,
120:                 EMFFormsViewContext viewModelContext) {
121:                 this.mappingManager = mappingManager;
122:                 this.viewModelContext = viewModelContext;
123:
124:                 contextTracker = new EMFFormsContextTracker(viewModelContext);
125:                 contextTracker.onChildContextAdded(this::childContextAdded)
126:                         .onChildContextRemoved(this::childContextRemoved)
127:                         .onContextDisposed(this::contextDisposed)
128:                         .open();
129:
130:                 viewModelChangeListener = new ModelChangeAddRemoveListenerImplementation();
131:                 dataModelListener = new ViewModelListener(viewModelContext, this);
132:                 viewModelContext.registerViewChangeListener(viewModelChangeListener);
133:         }
134:
135:         /**
136:          * {@inheritDoc}
137:          */
138:         @Override
139:         public Set<VControl> getControlsFor(Setting setting) {
140:                 final Set<VControl> result = new LinkedHashSet<VControl>();
141:                 final Set<VElement> allElements = getControlsFor(UniqueSetting.createSetting(setting));
142:•                for (final VElement element : allElements) {
143:•                        if (VControl.class.isInstance(element)) {
144:                                 result.add((VControl) element);
145:                         }
146:                 }
147:                 return result;
148:         }
149:
150:         /**
151:          * {@inheritDoc}
152:          */
153:         @Override
154:         public Set<VElement> getControlsFor(UniqueSetting setting) {
155:                 final Set<VElement> elements = new LinkedHashSet<VElement>();
156:                 final List<VElement> currentControls = settingToControlMap.get(setting);
157:                 final Set<VControl> controls = new LinkedHashSet<VControl>();
158:                 final Set<VElement> validParents = new LinkedHashSet<VElement>();
159:•                if (currentControls != null) {
160:•                        for (final VElement control : currentControls) {
161:•                                if (!control.isEffectivelyEnabled() || !control.isEffectivelyVisible()
162:•                                        || control.isEffectivelyReadonly()) {
163:                                         continue;
164:                                 }
165:•                                if (VControl.class.isInstance(control)) {
166:                                         controls.add((VControl) control);
167:•                                        if (controlContextMap.containsKey(control)) {
168:                                                 final VElement parent = contextParentMap.get(controlContextMap.get(control));
169:                                                 validParents.add(parent);
170:                                         }
171:                                 } else {
172:                                         elements.add(control);
173:                                 }
174:                         }
175:                 }
176:•                if (controls.isEmpty()) {
177:                         return Collections.emptySet();
178:                 }
179:                 final Set<VElement> result = new LinkedHashSet<VElement>(controls);
180:                 elements.retainAll(validParents);
181:                 result.addAll(elements);
182:                 return result;
183:         }
184:
185:         /**
186:          * {@inheritDoc}
187:          */
188:         @Override
189:         public synchronized void updateControlMapping(VControl vControl) {
190:•                if (vControl == null) {
191:                         return;
192:                 }
193:                 // delete old mapping
194:                 deleteOldMapping(vControl);
195:                 // update mapping
196:                 final EMFFormsViewContext controlContext = controlContextMap.get(vControl);
197:                 final Set<UniqueSetting> map = mappingManager.getAllSettingsFor(vControl.getDomainModelReference(),
198:•                        controlContext == null ? viewModelContext.getDomainModel() : controlContext.getDomainModel());
199:•                if (!controlToSettingMap.containsKey(vControl)) {
200:                         // We never add duplicate settings so don't need the overhead of a set (implemented by a map)
201:                         controlToSettingMap.put(vControl, new ArrayList<UniqueSetting>(map));
202:                 } else {
203:                         controlToSettingMap.get(vControl).addAll(map);
204:                 }
205:•                for (final UniqueSetting setting : map) {
206:•                        if (!settingToControlMap.containsKey(setting)) {
207:                                 // There is almost always exactly one control
208:                                 settingToControlMap.put(setting, new ArrayList<VElement>(1));
209:                                 handleAddForEObjectMapping(setting);
210:                         }
211:                         settingToControlMap.get(setting).add(vControl);
212:•                        if (controlContext != null) {
213:                                 VElement parentElement = contextParentMap.get(controlContext);
214:•                                while (parentElement != null) {
215:                                         settingToControlMap.get(setting).add(parentElement);
216:                                         final EMFFormsViewContext context = controlContextMap.get(parentElement);
217:•                                        if (context == null) {
218:                                                 break;
219:                                         }
220:                                         parentElement = contextParentMap.get(context);
221:                                 }
222:                         }
223:                 }
224:         }
225:
226:         private void deleteOldMapping(VControl vControl) {
227:•                if (controlToSettingMap.containsKey(vControl)) {
228:                         final Set<UniqueSetting> keysWithEmptySets = new LinkedHashSet<UniqueSetting>();
229:•                        for (final UniqueSetting setting : controlToSettingMap.get(vControl)) {
230:                                 final List<VElement> controlSet = settingToControlMap.get(setting);
231:                                 controlSet.remove(vControl); // We never repeat controls in this list
232:•                                if (controlSet.isEmpty()) {
233:                                         keysWithEmptySets.add(setting);
234:                                 }
235:                         }
236:•                        for (final UniqueSetting setting : keysWithEmptySets) {
237:                                 settingToControlMap.remove(setting);
238:                                 handleRemoveForEObjectMapping(setting);
239:                         }
240:                         controlToSettingMap.remove(vControl);
241:                 }
242:         }
243:
244:         private void handleAddForEObjectMapping(UniqueSetting setting) {
245:•                if (!eObjectToMappedSettings.containsKey(setting.getEObject())) {
246:                         eObjectToMappedSettings.put(setting.getEObject(), new LinkedHashSet<UniqueSetting>());
247:                 }
248:                 eObjectToMappedSettings.get(setting.getEObject()).add(setting);
249:         }
250:
251:         private void handleRemoveForEObjectMapping(UniqueSetting setting) {
252:                 final Set<UniqueSetting> settings = eObjectToMappedSettings.get(setting.getEObject());
253:                 settings.remove(setting);
254:•                if (settings.isEmpty()) {
255:                         eObjectToMappedSettings.remove(setting.getEObject());
256:                 }
257:         }
258:
259:         /**
260:          * {@inheritDoc}
261:          */
262:         @Override
263:         public void vControlRemoved(VControl vControl) {
264:                 deleteOldMapping(vControl);
265:
266:                 final EMFFormsViewContext viewContext = controlContextMap.get(vControl);
267:•                if (viewContext != null && contextListenerMap.containsKey(viewContext)) {
268:                         contextListenerMap.get(viewContext).removeVControl(vControl);
269:                 } else {
270:                         dataModelListener.removeVControl(vControl);
271:                 }
272:         }
273:
274:         /**
275:          * {@inheritDoc}
276:          */
277:         @Override
278:         public void vControlAdded(VControl vControl) {
279:•                if (vControl.getDomainModelReference() == null) {
280:                         return;
281:                 }
282:
283:                 final EMFFormsViewContext viewContext = controlContextMap.get(vControl);
284:                 resolveDMR(vControl, viewContext);
285:
286:                 checkAndUpdateSettingToControlMapping(vControl);
287:•                if (viewContext != null) {
288:                         contextListenerMap.get(viewContext).addVControl(vControl);
289:                 } else {
290:                         dataModelListener.addVControl(vControl);
291:                 }
292:         }
293:
294:         private void resolveDMR(VControl vControl, EMFFormsViewContext childContext) {
295:                 /* if child context is null use root context */
296:•                final EMFFormsViewContext viewContext = childContext != null ? childContext : viewModelContext;
297:                 // FIXME remove
298:                 SettingToControlExpandHelper.resolveDomainReferences(
299:                         vControl.getDomainModelReference(),
300:                         viewContext.getDomainModel(),
301:                         viewContext);
302:         }
303:
304:         /**
305:          * {@inheritDoc}
306:          */
307:         @Override
308:         public void checkAndUpdateSettingToControlMapping(EObject eObject) {
309:•                if (VControl.class.isInstance(eObject)) {
310:                         final VControl vControl = (VControl) eObject;
311:•                        if (vControl.getDomainModelReference() == null) {
312:                                 return;
313:                         }
314:
315:                         updateControlMapping(vControl);
316:                 }
317:         }
318:
319:         private void childContextAdded(EMFFormsViewContext parentContext, VElement parentElement,
320:                 EMFFormsViewContext childContext) {
321:
322:                 contextParentMap.put(childContext, parentElement);
323:                 final TreeIterator<EObject> eAllContents = childContext.getViewModel().eAllContents();
324:•                while (eAllContents.hasNext()) {
325:                         final EObject next = eAllContents.next();
326:•                        if (VControl.class.isInstance(next)) {
327:                                 controlContextMap.put((VControl) next, childContext);
328:                         }
329:                 }
330:                 contextListenerMap.put(childContext, new ViewModelListener(childContext, this));
331:                 childContext.registerViewChangeListener(viewModelChangeListener);
332:         }
333:
334:         private void childContextRemoved(EMFFormsViewContext parentContext, VElement parentElement,
335:                 EMFFormsViewContext childContext) {
336:
337:•                if (disposed) {
338:                         return;
339:                 }
340:
341:                 final TreeIterator<EObject> eAllContents = childContext.getViewModel().eAllContents();
342:•                while (eAllContents.hasNext()) {
343:                         final EObject next = eAllContents.next();
344:•                        if (VControl.class.isInstance(next)) {
345:                                 final VControl controlToRemove = (VControl) next;
346:                                 vControlParentsRemoved(childContext, controlToRemove);
347:                                 vControlRemoved(controlToRemove);
348:                                 controlContextMap.remove(controlToRemove);
349:                         }
350:                 }
351:
352:                 childContext.unregisterViewChangeListener(viewModelChangeListener);
353:                 final ViewModelListener listener = contextListenerMap.remove(childContext);
354:                 listener.dispose();
355:                 contextParentMap.remove(childContext);
356:         }
357:
358:         /**
359:          * Get all settings associated with the given control to remove.
360:          * For every setting, remove its mapping to any parent element of the given child context.
361:          * This is necessary when the child context is removed from this setting to control mapper in order to avoid
362:          * mappings to deleted settings after a child context was removed.
363:          *
364:          * @param childContext The child {@link EMFFormsViewContext} that will be removed from this setting to control
365:          * mapper
366:          * @param controlToRemove The {@link VControl} that will be removed from this setting to control mapper
367:          */
368:         private void vControlParentsRemoved(EMFFormsViewContext childContext, VControl controlToRemove) {
369:•                if (childContext == null) {
370:                         return;
371:                 }
372:                 final VElement parentElement = contextParentMap.get(childContext);
373:•                if (parentElement == null) {
374:                         return;
375:                 }
376:                 // remove the mapping of each setting of the removed control to the parent element
377:•                for (final UniqueSetting setting : getSettingsForControl(controlToRemove)) {
378:                         settingToControlMap.get(setting).remove(parentElement);
379:                 }
380:                 // Then compute the parent of the parent element
381:                 final EMFFormsViewContext parentContext = controlContextMap.get(parentElement);
382:                 vControlParentsRemoved(parentContext, controlToRemove);
383:         }
384:
385:         private void contextDisposed(EMFFormsViewContext context) {
386:•                if (contextTracker.isRoot(context)) {
387:                         context.unregisterViewChangeListener(viewModelChangeListener);
388:                         dataModelListener.dispose();
389:                         settingToControlMap.clear();
390:                         controlContextMap.clear();
391:                         contextParentMap.clear();
392:                         contextListenerMap.values().forEach(ViewModelListener::dispose);
393:                         contextListenerMap.clear();
394:                         contextTracker.close();
395:                         disposed = true;
396:                 }
397:         }
398:
399:         @Override
400:         public boolean hasControlsFor(EObject eObject) {
401:•                if (eObjectToMappedSettings.containsKey(eObject)) {
402:                         return true;
403:                 }
404:
405:                 return false;
406:         }
407:
408:         @Override
409:         public Collection<EObject> getEObjectsWithSettings() {
410:                 final Set<EObject> result = new LinkedHashSet<EObject>();
411:                 result.addAll(eObjectToMappedSettings.keySet());
412:                 return result;
413:         }
414:
415:         @Override
416:         public Collection<EObject> getEObjectsWithSettings(VElement element) {
417:                 final Set<EObject> result = new LinkedHashSet<>();
418:
419:•                for (final Iterator<EObject> iter = EcoreUtil.getAllContents(Collections.singleton(element)); iter.hasNext();) {
420:                         final EObject next = iter.next();
421:                         final List<UniqueSetting> settings = controlToSettingMap.get(next);
422:•                        if (settings != null && !settings.isEmpty()) {
423:                                 settings.stream().map(UniqueSetting::getEObject).forEach(result::add);
424:                         }
425:                 }
426:
427:                 return result;
428:         }
429:
430:         @Override
431:         public Set<UniqueSetting> getSettingsForControl(VControl control) {
432:                 final List<UniqueSetting> settings = controlToSettingMap.get(control);
433:•                if (settings == null) {
434:                         return Collections.emptySet();
435:                 }
436:                 return new SetView<UniqueSetting>(settings);
437:         }
438:
439:         @Override
440:         public boolean hasMapping(UniqueSetting setting, VElement control) {
441:                 final Collection<VElement> elements = settingToControlMap.get(setting);
442:•                return elements != null && elements.contains(control);
443:         }
444:
445:         /**
446:          * A view of any collection as an unmodifiable set.
447:          *
448:          * @param <E> the element type of the collection
449:          */
450:         final class SetView<E> extends AbstractSet<E> {
451:                 private final Collection<? extends E> content;
452:
453:                 /**
454:                  * Initializes me with my {@code content}.
455:                  *
456:                  * @param content the elements that I contain
457:                  */
458:                 SetView(Collection<? extends E> content) {
459:                         super();
460:
461:                         this.content = content;
462:                 }
463:
464:                 @Override
465:                 public Iterator<E> iterator() {
466:                         final Iterator<? extends E> delegate = content.iterator();
467:                         return new Iterator<E>() {
468:                                 @Override
469:                                 public boolean hasNext() {
470:                                         return delegate.hasNext();
471:                                 }
472:
473:                                 @Override
474:                                 public E next() {
475:                                         return delegate.next();
476:                                 }
477:
478:                                 @Override
479:                                 public void remove() {
480:                                         throw new UnsupportedOperationException();
481:                                 }
482:                         };
483:                 }
484:
485:                 @Override
486:                 public int size() {
487:                         return content.size();
488:                 }
489:         }
490: }