1 | package de.uka.ipd.sdq.featureinstance; |
2 | |
3 | import java.io.IOException; |
4 | import java.io.InputStream; |
5 | import java.util.HashMap; |
6 | import java.util.Iterator; |
7 | |
8 | import org.eclipse.emf.common.command.BasicCommandStack; |
9 | import org.eclipse.emf.common.util.EList; |
10 | import org.eclipse.emf.ecore.EObject; |
11 | import org.eclipse.emf.ecore.resource.Resource; |
12 | import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain; |
13 | import org.eclipse.emf.edit.provider.ComposedAdapterFactory; |
14 | import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory; |
15 | import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory; |
16 | import org.eclipse.jface.viewers.CheckboxTreeViewer; |
17 | |
18 | import de.uka.ipd.sdq.featureconfig.ConfigNode; |
19 | import de.uka.ipd.sdq.featureconfig.ConfigState; |
20 | import de.uka.ipd.sdq.featureconfig.Configuration; |
21 | import de.uka.ipd.sdq.featureconfig.FeatureConfig; |
22 | import de.uka.ipd.sdq.featureconfig.impl.featureconfigFactoryImpl; |
23 | import de.uka.ipd.sdq.featureconfig.provider.featureconfigItemProviderAdapterFactory; |
24 | import de.uka.ipd.sdq.featuremodel.ChildRelation; |
25 | import de.uka.ipd.sdq.featuremodel.Feature; |
26 | import de.uka.ipd.sdq.featuremodel.FeatureDiagram; |
27 | import de.uka.ipd.sdq.featuremodel.FeatureGroup; |
28 | import de.uka.ipd.sdq.featuremodel.Simple; |
29 | import de.uka.ipd.sdq.featuremodel.provider.featuremodelItemProviderAdapterFactory; |
30 | import de.uka.ipd.sdq.identifier.provider.IdentifierItemProviderAdapterFactory; |
31 | |
32 | public class FeatureConfigFunctionality { |
33 | |
34 | /** |
35 | * Checks if the Configuration object can be accessed in the loaded resource |
36 | * and returns it if possible |
37 | * |
38 | * @param resource |
39 | * The resource from which the Configuration-object can be |
40 | * accessed (a *.featureconfig-file) |
41 | * @return Returns a Configuration-object or null, if it can be accessed |
42 | * (e.g. no *.featureconfig-file) |
43 | */ |
44 | public Configuration getConfiguration(Resource resource) { |
45 | EList<EObject> tempList = resource.getContents(); |
46 | Iterator<EObject> tempIterator = tempList.iterator(); |
47 | EObject newResource; |
48 | if (tempIterator.hasNext()) { |
49 | newResource = tempIterator.next(); |
50 | } else { |
51 | return null; |
52 | } |
53 | |
54 | if (!(newResource instanceof Configuration)) { |
55 | return null; |
56 | } |
57 | return (Configuration) newResource; |
58 | } |
59 | |
60 | |
61 | /** |
62 | * Unchecks recursively parent nodes, if no children nodes are checked |
63 | * |
64 | * @param current |
65 | * The unchecked Feature |
66 | */ |
67 | public void uncheckParents(Object current, CheckboxTreeViewer treeViewer, FeatureConfig overridesConfig, AdapterFactoryEditingDomain editingDomain) { |
68 | boolean checked = getAnyChecked(current, treeViewer, editingDomain); |
69 | |
70 | if (!checked) { |
71 | Object parent = editingDomain.getParent(current); |
72 | |
73 | if (parent != null && !(parent instanceof FeatureDiagram)) { |
74 | treeViewer.setChecked(parent, false); |
75 | |
76 | if (parent instanceof Feature) { |
77 | uncheckInModel((Feature) parent, false, overridesConfig); |
78 | } |
79 | uncheckParents(parent, treeViewer,overridesConfig, editingDomain); |
80 | } |
81 | } |
82 | } |
83 | |
84 | /** |
85 | * Checks, if any siblings of the selected Node are also selected |
86 | * |
87 | * @param current |
88 | * @return <code>true</code> if there are any siblings of current checked |
89 | * <code>false</code> otherwise |
90 | */ |
91 | private boolean getAnyChecked (Object current, CheckboxTreeViewer treeViewer, AdapterFactoryEditingDomain editingDomain) { |
92 | Object parent = editingDomain.getParent(current); |
93 | |
94 | boolean checked = false; |
95 | |
96 | if (parent instanceof FeatureGroup) { |
97 | EList<Feature> children = ((FeatureGroup) parent).getChildren(); |
98 | Iterator<Feature> tempIter = children.iterator(); |
99 | Feature next; |
100 | while(tempIter.hasNext()) { |
101 | next = tempIter.next(); |
102 | if (treeViewer.getChecked(next)) { |
103 | checked = true; |
104 | } |
105 | } |
106 | } |
107 | else if (parent instanceof Feature) { |
108 | ChildRelation childRel = ((Feature) parent).getChildrelation(); |
109 | if (!(childRel instanceof FeatureGroup)) { |
110 | EList<Feature> childrenMan = ((Simple)childRel).getMandatoryChildren(); |
111 | EList<Feature> childrenOpt = ((Simple)childRel).getOptionalChildren(); |
112 | |
113 | Iterator<Feature> manIter = childrenMan.iterator(); |
114 | Feature next; |
115 | while(manIter.hasNext()) { |
116 | next = manIter.next(); |
117 | if (treeViewer.getChecked(next)) { |
118 | checked = true; |
119 | } |
120 | } |
121 | if (!checked) { |
122 | Iterator<Feature> optIter = childrenOpt.iterator(); |
123 | while(optIter.hasNext()) { |
124 | next = optIter.next(); |
125 | if (treeViewer.getChecked(next)) { |
126 | checked = true; |
127 | } |
128 | } |
129 | } |
130 | } |
131 | } |
132 | |
133 | return checked; |
134 | } |
135 | |
136 | |
137 | /** |
138 | * Checks recursively parent nodes, if a Node is checked |
139 | * |
140 | * @param current |
141 | * The checked Feature |
142 | */ |
143 | protected void checkParents(Object current, CheckboxTreeViewer treeViewer, FeatureConfig overridesConfig, AdapterFactoryEditingDomain editingDomain) { |
144 | Object parent = editingDomain.getParent(current); |
145 | if (parent != null) { |
146 | if (!(treeViewer.getChecked(parent))) { |
147 | if (!(parent instanceof FeatureGroup)) { |
148 | treeViewer.setChecked(parent, true); |
149 | } |
150 | |
151 | if (parent instanceof Feature) { |
152 | uncheckInModel((Feature) parent, true, overridesConfig); |
153 | } |
154 | checkParents(parent, treeViewer, overridesConfig, editingDomain); |
155 | } |
156 | } |
157 | } |
158 | |
159 | /** |
160 | * Navigates to the FeatureDiagram from a given Feature-object |
161 | * |
162 | * @param feature |
163 | * A Feature-object |
164 | * @param editingDomain The necessary editingDomain |
165 | * @return the parent FeatureDiagram to the given Feature-object |
166 | */ |
167 | public FeatureDiagram navigateToFeatureDiagram(Feature feature, AdapterFactoryEditingDomain editingDomain) { |
168 | Object parent = editingDomain.getParent(feature); |
169 | |
170 | while (parent != null && !(parent instanceof FeatureDiagram)) { |
171 | parent = editingDomain.getParent(parent); |
172 | } |
173 | |
174 | return (FeatureDiagram) parent; |
175 | } |
176 | |
177 | /** |
178 | * Initializes the adapterFactory, the commandStack and with these objects |
179 | * the editingDomain |
180 | */ |
181 | public AdapterFactoryEditingDomain initializeEditingDomain() { |
182 | ComposedAdapterFactory adapterFactory = new ComposedAdapterFactory( |
183 | ComposedAdapterFactory.Descriptor.Registry.INSTANCE); |
184 | |
185 | adapterFactory |
186 | .addAdapterFactory(new ResourceItemProviderAdapterFactory()); |
187 | adapterFactory |
188 | .addAdapterFactory(new featureconfigItemProviderAdapterFactory()); |
189 | adapterFactory |
190 | .addAdapterFactory(new featuremodelItemProviderAdapterFactory()); |
191 | adapterFactory |
192 | .addAdapterFactory(new IdentifierItemProviderAdapterFactory()); |
193 | adapterFactory |
194 | .addAdapterFactory(new ReflectiveItemProviderAdapterFactory()); |
195 | |
196 | BasicCommandStack commandStack = new BasicCommandStack(); |
197 | |
198 | return new AdapterFactoryEditingDomain(adapterFactory, |
199 | commandStack, new HashMap<Resource, Boolean>()); |
200 | } |
201 | |
202 | /** |
203 | * Checks if a newly loaded featureconfig-file references the opened FeatureDiagram resource |
204 | * |
205 | * @param existingResource Newly loaded Resource-object (should be a featureconfig-file) |
206 | * @return <code>false</code>, if existingResource doesn't include a Configuration-object or if no ConifgNode references to the opened model |
207 | * <code>true</code> otherwise |
208 | */ |
209 | public boolean isFeatureDiagramReferenceCorrect (Resource existingResource) { |
210 | Configuration configuration = getConfiguration(existingResource); |
211 | |
212 | boolean correct = false; |
213 | |
214 | if (configuration == null) { |
215 | return correct; |
216 | } |
217 | else { |
218 | EList<FeatureConfig> tempOverrides = configuration.getConfigOverrides(); |
219 | FeatureConfig tempDefault = configuration.getDefaultConfig(); |
220 | |
221 | if (tempOverrides != null && !tempOverrides.isEmpty()) { |
222 | EList <ConfigNode> configList = tempOverrides.get(0).getConfignode(); //Assumption: Every config references the same Feature Diagram |
223 | if (!(configList.isEmpty())) { |
224 | Iterator<ConfigNode> configIterator = configList.iterator(); |
225 | while (configIterator.hasNext()) { |
226 | if (configIterator.next().getOrigin() != null) { |
227 | correct = true; |
228 | } |
229 | } |
230 | } |
231 | } |
232 | |
233 | if (!correct && tempDefault != null) { |
234 | EList <ConfigNode> configList = tempDefault.getConfignode(); |
235 | if (!(configList.isEmpty())) { |
236 | Iterator<ConfigNode> configIterator = configList.iterator(); |
237 | while (configIterator.hasNext()) { |
238 | if (configIterator.next().getOrigin() != null) { |
239 | correct = true; |
240 | } |
241 | } |
242 | } |
243 | } |
244 | } |
245 | return correct; |
246 | } |
247 | |
248 | /** |
249 | * Selects recursively the mandatory Features |
250 | * |
251 | * @param curRelation |
252 | * The ChildRelation, where the selecting should start |
253 | */ |
254 | public void selectMandatoryFeatures(ChildRelation curRelation, CheckboxTreeViewer treeViewer, FeatureConfig overridesConfig) { |
255 | if (curRelation != null) { |
256 | if (curRelation instanceof FeatureGroup) { |
257 | EList<Feature> nodes = ((FeatureGroup) curRelation) |
258 | .getChildren(); |
259 | Iterator<Feature> nodesIter = nodes.iterator(); |
260 | while (nodesIter.hasNext()) { |
261 | selectMandatoryFeatures(nodesIter.next().getChildrelation(), treeViewer, overridesConfig); |
262 | } |
263 | } else if (curRelation instanceof Simple) { |
264 | EList<Feature> mandFeatures = ((Simple) curRelation) |
265 | .getMandatoryChildren(); |
266 | EList<Feature> optFeatures = ((Simple) curRelation) |
267 | .getOptionalChildren(); |
268 | |
269 | Iterator<Feature> featureIter = mandFeatures.iterator(); |
270 | while (featureIter.hasNext()) { |
271 | Feature next = featureIter.next(); |
272 | treeViewer.setChecked(next, true); |
273 | uncheckInModel(next, true, overridesConfig); |
274 | selectMandatoryFeatures(next.getChildrelation(), treeViewer, overridesConfig); |
275 | } |
276 | |
277 | featureIter = optFeatures.iterator(); |
278 | while (featureIter.hasNext()) { |
279 | selectMandatoryFeatures(featureIter.next() |
280 | .getChildrelation(), treeViewer, overridesConfig); |
281 | } |
282 | } |
283 | } |
284 | } |
285 | |
286 | /** |
287 | * Registers changes made in the TreeViewer to the resource |
288 | * |
289 | * @param element |
290 | * The changed Feature |
291 | * @param state |
292 | * The checked/unchecked state |
293 | */ |
294 | public void uncheckInModel(Feature element, boolean state, FeatureConfig overridesConfig) { |
295 | // firePropertyChange(IEditorPart.PROP_DIRTY); |
296 | int hash = element.hashCode(); |
297 | boolean found = false; |
298 | Iterator<ConfigNode> tempIter = overridesConfig.getConfignode() |
299 | .iterator(); |
300 | |
301 | // search for existing ConfigNodes in the overridesConfig and register |
302 | // changes |
303 | while (tempIter.hasNext()) { |
304 | ConfigNode next = tempIter.next(); |
305 | if (next.getOrigin().hashCode() == hash) { |
306 | found = true; |
307 | if (state) { |
308 | next.setConfigState(ConfigState.SELECTED); |
309 | } else { |
310 | next.setConfigState(ConfigState.ELIMINATED); |
311 | } |
312 | } |
313 | } |
314 | |
315 | // if no ConfigNode exists, create new one |
316 | if (!(found)) { |
317 | featureconfigFactoryImpl factory = new featureconfigFactoryImpl(); |
318 | ConfigNode newConfig = factory.createConfigNode(); |
319 | newConfig.setOrigin(element); |
320 | |
321 | if (state) { |
322 | newConfig.setConfigState(ConfigState.SELECTED); |
323 | } else { |
324 | newConfig.setConfigState(ConfigState.ELIMINATED); |
325 | } |
326 | overridesConfig.getConfignode().add(newConfig); |
327 | } |
328 | } |
329 | |
330 | /** |
331 | * Checks/unchecks the defaultConfiguration in the Viewer |
332 | */ |
333 | public void markDefaultConfig(FeatureConfig defaultConfig, CheckboxTreeViewer treeViewer) { |
334 | // mark all default configNodes |
335 | EList<ConfigNode> defaultNodes = defaultConfig.getConfignode(); |
336 | Iterator<ConfigNode> tempIter = defaultNodes.iterator(); |
337 | ConfigNode next; |
338 | Feature referenced; |
339 | while (tempIter.hasNext()) { |
340 | next = tempIter.next(); |
341 | referenced = (Feature) next.getOrigin(); |
342 | |
343 | // selected |
344 | if (next.getConfigState().getValue() == 0) { |
345 | treeViewer.setGrayChecked(referenced, true); |
346 | } |
347 | // eliminated |
348 | else if (next.getConfigState().getValue() == 1) { |
349 | treeViewer.setGrayChecked(referenced, false); |
350 | } |
351 | } |
352 | } |
353 | |
354 | /** |
355 | * Checks/unchecks the configurationOverrides in the Viewer |
356 | */ |
357 | public void markOverridesConfig(FeatureConfig overridesConfig, CheckboxTreeViewer treeViewer) { |
358 | // mark all overrides configNodes |
359 | EList<ConfigNode> overridesNodes = overridesConfig.getConfignode(); |
360 | Iterator<ConfigNode> tempIter = overridesNodes.iterator(); |
361 | ConfigNode next; |
362 | Feature referenced; |
363 | while (tempIter.hasNext()) { |
364 | next = tempIter.next(); |
365 | referenced = (Feature) next.getOrigin(); |
366 | |
367 | // selected |
368 | if (next.getConfigState().getValue() == 0) { |
369 | treeViewer.setGrayed(referenced, false); |
370 | treeViewer.setChecked(referenced, true); |
371 | } |
372 | // eliminated |
373 | else if (next.getConfigState().getValue() == 1) { |
374 | treeViewer.setGrayed(referenced, false); |
375 | treeViewer.setChecked(referenced, false); |
376 | } |
377 | } |
378 | } |
379 | |
380 | /** |
381 | * Checks if a Feature `node` is a mandatory Feature |
382 | * |
383 | * @param node |
384 | * The Feature which needs to be checked |
385 | * @return <code>true</code>, if node is a mandatory Feature |
386 | * <code>false</code>, else |
387 | */ |
388 | public boolean checkMandatory(Feature node, AdapterFactoryEditingDomain editingDomain) { |
389 | Object parent = editingDomain.getParent(node); |
390 | |
391 | boolean mandatory = false; |
392 | |
393 | if (parent instanceof Simple) { |
394 | EList<Feature> featureList = ((Simple) parent) |
395 | .getMandatoryChildren(); |
396 | |
397 | for (Feature current : featureList) { |
398 | if (current == node) { |
399 | mandatory = true; |
400 | } |
401 | } |
402 | } |
403 | |
404 | return mandatory; |
405 | } |
406 | |
407 | /** |
408 | * Grays out the FeatureGroups in the treeViewer |
409 | * |
410 | * @param curRoot The current ChildRelation |
411 | */ |
412 | public void grayFeatureGroups (ChildRelation curRelation, CheckboxTreeViewer treeViewer) { |
413 | if (curRelation != null) { |
414 | if (curRelation instanceof FeatureGroup) { |
415 | treeViewer.setGrayed(curRelation, true); |
416 | EList<Feature> nodes = ((FeatureGroup)curRelation).getChildren(); |
417 | Iterator<Feature> nodesIter = nodes.iterator(); |
418 | while (nodesIter.hasNext()) { |
419 | grayFeatureGroups(nodesIter.next().getChildrelation(), treeViewer); |
420 | } |
421 | } |
422 | else if(curRelation instanceof Simple) { |
423 | EList<Feature> mandFeatures = ((Simple)curRelation).getMandatoryChildren(); |
424 | EList<Feature> optFeatures = ((Simple)curRelation).getOptionalChildren(); |
425 | |
426 | Iterator<Feature> featureIter = mandFeatures.iterator(); |
427 | while (featureIter.hasNext()) { |
428 | grayFeatureGroups(featureIter.next().getChildrelation(), treeViewer); |
429 | } |
430 | |
431 | featureIter = optFeatures.iterator(); |
432 | while (featureIter.hasNext()) { |
433 | grayFeatureGroups(featureIter.next().getChildrelation(), treeViewer); |
434 | } |
435 | } |
436 | } |
437 | } |
438 | |
439 | |
440 | /** |
441 | * This returns whether something has been persisted to the URI of the |
442 | * specified resource. The implementation uses the URI converter from the |
443 | * editor's resource set to try to open an input stream. <!-- begin-user-doc |
444 | * --> <!-- end-user-doc --> |
445 | * |
446 | * @generated |
447 | */ |
448 | protected boolean isPersisted(Resource resource, AdapterFactoryEditingDomain editingDomain) { |
449 | boolean result = false; |
450 | try { |
451 | InputStream stream = editingDomain.getResourceSet() |
452 | .getURIConverter().createInputStream(resource.getURI()); |
453 | if (stream != null) { |
454 | result = true; |
455 | stream.close(); |
456 | } |
457 | } catch (IOException e) { |
458 | // Ignore |
459 | } |
460 | return result; |
461 | } |
462 | } |