Skip to content

Package: DefaultCreateNewModelElementStrategyProvider$DefaultStrategy

DefaultCreateNewModelElementStrategyProvider$DefaultStrategy

nameinstructionbranchcomplexitylinemethod
DefaultCreateNewModelElementStrategyProvider.DefaultStrategy(DefaultCreateNewModelElementStrategyProvider, EClassSelectionStrategy)
M: 0 C: 9
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
createNewModelElement(EObject, EReference)
M: 32 C: 57
64%
M: 2 C: 8
80%
M: 2 C: 4
67%
M: 7 C: 16
70%
M: 0 C: 1
100%
getModelElementInstanceFromList(Collection, Map)
M: 26 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 9 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2011-2018 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: * Christian W. Damus - bug 529138
14: ******************************************************************************/
15: package org.eclipse.emf.ecp.ui.view.swt.reference;
16:
17: import static org.osgi.service.component.annotations.ReferenceCardinality.MULTIPLE;
18: import static org.osgi.service.component.annotations.ReferencePolicy.DYNAMIC;
19:
20: import java.util.ArrayList;
21: import java.util.Collection;
22: import java.util.Collections;
23: import java.util.HashSet;
24: import java.util.LinkedHashMap;
25: import java.util.Map;
26:
27: import org.eclipse.emf.ecore.EClass;
28: import org.eclipse.emf.ecore.EObject;
29: import org.eclipse.emf.ecore.EPackage;
30: import org.eclipse.emf.ecore.EReference;
31: import org.eclipse.emf.ecore.impl.DynamicEObjectImpl;
32: import org.eclipse.emf.ecore.util.EcoreUtil;
33: import org.eclipse.emf.ecp.common.spi.ChildrenDescriptorCollector;
34: import org.eclipse.emf.ecp.common.spi.EMFUtils;
35: import org.eclipse.emf.ecp.spi.common.ui.CompositeFactory;
36: import org.eclipse.emf.ecp.spi.common.ui.SelectModelElementWizardFactory;
37: import org.eclipse.emf.ecp.spi.common.ui.composites.SelectionComposite;
38: import org.eclipse.emf.ecp.ui.view.swt.reference.CreateNewModelElementStrategy.Provider;
39: import org.eclipse.emf.edit.command.CommandParameter;
40: import org.eclipse.emfforms.bazaar.Bazaar;
41: import org.eclipse.emfforms.bazaar.Create;
42: import org.eclipse.emfforms.common.Optional;
43: import org.eclipse.emfforms.spi.bazaar.BazaarUtil;
44: import org.eclipse.emfforms.spi.common.report.AbstractReport;
45: import org.eclipse.emfforms.spi.common.report.ReportService;
46: import org.eclipse.jface.dialogs.MessageDialog;
47: import org.eclipse.jface.viewers.TreeViewer;
48: import org.eclipse.swt.widgets.Display;
49: import org.osgi.service.component.ComponentContext;
50: import org.osgi.service.component.annotations.Activate;
51: import org.osgi.service.component.annotations.Component;
52: import org.osgi.service.component.annotations.Deactivate;
53: import org.osgi.service.component.annotations.Reference;
54:
55: /**
56: * Default strategy that allows creating a new model element based on the sub classes of the reference type. If
57: * there is more than one, a selection dialog is shown.
58: * This implementation utilizes the {@link EClassSelectionStrategy} to filter the EClass to offer.
59: *
60: * @author Eugen Neufeld
61: * @since 1.17
62: *
63: */
64: @Component(name = "DefaultCreateNewModelElementStrategyProvider", property = "service.ranking:Integer=1", service = {
65:         Provider.class, DefaultCreateNewModelElementStrategyProvider.class })
66: public class DefaultCreateNewModelElementStrategyProvider
67:         extends ReferenceServiceCustomizationVendor<CreateNewModelElementStrategy> implements Provider {
68:
69:         private final Bazaar<EClassSelectionStrategy> eclassSelectionStrategyBazaar = BazaarUtil
70:                 .createBazaar(EClassSelectionStrategy.NULL);
71:         private ComponentContext context;
72:         private ReportService reportService;
73:
74:         /**
75:          * Add an {@code EClass} selection strategy provider.
76:          *
77:          * @param provider the provider to add
78:          */
79:         @Reference(cardinality = MULTIPLE, policy = DYNAMIC)
80:         public void addEClassSelectionStrategyProvider(EClassSelectionStrategy.Provider provider) {
81:                 eclassSelectionStrategyBazaar.addVendor(provider);
82:         }
83:
84:         /**
85:          * Remove an {@code EClass} selection strategy provider.
86:          *
87:          * @param provider the provider to remove
88:          */
89:         public void removeEClassSelectionStrategyProvider(EClassSelectionStrategy.Provider provider) {
90:                 eclassSelectionStrategyBazaar.removeVendor(provider);
91:         }
92:
93:         /**
94:          * The {@link ReportService} to use for errors.
95:          *
96:          * @param reportService The {@link ReportService}
97:          */
98:         @Reference
99:         void setReportService(ReportService reportService) {
100:                 this.reportService = reportService;
101:         }
102:
103:         /**
104:          * Activates me.
105:          *
106:          * @param context my component context
107:          */
108:         @Activate
109:         void activate(ComponentContext context) {
110:                 this.context = context;
111:         }
112:
113:         /**
114:          * Deactivates me.
115:          */
116:         @Deactivate
117:         void deactivate() {
118:                 context = null;
119:         }
120:
121:         @Override
122:         protected boolean handles(EObject owner, EReference reference) {
123:                 return true;
124:         }
125:
126:         /**
127:          * Creates the {@link CreateNewModelElementStrategy}.
128:          *
129:          * @return The created {@link CreateNewModelElementStrategy}
130:          */
131:         @Create
132:         public CreateNewModelElementStrategy createCreateNewModelElementStrategy() {
133:                 final EClassSelectionStrategy classSelectionStrategy = ReferenceStrategyUtil
134:                         .createDynamicEClassSelectionStrategy(eclassSelectionStrategyBazaar, context);
135:                 return new DefaultStrategy(classSelectionStrategy);
136:         }
137:
138:         /**
139:          * Obtain a mapping of new objects provided by an {@code owner}'s edit provider, by class.
140:          *
141:          * @param owner the owner of a reference in which to create an object
142:          * @param reference the reference in which to create an object
143:          *
144:          * @return a mapping of edit-provider supplied possible children
145:          */
146:         public Map<EClass, EObject> getNewObjectsByDescriptors(EObject owner, EReference reference) {
147:                 final Collection<CommandParameter> descriptors = getNewChildDescriptors(owner, reference);
148:                 if (descriptors.isEmpty()) {
149:                         return Collections.emptyMap();
150:                 }
151:
152:                 final Map<EClass, EObject> result = new LinkedHashMap<EClass, EObject>();
153:                 for (final CommandParameter next : descriptors) {
154:                         final EObject object = next.getEValue();
155:                         result.put(object.eClass(), object);
156:                 }
157:                 return result;
158:         }
159:
160:         /**
161:          * Obtain new child descriptors from the {@code owner}'s edit provider.
162:          *
163:          * @param owner the owner of a reference in which to create an object
164:          * @param reference the reference in which to create an object
165:          * @return the new child descriptors
166:          */
167:         private Collection<CommandParameter> getNewChildDescriptors(EObject owner, EReference reference) {
168:
169:                 // The item provider offers new child descriptors for probably multiple containment references.
170:                 // We want only those compatible with our reference
171:
172:                 final Collection<?> descriptors = new ChildrenDescriptorCollector().getDescriptors(owner);
173:
174:                 final EClass referenceType = reference.getEReferenceType();
175:                 final Collection<CommandParameter> result = new ArrayList<CommandParameter>(descriptors.size());
176:                 for (final Object next : descriptors) {
177:                         if (next instanceof CommandParameter) {
178:                                 final CommandParameter newChild = (CommandParameter) next;
179:                                 if (referenceType.isInstance(newChild.getEValue())) {
180:                                         result.add(newChild);
181:                                 }
182:                         }
183:                 }
184:
185:                 return result;
186:         }
187:
188:         //
189:         // Nested types
190:         //
191:
192:         /**
193:          * The default creation strategy implementation.
194:          */
195:         private class DefaultStrategy implements CreateNewModelElementStrategy {
196:                 private final EClassSelectionStrategy classSelectionStrategy;
197:
198:                 DefaultStrategy(final EClassSelectionStrategy classSelectionStrategy) {
199:                         super();
200:
201:                         this.classSelectionStrategy = classSelectionStrategy;
202:                 }
203:
204:                 @Override
205:                 public Optional<EObject> createNewModelElement(EObject owner, EReference reference) {
206:                         // Ask the edit provider for available children. If it provides none (which is
207:                         // usually the case for cross-reference features, not containments) then fall back
208:                         // to the release 1.16 behaviour of just finding all subclasses of the reference type
209:                         final Map<EClass, EObject> availableChildren = getNewObjectsByDescriptors(owner, reference);
210:•                        final Collection<EClass> availableClasses = availableChildren.isEmpty()
211:                                 ? EMFUtils.getSubClasses(reference.getEReferenceType())
212:                                 : availableChildren.keySet();
213:
214:                         final Collection<EClass> classes = classSelectionStrategy.collectEClasses(owner, reference,
215:                                 availableClasses);
216:•                        if (classes.isEmpty()) {
217:                                 final String errorMessage = String.format("No concrete classes for the type %1$s were found!", //$NON-NLS-1$
218:                                         reference.getEReferenceType().getName());
219:                                 MessageDialog.openError(Display.getDefault().getActiveShell(), "Error", //$NON-NLS-1$
220:                                         errorMessage);
221:                                 reportService.report(new AbstractReport(errorMessage));
222:                                 return Optional.empty();
223:                         }
224:•                        if (classes.size() == 1) {
225:                                 final EClass only = classes.iterator().next();
226:                                 EObject result = availableChildren.get(only);
227:                                 // if the eclass is not dynamic emf
228:•                                if (result == null) {
229:•                                        if (only.getInstanceClass() != null) {
230:                                                 // Create one in the release 1.16 way
231:                                                 result = EcoreUtil.create(only);
232:                                         } else {
233:                                                 result = new DynamicEObjectImpl(only);
234:                                         }
235:                                 }
236:                                 return Optional.of(result);
237:                         }
238:                         return Optional.ofNullable(getModelElementInstanceFromList(classes, availableChildren));
239:                 }
240:
241:                 /**
242:                  * Prompt the user to select one of the given {@code classes} to instantiate. If the
243:                  * available children includes an instance of the selected class, then use it, otherwise
244:                  * create a new unconfigured instance.
245:                  *
246:                  * @param classes the classes to chose from
247:                  * @param availableChildren available instances of some intersection of those {@code classes}
248:                  *
249:                  * @return an instance of the class selected by the user, or {@code null} if the user cancelled
250:                  * the prompt
251:                  */
252:                 private EObject getModelElementInstanceFromList(Collection<EClass> classes,
253:                         Map<EClass, EObject> availableChildren) {
254:
255:                         final SelectionComposite<TreeViewer> helper = CompositeFactory.getSelectModelClassComposite(
256:                                 new HashSet<EPackage>(),
257:                                 new HashSet<EPackage>(), classes);
258:
259:                         EObject result = SelectModelElementWizardFactory.openCreateNewModelElementDialog(helper);
260:•                        if (result != null) {
261:                                 final EObject fromAvailable = availableChildren.get(result.eClass());
262:•                                if (fromAvailable != null) {
263:                                         // Use the object provided by the edit provider, instead, as it may be
264:                                         // pre-configured in some important way
265:                                         result = fromAvailable;
266:                                 }
267:                         }
268:                         return result;
269:                 }
270:         }
271: }