Skip to content

Package: TreeMasterDetailValidationInitiator$TreeMasterDetailValidationInitiatorDomainChangeListener

TreeMasterDetailValidationInitiator$TreeMasterDetailValidationInitiatorDomainChangeListener

nameinstructionbranchcomplexitylinemethod
TreeMasterDetailValidationInitiator.TreeMasterDetailValidationInitiatorDomainChangeListener(TreeMasterDetailValidationInitiator, ViewModelContext)
M: 0 C: 9
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
cleanupRemovedValues(Object, TreeMasterDetailValidationInitiator.TreeContextMapping)
M: 19 C: 48
72%
M: 6 C: 6
50%
M: 4 C: 3
43%
M: 3 C: 12
80%
M: 0 C: 1
100%
getExistingOrNewChildContext(TreeMasterDetailValidationInitiator.TreeContextMapping, Object)
M: 0 C: 31
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 7
100%
M: 0 C: 1
100%
isChildObjectRemoved(Set, Set, int)
M: 0 C: 14
100%
M: 2 C: 4
67%
M: 2 C: 2
50%
M: 0 C: 2
100%
M: 0 C: 1
100%
notifyChange(ModelChangeNotification)
M: 0 C: 119
100%
M: 0 C: 14
100%
M: 0 C: 8
100%
M: 0 C: 21
100%
M: 0 C: 1
100%

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 Neufeld - initial API and implementation
13: ******************************************************************************/
14: package org.eclipse.emf.ecp.view.treemasterdetail.internal.validation;
15:
16: import java.util.Collection;
17: import java.util.HashSet;
18: import java.util.LinkedHashMap;
19: import java.util.LinkedHashSet;
20: import java.util.Map;
21: import java.util.Set;
22:
23: import org.eclipse.emf.common.notify.AdapterFactory;
24: import org.eclipse.emf.common.notify.Notification;
25: import org.eclipse.emf.common.util.TreeIterator;
26: import org.eclipse.emf.ecore.EObject;
27: import org.eclipse.emf.ecp.view.model.common.edit.provider.CustomReflectiveItemProviderAdapterFactory;
28: import org.eclipse.emf.ecp.view.spi.context.GlobalViewModelService;
29: import org.eclipse.emf.ecp.view.spi.context.ViewModelContext;
30: import org.eclipse.emf.ecp.view.spi.model.ModelChangeListener;
31: import org.eclipse.emf.ecp.view.spi.model.ModelChangeNotification;
32: import org.eclipse.emf.ecp.view.spi.model.VElement;
33: import org.eclipse.emf.ecp.view.spi.model.VView;
34: import org.eclipse.emf.ecp.view.spi.model.VViewModelProperties;
35: import org.eclipse.emf.ecp.view.spi.model.util.ViewModelPropertiesHelper;
36: import org.eclipse.emf.ecp.view.spi.provider.ViewProviderHelper;
37: import org.eclipse.emf.ecp.view.treemasterdetail.model.VTreeMasterDetail;
38: import org.eclipse.emf.ecp.view.treemasterdetail.ui.swt.internal.RootObject;
39: import org.eclipse.emf.ecp.view.treemasterdetail.ui.swt.internal.TreeMasterDetailSelectionManipulatorHelper;
40: import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
41: import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider;
42: import org.eclipse.emfforms.spi.core.services.view.EMFFormsContextListener;
43: import org.eclipse.emfforms.spi.core.services.view.EMFFormsViewContext;
44:
45: /**
46: * The TreeMasterDatailValidationInitiator searches for {@link VTreeMasterDetail} VElements and registers the necessary
47: * ViewModelContexts.
48: *
49: * @author Eugen Neufeld
50: *
51: */
52: @SuppressWarnings("restriction")
53: public class TreeMasterDetailValidationInitiator implements
54:         GlobalViewModelService, EMFFormsContextListener {
55:
56:         /**
57:          * @author Eugen Neufeld
58:          * @author Johannes Faltermeier
59:          *
60:          */
61:         private final class TreeMasterDetailValidationInitiatorDomainChangeListener implements ModelChangeListener {
62:                 private final ViewModelContext context;
63:
64:                 /**
65:                  * @param context
66:                  */
67:                 private TreeMasterDetailValidationInitiatorDomainChangeListener(ViewModelContext context) {
68:                         this.context = context;
69:                 }
70:
71:                 @Override
72:                 public void notifyChange(ModelChangeNotification notification) {
73:•                        if (notification.getRawNotification().isTouch() || mapping.isEmpty()) {
74:                                 return;
75:                         }
76:•                        for (final TreeContextMapping treeContextEntry : new LinkedHashSet<TreeContextMapping>(mapping.keySet())) {
77:•                                if (!mapping.get(treeContextEntry).contains(notification.getNotifier())) {
78:                                         return;
79:                                 }
80:                                 final Set<Object> children = getAllChildren(notification.getNotifier(), adapterFactoryContentProvider);
81:                                 final Set<Object> childrenTreeContextEntry = new HashSet<Object>(mapping.get(treeContextEntry));
82:
83:•                                if (childrenTreeContextEntry.containsAll(children)) {
84:                                         if (isChildObjectRemoved(children, childrenTreeContextEntry,
85:•                                                notification.getRawNotification().getEventType())) {
86:
87:                                                 // Calculate the removed child objects by calculating the diff between the objects referenced in
88:                                                 // the mapping and the notifier and its actual children.
89:                                                 childrenTreeContextEntry.removeAll(children);
90:                                                 childrenTreeContextEntry.remove(notification.getNotifier());
91:
92:                                                 // For every removed child object, remove this listener and the TMD Validation Initiator as
93:                                                 // context users from the child object's context. This allows that the child context is disposed
94:                                                 // once its other listeners are removed, too.
95:                                                 final Object oldValue = notification.getRawNotification().getOldValue();
96:                                                 cleanupRemovedValues(oldValue, treeContextEntry);
97:                                         }
98:                                         return;
99:                                 }
100:
101:                                 // Register this listener to every child context of any newly added child object.
102:                                 children.removeAll(childrenTreeContextEntry);
103:•                                for (final Object child : children) {
104:                                         mapping.get(treeContextEntry).add(child);
105:                                         final ViewModelContext childContext = getExistingOrNewChildContext(treeContextEntry, child);
106:                                         childContext.addContextUser(this);
107:                                 }
108:                         }
109:                 }
110:
111:                 /**
112:                  * Cleans up the removed values.
113:                  * For every removed child object, remove this listener and the TMD Validation Initiator as
114:                  * context users from the child object's context. This allows that the child context is disposed
115:                  * once its other listeners are removed, too.
116:                  *
117:                  * @param removedValueObject the removed value object.
118:                  * @param treeContextEntry the {@link TreeContextMapping} to retrieve the view model context to remove the
119:                  * context users from.
120:                  */
121:                 private void cleanupRemovedValues(Object removedValueObject, TreeContextMapping treeContextEntry) {
122:•                        if (removedValueObject != null) {
123:                                 final Set<Object> removedChildren = new HashSet<Object>();
124:•                                if (removedValueObject instanceof Collection) {
125:•                                        for (final Object removedListObject : (Collection<?>) removedValueObject) {
126:•                                                if (removedListObject instanceof EObject) {
127:                                                         removedChildren.add(removedListObject);
128:                                                 }
129:                                         }
130:•                                } else if (removedValueObject instanceof EObject) {
131:                                         removedChildren.add(removedValueObject);
132:                                 }
133:•                                for (final Object removedChild : removedChildren) {
134:                                         final ViewModelContext childContext = getExistingOrNewChildContext(treeContextEntry,
135:                                                 removedChild);
136:                                         childContext.removeContextUser(this);
137:                                         childContext.removeContextUser(TreeMasterDetailValidationInitiator.this);
138:                                         mapping.get(treeContextEntry).remove(removedChild);
139:                                 }
140:                         }
141:                 }
142:
143:                 /**
144:                  * Checks whether a child object has been removed by looking at the notification type and comparing the actual
145:                  * children object to the children object known to the TreeMasterDetailValidationInitiator.
146:                  *
147:                  * @param children The actual children objects of the notifier
148:                  * @param childrenFromTreeContextEntry The children objects of the notifier known to the
149:                  * TreeMasterDetailValidationInitiator
150:                  * @param notificationType The type of notification
151:                  * @return Whether a child object of the notifier was removed
152:                  */
153:                 private boolean isChildObjectRemoved(Set<Object> children, Set<Object> childrenFromTreeContextEntry,
154:                         int notificationType) {
155:•                        return (Notification.REMOVE == notificationType || Notification.REMOVE_MANY == notificationType)
156:•                                && !children.containsAll(childrenFromTreeContextEntry);
157:                 }
158:
159:                 private ViewModelContext getExistingOrNewChildContext(TreeContextMapping treeContextEntry, Object childObject) {
160:                         final VElement viewModel = context.getViewModel();
161:                         final VViewModelProperties properties = ViewModelPropertiesHelper
162:                                 .getInhertitedPropertiesOrEmpty(viewModel);
163:                         properties.addNonInheritableProperty(DETAIL_KEY, true);
164:                         final EObject eObject = (EObject) manipulateSelection(childObject);
165:
166:                         return treeContextEntry.context.getChildContext(eObject,
167:                                 treeContextEntry.control, ViewProviderHelper.getView(eObject, properties));
168:                 }
169:         }
170:
171:         /**
172:          * A Mapping for TreeMasterDetails.
173:          *
174:          * @author Eugen Neufeld
175:          *
176:          */
177:         private static class TreeContextMapping {
178:                 private VTreeMasterDetail control;
179:                 private ViewModelContext context;
180:
181:                 /**
182:                  * {@inheritDoc}
183:                  *
184:                  * @see java.lang.Object#hashCode()
185:                  */
186:                 @Override
187:                 public int hashCode() {
188:                         final int prime = 31;
189:                         int result = 1;
190:                         result = prime * result + (context == null ? 0 : context.hashCode());
191:                         result = prime * result + (control == null ? 0 : control.hashCode());
192:                         return result;
193:                 }
194:
195:                 /**
196:                  * {@inheritDoc}
197:                  *
198:                  * @see java.lang.Object#equals(java.lang.Object)
199:                  */
200:                 @Override
201:                 public boolean equals(Object obj) {
202:                         if (this == obj) {
203:                                 return true;
204:                         }
205:                         if (obj == null) {
206:                                 return false;
207:                         }
208:                         if (getClass() != obj.getClass()) {
209:                                 return false;
210:                         }
211:                         final TreeContextMapping other = (TreeContextMapping) obj;
212:                         if (context == null) {
213:                                 if (other.context != null) {
214:                                         return false;
215:                                 }
216:                         } else if (!context.equals(other.context)) {
217:                                 return false;
218:                         }
219:                         if (control == null) {
220:                                 if (other.control != null) {
221:                                         return false;
222:                                 }
223:                         } else if (!control.equals(other.control)) {
224:                                 return false;
225:                         }
226:                         return true;
227:                 }
228:
229:         }
230:
231:         private final Map<TreeContextMapping, Set<Object>> mapping = new LinkedHashMap<TreeContextMapping, Set<Object>>();
232:         /**
233:          * The detail key passed to the view model context.
234:          */
235:         public static final String DETAIL_KEY = "detail"; //$NON-NLS-1$
236:
237:         /**
238:          * Context key for the root.
239:          */
240:         public static final String ROOT_KEY = "root"; //$NON-NLS-1$
241:
242:         private ComposedAdapterFactory adapterFactory;
243:
244:         private AdapterFactoryContentProvider adapterFactoryContentProvider;
245:         private ViewModelContext context;
246:
247:         /**
248:          * Constructor of the Initiator.
249:          */
250:         public TreeMasterDetailValidationInitiator() {
251:                 adapterFactory = new ComposedAdapterFactory(new AdapterFactory[] {
252:                         new CustomReflectiveItemProviderAdapterFactory(),
253:                         new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE) });
254:
255:                 adapterFactoryContentProvider = new AdapterFactoryContentProvider(
256:                         adapterFactory) {
257:                         @Override
258:                         public Object[] getElements(Object object) {
259:                                 return new Object[] { ((RootObject) object).getRoot() };
260:                         }
261:                 };
262:
263:         }
264:
265:         @Override
266:         public void instantiate(final ViewModelContext context) {
267:                 this.context = context;
268:                 context.registerDomainChangeListener(new TreeMasterDetailValidationInitiatorDomainChangeListener(context));
269:                 checkForTreeMasterDetail(context);
270:                 context.registerEMFFormsContextListener(this);
271:         }
272:
273:         private void checkForTreeMasterDetail(ViewModelContext context) {
274:                 final EObject viewRoot = context.getViewModel();
275:                 final TreeIterator<EObject> eAllContents = viewRoot.eAllContents();
276:                 while (eAllContents.hasNext()) {
277:                         final EObject eObject = eAllContents.next();
278:                         if (VTreeMasterDetail.class.isInstance(eObject)) {
279:                                 final VTreeMasterDetail treeMasterDetail = VTreeMasterDetail.class.cast(eObject);
280:                                 registerRootChildContext(treeMasterDetail, context);
281:                                 registerChildrenChildContext(treeMasterDetail, context, adapterFactoryContentProvider);
282:                         }
283:                 }
284:         }
285:
286:         private void registerChildrenChildContext(VTreeMasterDetail treeMasterDetail, ViewModelContext viewModelContext,
287:                 final AdapterFactoryContentProvider adapterFactoryContentProvider) {
288:                 final Set<Object> children = getAllChildren(viewModelContext.getDomainModel(),
289:                         adapterFactoryContentProvider);
290:
291:                 for (final Object object : children) {
292:                         final VElement viewModel = viewModelContext.getViewModel();
293:                         final VViewModelProperties properties = ViewModelPropertiesHelper.getInhertitedPropertiesOrEmpty(viewModel);
294:                         properties.addNonInheritableProperty(DETAIL_KEY, true);
295:                         final TreeContextMapping entry = new TreeContextMapping();
296:                         entry.context = viewModelContext;
297:                         entry.control = treeMasterDetail;
298:                         if (!mapping.containsKey(entry)) {
299:                                 mapping.put(entry, new LinkedHashSet<Object>());
300:                         }
301:                         mapping.get(entry).add(object);
302:
303:                         final EObject manipulateSelection = (EObject) manipulateSelection(object);
304:                         final VView view = ViewProviderHelper.getView(manipulateSelection, properties);
305:
306:                         final ViewModelContext childContext = viewModelContext.getChildContext(manipulateSelection,
307:                                 treeMasterDetail, view);
308:                         childContext.addContextUser(this);
309:                 }
310:         }
311:
312:         private void registerRootChildContext(VTreeMasterDetail treeMasterDetail, ViewModelContext viewModelContext) {
313:                 final VElement viewModel = viewModelContext.getViewModel();
314:                 final VViewModelProperties properties = ViewModelPropertiesHelper.getInhertitedPropertiesOrEmpty(viewModel);
315:                 properties.addNonInheritableProperty(DETAIL_KEY, true);
316:                 properties.addNonInheritableProperty(ROOT_KEY, true);
317:                 final TreeContextMapping entry = new TreeContextMapping();
318:                 entry.context = viewModelContext;
319:                 entry.control = treeMasterDetail;
320:                 if (!mapping.containsKey(entry)) {
321:                         mapping.put(entry, new LinkedHashSet<Object>());
322:                 }
323:                 mapping.get(entry).add(viewModelContext.getDomainModel());
324:
325:                 final Object manipulateSelection = manipulateSelection(viewModelContext.getDomainModel());
326:                 VView view = treeMasterDetail.getDetailView();
327:                 if (view == null || view.getChildren().isEmpty()) {
328:                         view = ViewProviderHelper.getView((EObject) manipulateSelection, properties);
329:                 }
330:                 final ViewModelContext childContext = viewModelContext.getChildContext((EObject) manipulateSelection,
331:                         treeMasterDetail, view);
332:                 childContext.addContextUser(this);
333:         }
334:
335:         private Set<Object> getAllChildren(Object parent, AdapterFactoryContentProvider adapterFactoryContentProvider) {
336:                 final Set<Object> allChildren = new LinkedHashSet<Object>();
337:                 final Object[] children = adapterFactoryContentProvider.getChildren(parent);
338:                 for (final Object object : children) {
339:                         // final Object manipulatedSelection = manipulateSelection(object);
340:                         if (!EObject.class.isInstance(object)) {
341:                                 continue;
342:                         }
343:                         allChildren.add(object);
344:                         allChildren.addAll(getAllChildren(object, adapterFactoryContentProvider));
345:                 }
346:                 return allChildren;
347:         }
348:
349:         private Object manipulateSelection(Object object) {
350:                 return TreeMasterDetailSelectionManipulatorHelper.manipulateSelection(object);
351:         }
352:
353:         @Override
354:         public void dispose() {
355:                 context.unregisterEMFFormsContextListener(this);
356:                 adapterFactoryContentProvider.dispose();
357:                 adapterFactory.dispose();
358:         }
359:
360:         @Override
361:         public int getPriority() {
362:                 return 2;
363:         }
364:
365:         /**
366:          * {@inheritDoc}
367:          *
368:          * @see org.eclipse.emf.ecp.view.spi.context.GlobalViewModelService#childViewModelContextAdded(org.eclipse.emf.ecp.view.spi.context.ViewModelContext)
369:          */
370:         @Override
371:         public void childViewModelContextAdded(ViewModelContext childContext) {
372:                 checkForTreeMasterDetail(childContext);
373:         }
374:
375:         /**
376:          * {@inheritDoc}
377:          *
378:          * @see org.eclipse.emfforms.spi.core.services.view.EMFFormsContextListener#childContextAdded(org.eclipse.emf.ecp.view.spi.model.VElement,
379:          * org.eclipse.emfforms.spi.core.services.view.EMFFormsViewContext)
380:          */
381:         @Override
382:         public void childContextAdded(VElement parentElement, EMFFormsViewContext childContext) {
383:                 if (ViewModelContext.class.isInstance(childContext)) {
384:                         checkForTreeMasterDetail(ViewModelContext.class.cast(childContext));
385:                 }
386:         }
387:
388:         /**
389:          * {@inheritDoc}
390:          *
391:          * @see org.eclipse.emfforms.spi.core.services.view.EMFFormsContextListener#childContextDisposed(org.eclipse.emfforms.spi.core.services.view.EMFFormsViewContext)
392:          */
393:         @Override
394:         public void childContextDisposed(EMFFormsViewContext childContext) {
395:                 // intentionally left empty
396:         }
397:
398:         /**
399:          * {@inheritDoc}
400:          *
401:          * @see org.eclipse.emfforms.spi.core.services.view.EMFFormsContextListener#contextInitialised()
402:          */
403:         @Override
404:         public void contextInitialised() {
405:                 // intentionally left empty
406:         }
407:
408:         /**
409:          * {@inheritDoc}
410:          *
411:          * @see org.eclipse.emfforms.spi.core.services.view.EMFFormsContextListener#contextDispose()
412:          */
413:         @Override
414:         public void contextDispose() {
415:                 // intentionally left empty
416:         }
417:
418: }