| /******************************************************************************* |
| * Copyright (c) 2010, 2019 BestSolution.at and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Tom Schindl <tom.schindl@bestsolution.at> - initial API and implementation |
| * Steven Spungin <steve@spungin.tv> - Ongoing Maintenance, Bug 439532, Bug 443945 |
| * Patrik Suzzi <psuzzi@gmail.com> - Bug 467262 |
| * Olivier Prouvost <olivier.prouvost@opcoach.com> - Bug 509488, 525986 |
| * Patrik Suzzi <psuzzi@gmail.com> - Bug 509606 |
| ******************************************************************************/ |
| package org.eclipse.e4.tools.emf.ui.internal.common.component; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import javax.annotation.PostConstruct; |
| import javax.inject.Inject; |
| |
| import org.eclipse.core.databinding.observable.list.IObservableList; |
| import org.eclipse.e4.core.contexts.IEclipseContext; |
| import org.eclipse.e4.emf.xpath.EcoreXPathContextFactory; |
| import org.eclipse.e4.emf.xpath.XPathContext; |
| import org.eclipse.e4.emf.xpath.XPathContextFactory; |
| import org.eclipse.e4.tools.emf.ui.common.IEditorFeature.FeatureClass; |
| import org.eclipse.e4.tools.emf.ui.common.Util; |
| import org.eclipse.e4.tools.emf.ui.common.Util.InternalPackage; |
| import org.eclipse.e4.tools.emf.ui.common.component.AbstractComponentEditor; |
| import org.eclipse.e4.tools.emf.ui.internal.E4Properties; |
| import org.eclipse.e4.tools.emf.ui.internal.ResourceProvider; |
| import org.eclipse.e4.tools.emf.ui.internal.common.AbstractPickList.PickListFeatures; |
| import org.eclipse.e4.tools.emf.ui.internal.common.E4PickList; |
| import org.eclipse.e4.tools.emf.ui.internal.common.component.ControlFactory.TextPasteHandler; |
| import org.eclipse.e4.tools.emf.ui.internal.common.component.dialogs.FeatureSelectionDialog; |
| import org.eclipse.e4.tools.emf.ui.internal.common.component.dialogs.FindParentReferenceElementDialog; |
| import org.eclipse.e4.tools.emf.ui.internal.common.component.tabs.empty.E; |
| import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VSnippetsEditor; |
| import org.eclipse.e4.ui.model.application.MApplication; |
| import org.eclipse.e4.ui.model.application.MApplicationElement; |
| import org.eclipse.e4.ui.model.application.impl.ApplicationElementImpl; |
| import org.eclipse.e4.ui.model.application.impl.ApplicationPackageImpl; |
| import org.eclipse.e4.ui.model.fragment.MModelFragment; |
| import org.eclipse.e4.ui.model.fragment.MStringModelFragment; |
| import org.eclipse.e4.ui.model.fragment.impl.FragmentPackageImpl; |
| import org.eclipse.e4.ui.model.fragment.impl.StringModelFragmentImpl; |
| import org.eclipse.e4.ui.model.internal.ModelUtils; |
| import org.eclipse.emf.common.command.Command; |
| import org.eclipse.emf.common.util.TreeIterator; |
| import org.eclipse.emf.databinding.EMFDataBindingContext; |
| import org.eclipse.emf.databinding.FeaturePath; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.emf.edit.command.AddCommand; |
| import org.eclipse.jface.action.Action; |
| import org.eclipse.jface.bindings.keys.KeyStroke; |
| import org.eclipse.jface.bindings.keys.ParseException; |
| import org.eclipse.jface.databinding.swt.IWidgetValueProperty; |
| import org.eclipse.jface.databinding.swt.typed.WidgetProperties; |
| import org.eclipse.jface.fieldassist.ContentProposal; |
| import org.eclipse.jface.fieldassist.ContentProposalAdapter; |
| import org.eclipse.jface.fieldassist.ControlDecoration; |
| import org.eclipse.jface.fieldassist.FieldDecorationRegistry; |
| import org.eclipse.jface.fieldassist.IContentProposal; |
| import org.eclipse.jface.fieldassist.IContentProposalProvider; |
| import org.eclipse.jface.fieldassist.TextContentAdapter; |
| import org.eclipse.jface.viewers.LabelProvider; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.jface.viewers.Viewer; |
| import org.eclipse.jface.viewers.ViewerComparator; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.CTabFolder; |
| import org.eclipse.swt.custom.CTabItem; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.Button; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Text; |
| |
| public class StringModelFragment extends AbstractComponentEditor<MStringModelFragment> { |
| private Composite composite; |
| private EMFDataBindingContext context; |
| |
| // The selected Container is the class that match the ID. |
| // It can be get from the FindParentReferenceDialog or computed from the ID. |
| private EClass selectedContainer; |
| |
| // This is the list of available 'add child' actions depending on selected |
| // values |
| private final List<Action> actions = new ArrayList<>(); |
| |
| @Inject |
| IEclipseContext eclipseContext; |
| |
| // The pickList to select the kind of children to add (must be refreshed) |
| private E4PickList pickList; |
| private Text featureText; |
| |
| @Inject |
| public StringModelFragment() { |
| super(); |
| } |
| |
| @PostConstruct |
| public void init() { |
| } |
| |
| @Override |
| public Image getImage(Object element) { |
| return getImage(element, ResourceProvider.IMG_StringModelFragment); |
| } |
| |
| @Override |
| public String getLabel(Object element) { |
| |
| MStringModelFragment modelFragment; |
| if (element instanceof MStringModelFragment) { |
| modelFragment = (MStringModelFragment) element; |
| } else { |
| modelFragment = getStringModelFragment(); |
| } |
| |
| EClass container = findContainerType(modelFragment); |
| String result; |
| if (container == null) { |
| result = Messages.StringModelFragment_Label; |
| } else { |
| result = Messages.StringModelFragment_LabelFor + container.getName(); |
| } |
| |
| return result; |
| } |
| |
| @Override |
| public FeaturePath[] getLabelProperties() { |
| return new FeaturePath[] { |
| FeaturePath.fromList(FragmentPackageImpl.Literals.STRING_MODEL_FRAGMENT__FEATURENAME), |
| FeaturePath.fromList(FragmentPackageImpl.Literals.STRING_MODEL_FRAGMENT__PARENT_ELEMENT_ID) }; |
| } |
| |
| @Override |
| public String getDetailLabel(Object element) { |
| if (element instanceof StringModelFragmentImpl) { |
| final StringModelFragmentImpl fragment = (StringModelFragmentImpl) element; |
| String ret = ""; //$NON-NLS-1$ |
| if (E.notEmpty(fragment.getFeaturename())) { |
| ret += fragment.getFeaturename(); |
| } |
| if (E.notEmpty(fragment.getParentElementId())) { |
| ret += " (" + fragment.getParentElementId() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| return ret; |
| } |
| return null; |
| } |
| |
| @Override |
| public String getDescription(Object element) { |
| return Messages.StringModelFragment_Description; |
| } |
| |
| @Override |
| public Composite doGetEditor(Composite parent, Object object) { |
| if (composite == null) { |
| context = new EMFDataBindingContext(); |
| composite = createForm(parent); |
| } |
| selectedContainer = null; |
| getMaster().setValue((MStringModelFragment) object); |
| updateChildrenChoice(); |
| getEditor().setHeaderTitle(getLabel(null)); |
| return composite; |
| } |
| |
| /** |
| * Returns the selectedContainer, which is the EClass behind the Extended |
| * Element ID. It can be known thanks to the dialog or must be computed from |
| * the ID value |
| * |
| * @return |
| */ |
| private EClass getSelectedContainer() { |
| if (selectedContainer != null) { |
| return selectedContainer; |
| } |
| |
| // we get the StringModelFragment. If not initialized, no search... |
| StringModelFragmentImpl modelFragment = getStringModelFragment(); |
| selectedContainer = findContainerType(modelFragment); |
| |
| updateTitle(); |
| |
| return selectedContainer; |
| } |
| |
| /** |
| * Returns the selectedContainer, which is the EClass behind the Extended |
| * Element ID. It can be known thanks to the dialog or must be computed from the |
| * ID value |
| * |
| */ |
| public static EClass findContainerType(MStringModelFragment modelFragment) { |
| // we get the StringModelFragment. If not initialized, no search... |
| if (modelFragment == null) { |
| return null; |
| } |
| |
| // If no element ID, no search... |
| String parentElementId = modelFragment.getParentElementId(); |
| if ((parentElementId == null) || (parentElementId.isEmpty())) { |
| return null; |
| } |
| |
| // known ID for application are directly filtered. |
| if ("xpath:/".equals(parentElementId) || "org.eclipse.e4.legacy.ide.application".equals(parentElementId)) { |
| return ApplicationPackageImpl.eINSTANCE.getApplication(); |
| } |
| |
| // We have to proceed to a simple search on all elements in all resource |
| // set... this resource set is cached by Util... |
| ResourceSet resourceSet = Util.getModelElementResources(); |
| |
| String xpath = parentElementId.startsWith("xpath:") ? parentElementId.substring(6) : null; |
| |
| for (final Resource res : resourceSet.getResources()) { |
| final TreeIterator<EObject> it = EcoreUtil.getAllContents(res, true); |
| while (it.hasNext()) { |
| final EObject o = it.next(); |
| // We found this element, if this is an application element not |
| // contained in model fragment imports |
| // and having the same ID. We return the first found. |
| |
| // Deal with non default MApplication IDs. |
| if (xpath != null) { |
| if (o instanceof MApplication) { |
| EClass found = getTargetClassFromXPath((MApplication) o, xpath); |
| if (found != null) { |
| return found; |
| } |
| } |
| } else { |
| // This is a standard search with ID. |
| if ((o instanceof MApplicationElement) |
| && (o.eContainingFeature() != FragmentPackageImpl.Literals.MODEL_FRAGMENTS__IMPORTS) |
| && parentElementId.equals(((MApplicationElement) o).getElementId())) { |
| return o.eClass(); |
| } |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| private void updateTitle() { |
| getEditor().setHeaderTitle(getLabel(null)); |
| } |
| |
| private StringModelFragmentImpl getStringModelFragment() { |
| return ((StringModelFragmentImpl) getMaster().getValue()); |
| } |
| |
| private Composite createForm(Composite parent) { |
| final CTabFolder folder = new CTabFolder(parent, SWT.BOTTOM); |
| |
| final CTabItem item = new CTabItem(folder, SWT.NONE); |
| item.setText(Messages.ModelTooling_Common_TabDefault); |
| |
| parent = createScrollableContainer(folder); |
| item.setControl(parent.getParent()); |
| |
| if (getEditor().isShowXMIId() || getEditor().isLiveModel()) { |
| ControlFactory.createXMIId(parent, this); |
| } |
| |
| final IWidgetValueProperty<Text, String> textProp = WidgetProperties.text(SWT.Modify); |
| { |
| final Label l = new Label(parent, SWT.NONE); |
| l.setText(Messages.StringModelFragment_ParentId); |
| l.setToolTipText(Messages.StringModelFragment_ParentIdTooltip); |
| l.setLayoutData(new GridData()); |
| |
| final Composite comp = new Composite(parent, SWT.NONE); |
| GridData gd = new GridData(GridData.FILL_HORIZONTAL); |
| gd.horizontalSpan = 2; |
| comp.setLayoutData(gd); |
| final GridLayout gl = new GridLayout(2, false); |
| gl.marginWidth = gl.marginHeight = 0; |
| gl.verticalSpacing = 0; |
| gl.marginLeft = gl.marginBottom = gl.marginRight = gl.marginTop = 0; |
| comp.setLayout(gl); |
| |
| final Text t = new Text(comp, SWT.BORDER); |
| TextPasteHandler.createFor(t); |
| // t.setEditable(false); |
| gd = new GridData(GridData.FILL_HORIZONTAL); |
| t.setLayoutData(gd); |
| context.bindValue(textProp.observeDelayed(200, t), |
| E4Properties.parentElementId(getEditingDomain()).observeDetail(getMaster())); |
| |
| // Add a modify listener to control the change of the ID -> Must |
| // force the computation of selectedContainer. |
| t.addModifyListener(e -> selectedContainer = null); |
| |
| Button b = ControlFactory.createFindButton(comp, resourcePool); |
| b.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| final FindParentReferenceElementDialog dialog = new FindParentReferenceElementDialog(b.getShell(), |
| StringModelFragment.this, getMaster().getValue(), Messages, |
| getSelectedContainer()); |
| dialog.open(); |
| selectedContainer = dialog.getSelectedContainer(); |
| updateTitle(); |
| } |
| }); |
| } |
| |
| { |
| final Label l = new Label(parent, SWT.NONE); |
| l.setText(Messages.StringModelFragment_Featurename); |
| l.setToolTipText(Messages.StringModelFragment_FeaturenameTooltip); |
| l.setLayoutData(new GridData()); |
| |
| final Composite comp = new Composite(parent, SWT.NONE); |
| GridData gd = new GridData(GridData.FILL_HORIZONTAL); |
| gd.horizontalSpan = 2; |
| comp.setLayoutData(gd); |
| final GridLayout gl = new GridLayout(2, false); |
| gl.marginWidth = gl.marginHeight = 0; |
| gl.verticalSpacing = 0; |
| gl.marginLeft = gl.marginBottom = gl.marginRight = gl.marginTop = 0; |
| comp.setLayout(gl); |
| |
| featureText = new Text(comp, SWT.BORDER); |
| TextPasteHandler.createFor(featureText); |
| gd = new GridData(GridData.FILL_HORIZONTAL); |
| featureText.setLayoutData(gd); |
| context.bindValue(textProp.observeDelayed(200, featureText), |
| E4Properties.featureName(getEditingDomain()).observeDetail(getMaster())); |
| |
| // create the decoration for the text component |
| final ControlDecoration deco = new ControlDecoration(featureText, SWT.TOP | SWT.LEFT); |
| |
| // use an existing image |
| Image image = FieldDecorationRegistry.getDefault() |
| .getFieldDecoration(FieldDecorationRegistry.DEC_INFORMATION).getImage(); |
| |
| // set description and image |
| deco.setDescriptionText(Messages.StringModelFragment_Ctrl_Space); |
| deco.setImage(image); |
| |
| // always show decoration |
| deco.setShowOnlyOnFocus(false); |
| |
| // hide the decoration if the text component has content |
| featureText.addModifyListener(e -> { |
| Text text = (Text) e.getSource(); |
| if (!text.getText().isEmpty()) { |
| deco.hide(); |
| } else { |
| deco.show(); |
| } |
| }); |
| |
| KeyStroke keyStroke; |
| try { |
| char[] autoactivationChar = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.".toCharArray(); |
| keyStroke = KeyStroke.getInstance("Ctrl+Space"); |
| ContentProposalAdapter adapter = new ContentProposalAdapter(featureText, new TextContentAdapter(), |
| new StringModelFragmentProposalProvider(this, featureText), keyStroke, autoactivationChar); |
| adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE); |
| } catch (ParseException e) { |
| e.printStackTrace(); |
| } |
| featureText.addModifyListener(e -> updateChildrenChoice()); |
| |
| Button b = ControlFactory.createFindButton(comp, resourcePool); |
| b.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| final FeatureSelectionDialog dialog = new FeatureSelectionDialog(b.getShell(), |
| getEditingDomain(), getMaster().getValue(), Messages, |
| getSelectedContainer()); |
| dialog.open(); |
| } |
| }); |
| |
| } |
| |
| ControlFactory.createTextField(parent, Messages.StringModelFragment_PositionInList, getMaster(), context, |
| textProp, E4Properties.positionInList(getEditingDomain())); |
| |
| // ------------------------------------------------------------ |
| { |
| |
| pickList = new E4PickList(parent, SWT.NONE, Arrays.asList(PickListFeatures.NO_GROUP), this, |
| FragmentPackageImpl.Literals.MODEL_FRAGMENT__ELEMENTS) { |
| @Override |
| protected void addPressed() { |
| if(!getSelection().isEmpty()) { |
| final EClass eClass = ((FeatureClass) getSelection().getFirstElement()).eClass; |
| handleAdd(eClass, false); |
| } |
| } |
| |
| @Override |
| protected List<?> getContainerChildren(Object master) { |
| return ((StringModelFragmentImpl) master).getElements(); |
| } |
| }; |
| |
| pickList.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1)); |
| |
| pickList.setLabelProvider(new LabelProvider() { |
| @Override |
| public String getText(Object element) { |
| final FeatureClass eclass = (FeatureClass) element; |
| return eclass.label; |
| } |
| }); |
| |
| pickList.setComparator(new ViewerComparator() { |
| @Override |
| public int compare(Viewer viewer, Object e1, Object e2) { |
| final FeatureClass eClass1 = (FeatureClass) e1; |
| final FeatureClass eClass2 = (FeatureClass) e2; |
| return eClass1.label.compareTo(eClass2.label); |
| } |
| }); |
| |
| } |
| |
| createContributedEditorTabs(folder, context, getMaster(), MStringModelFragment.class); |
| |
| folder.setSelection(0); |
| |
| updateChildrenChoice(); |
| |
| return folder; |
| } |
| |
| static class StringModelFragmentProposalProvider implements IContentProposalProvider { |
| |
| private StringModelFragment fragment; |
| private Text text; |
| |
| /** |
| * Initialize the class passing the current instance. |
| */ |
| public StringModelFragmentProposalProvider(StringModelFragment fragment, Text t) { |
| this.fragment = fragment; |
| this.text = t; |
| } |
| |
| @Override |
| public IContentProposal[] getProposals(String cont, int position) { |
| List<String[]> contents = new ArrayList<>(); |
| StringBuilder sb = new StringBuilder(256); |
| if (fragment.getSelectedContainer() != null) { |
| for (EReference r : fragment.getSelectedContainer().getEAllReferences()) { |
| if (Util.referenceIsModelFragmentCompliant(r) && r.getName().startsWith(text.getText())) { |
| String content = r.getName(); |
| sb.setLength(0); |
| sb.append(content).append(": "); |
| final EClassifier type = ModelUtils.getTypeArgument(this.fragment.getSelectedContainer(), |
| r.getEGenericType()); |
| if (r.isMany()) { |
| // List<Container> |
| sb.append("List<").append(type.getName()).append(">"); |
| } else { |
| // TypeOfTheClass |
| sb.append(type.getName()); |
| } |
| contents.add(new String[] { content, sb.toString() }); |
| } |
| } |
| } |
| |
| Collections.sort(contents, (o1, o2) -> o1[0].compareTo(o2[0])); |
| |
| IContentProposal[] contentProposals = new IContentProposal[contents.size()]; |
| for (int i = 0; i < contents.size(); i++) { |
| contentProposals[i] = new ContentProposal(contents.get(i)[0], contents.get(i)[1], null); |
| } |
| return contentProposals; |
| } |
| |
| } |
| |
| public void dispose() { |
| if (composite != null) { |
| composite.dispose(); |
| composite = null; |
| } |
| |
| if (context != null) { |
| context.dispose(); |
| context = null; |
| } |
| } |
| |
| /** |
| * This method will update the picklist containing the list of possible |
| * children classes |
| * |
| */ |
| private void updateChildrenChoice() { |
| selectedContainer = getSelectedContainer(); |
| |
| final List<FeatureClass> list = getTargetChildrenClasses(); |
| |
| pickList.setInput(list); |
| if (list.size() > 0) { |
| pickList.setSelection(new StructuredSelection(list.get(0))); |
| } |
| |
| // pickList.getList().refresh(); |
| |
| pickList.getList().setInput(E4Properties.elements().observeDetail(getMaster())); |
| |
| // Update the possible actions |
| actions.clear(); |
| for (final FeatureClass featureClass : list) { |
| actions.add(new Action(featureClass.label) { |
| @Override |
| public void run() { |
| handleAdd(featureClass.eClass, false); |
| } |
| }); |
| } |
| } |
| |
| @Override |
| public IObservableList<?> getChildList(Object element) { |
| return E4Properties.elements().observe((MModelFragment) element); |
| } |
| |
| protected void handleAdd(EClass eClass, boolean separator) { |
| final EObject eObject = EcoreUtil.create(eClass); |
| setElementId(eObject); |
| final Command cmd = AddCommand.create(getEditingDomain(), getMaster().getValue(), |
| FragmentPackageImpl.Literals.MODEL_FRAGMENT__ELEMENTS, eObject); |
| |
| if (cmd.canExecute()) { |
| getEditingDomain().getCommandStack().execute(cmd); |
| getEditor().setSelection(eObject); |
| } |
| } |
| |
| @Override |
| public List<Action> getActions(Object element) { |
| final ArrayList<Action> l = new ArrayList<>(super.getActions(element)); |
| l.addAll(actions); |
| Collections.sort(l, (o1, o2) -> o1.getText().compareTo(o2.getText())); |
| return l; |
| } |
| |
| /** |
| * Returns the EClass of the Application element(s) referenced by the xpath |
| * value (without prefix) |
| * |
| * @param application |
| * : the application to be parsed |
| * @param xpath |
| * : the xpath value without the 'xpath:' prefix |
| * @return the list of EClass(es) matching this xpath |
| */ |
| private static EClass getTargetClassFromXPath(MApplication application, String xpath) { |
| |
| XPathContextFactory<EObject> f = EcoreXPathContextFactory.newInstance(); |
| XPathContext xpathContext = f.newContext((EObject) application); |
| Iterator<Object> i = xpathContext.iterate(xpath); |
| |
| try { |
| while (i.hasNext()) { |
| Object obj = i.next(); |
| if (obj instanceof MApplicationElement) { |
| ApplicationElementImpl ae = (ApplicationElementImpl) obj; |
| return ae.eClass(); |
| } |
| } |
| } catch (Exception ex) { |
| // custom xpath functions will throw exceptions |
| ex.printStackTrace(); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * This method computes the available classes that can be selected as child |
| * for the current selected element. The result is cached in a map as the |
| * meta model will not change ! |
| * |
| * @return an empty list or the list for possible children |
| */ |
| |
| public List<FeatureClass> getTargetChildrenClasses() { |
| List<FeatureClass> targetChildrenClasses = new ArrayList<>(); |
| if (selectedContainer != null) { |
| List<FeatureClass> childTypes = getTargetChildrenClasses(selectedContainer, |
| featureText.getText()); |
| targetChildrenClasses.addAll(childTypes); |
| } |
| return targetChildrenClasses; |
| } |
| |
| /** |
| * This method computes the available classes that can be selected as child for |
| * the current selected element. The result is cached in a map as the meta model |
| * will not change ! |
| * |
| * @param targetClass |
| * the target class to check against |
| * |
| * @return an empty list or the list for possible children |
| */ |
| |
| public static List<FeatureClass> getTargetChildrenClasses(EClass targetClass, String featurename) { |
| List<FeatureClass> result = Collections.emptyList(); |
| |
| if (targetClass != null) { |
| // The top level class for children, is the class of the EReference |
| // bound to feature name |
| |
| // We must manage especially snippets (see bug 531219) No other solution ... |
| if ("snippets".equals(featurename)) { |
| result = new ArrayList<>(); |
| for (EClass c : VSnippetsEditor.SNIPPET_CHILDREN) { |
| result.add(new FeatureClass(c.getName(), c)); |
| } |
| } else { |
| EReference childRef = null; |
| |
| for (EReference ref : targetClass.getEAllReferences()) { |
| if (ref.getName().equals(featurename)) { |
| childRef = ref; |
| break; |
| } |
| } |
| |
| if (childRef == null) { |
| return result; |
| } |
| |
| // Get the parent EClass where this childRef is defined... |
| // For instance : for the 'children' reference it will be in |
| // UIElementContainer<T extends UIElement> |
| // We must check if the selectedContainer extends |
| // UIElementContainer<XXX> and in this case childRef is XXX |
| final EClass childClass = (EClass) ModelUtils.getTypeArgument(targetClass, |
| childRef.getEGenericType()); |
| |
| // Search for descendant of ChildClass -> This result could be |
| // cached for all StringModelFragment editors instances and computed |
| // once... |
| result = new ArrayList<>(); |
| for (final InternalPackage p : Util.loadPackages()) { |
| for (EClass c : p.getAllClasses()) { |
| if (childClass.isSuperTypeOf(c) && isRelevant(c.getName())) { |
| result.add(new FeatureClass(c.getName(), c)); |
| } |
| } |
| |
| } |
| } |
| } |
| return result; |
| } |
| |
| // Fix bug 531054 -> This code could be removed when Dialog and WizardDialog |
| // will disappear from model ! |
| static private final List<String> excludeNames = Arrays.asList("Dialog", "WizardDialog"); |
| |
| // Fix bug 531054 -> This code could be removed when DIalog and WizardDialog |
| // will be definitively removed from code (after 2020). |
| private static boolean isRelevant(String className) |
| { |
| // System.out.println("Checking if " + className + " should be kept : " + |
| // !excludeNames.contains(className)); |
| return !excludeNames.contains(className); |
| } |
| |
| } |