| /******************************************************************************** |
| * Copyright (c) 2011 Eike Stepper (Berlin, Germany) and others. |
| * |
| * All rights reserved. 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: |
| * Eike Stepper - initial API and implementation |
| ********************************************************************************/ |
| package org.eclipse.emf.ecp.spi.ui; |
| |
| import java.io.IOException; |
| import java.text.MessageFormat; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Set; |
| |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.emf.ecore.xmi.XMLResource; |
| import org.eclipse.emf.ecp.common.spi.ChildrenDescriptorCollector; |
| import org.eclipse.emf.ecp.core.ECPProject; |
| import org.eclipse.emf.ecp.core.ECPRepository; |
| import org.eclipse.emf.ecp.core.util.ECPCheckoutSource; |
| import org.eclipse.emf.ecp.core.util.ECPContainer; |
| import org.eclipse.emf.ecp.core.util.ECPProperties; |
| import org.eclipse.emf.ecp.core.util.ECPUtil; |
| import org.eclipse.emf.ecp.internal.core.util.Disposable; |
| import org.eclipse.emf.ecp.internal.core.util.Element; |
| import org.eclipse.emf.ecp.internal.ui.Activator; |
| import org.eclipse.emf.ecp.internal.ui.Messages; |
| import org.eclipse.emf.ecp.internal.ui.composites.PropertiesComposite; |
| import org.eclipse.emf.ecp.spi.core.InternalProvider; |
| import org.eclipse.emf.ecp.spi.ui.util.ECPHandlerHelper; |
| import org.eclipse.emf.edit.command.AddCommand; |
| import org.eclipse.emf.edit.command.CommandParameter; |
| import org.eclipse.emf.edit.domain.EditingDomain; |
| import org.eclipse.emf.edit.provider.ItemProviderAdapter; |
| import org.eclipse.emf.edit.ui.action.CreateChildAction; |
| import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry; |
| import org.eclipse.jface.action.Action; |
| import org.eclipse.jface.action.IContributionItem; |
| import org.eclipse.jface.action.IMenuListener; |
| import org.eclipse.jface.action.IMenuManager; |
| import org.eclipse.jface.action.MenuManager; |
| import org.eclipse.jface.resource.ImageDescriptor; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Text; |
| |
| /** |
| * @author Eike Stepper |
| * @author Eugen Neufeld |
| * @since 1.1 |
| */ |
| public class DefaultUIProvider extends Element implements UIProvider { |
| |
| private static final String PROJECT_OPEN_ICON = "icons/project_open.gif"; //$NON-NLS-1$ |
| private static final String PROJECT_CLOSED_ICON = "icons/project_closed.gif"; //$NON-NLS-1$ |
| private static final String REPOSITORY_ICON = "icons/repository.gif"; //$NON-NLS-1$ |
| private static final String UNKNOWN_PACKAGE_ICON = "icons/EPackageUnknown.gif"; //$NON-NLS-1$ |
| private static final String EPACKAGE_ICON = "icons/EPackage.gif"; //$NON-NLS-1$ |
| |
| private final Disposable disposable = new Disposable(this) { |
| @Override |
| protected void doDispose() { |
| DefaultUIProvider.this.doDispose(); |
| } |
| }; |
| |
| private String label; |
| |
| private String description; |
| |
| /** |
| * Constructor of a {@link DefaultUIProvider}. |
| * |
| * @param name the name for this {@link UIProvider} |
| */ |
| public DefaultUIProvider(String name) { |
| super(name); |
| label = name; |
| description = ""; //$NON-NLS-1$ |
| } |
| |
| /** {@inheritDoc} **/ |
| @Override |
| public String getType() { |
| return TYPE; |
| } |
| |
| /** {@inheritDoc} **/ |
| @Override |
| public InternalProvider getProvider() { |
| return (InternalProvider) ECPUtil.getECPProviderRegistry().getProvider(getName()); |
| } |
| |
| /** {@inheritDoc} **/ |
| @Override |
| public final String getLabel() { |
| return label; |
| } |
| |
| /** {@inheritDoc} **/ |
| @Override |
| public final void setLabel(String label) { |
| this.label = label; |
| } |
| |
| /** {@inheritDoc} **/ |
| @Override |
| public final String getDescription() { |
| return description; |
| } |
| |
| /** {@inheritDoc} **/ |
| @Override |
| public final void setDescription(String description) { |
| this.description = description; |
| } |
| |
| /** {@inheritDoc} **/ |
| @Override |
| public <T> T getAdapter(Object adaptable, Class<T> adapterType) { |
| return null; |
| } |
| |
| /** |
| * Returns an object which is an instance of the given class associated with this object. Returns <code>null</code> |
| * if |
| * no such object can be found. |
| * <p> |
| * This implementation of the method declared by <code>IAdaptable</code> passes the request along to the platform's |
| * adapter manager; roughly <code>Platform.getAdapterManager().getAdapter(this, adapter)</code>. Subclasses may |
| * override this method (however, if they do so, they should invoke the method on their superclass to ensure that |
| * the Platform's adapter manager is consulted). |
| * </p> |
| * |
| * @param adapterType |
| * the class to adapt to |
| * @return the adapted object or <code>null</code> |
| * @see org.eclipse.core.runtime.IAdaptable#getAdapter(Class) |
| */ |
| @Override |
| public Object getAdapter(@SuppressWarnings("rawtypes") Class adapterType) { |
| return Platform.getAdapterManager().getAdapter(this, adapterType); |
| } |
| |
| /** {@inheritDoc} **/ |
| @Override |
| public final boolean isDisposed() { |
| return disposable.isDisposed(); |
| } |
| |
| /** {@inheritDoc} **/ |
| @Override |
| public final void dispose() { |
| disposable.dispose(); |
| } |
| |
| /** {@inheritDoc} **/ |
| @Override |
| public final void addDisposeListener(DisposeListener listener) { |
| disposable.addDisposeListener(listener); |
| } |
| |
| /** {@inheritDoc} **/ |
| @Override |
| public final void removeDisposeListener(DisposeListener listener) { |
| disposable.removeDisposeListener(listener); |
| } |
| |
| /** |
| * Subclasses can override. |
| */ |
| protected void doDispose() { |
| // Subclasses can override. |
| } |
| |
| /** {@inheritDoc} **/ |
| @Override |
| public String getText(Object element) { |
| if (element instanceof Resource) { |
| final Resource resource = (Resource) element; |
| return resource.getURI().lastSegment(); |
| } |
| |
| return UIProvider.EMF_LABEL_PROVIDER.getText(element); |
| } |
| |
| /** {@inheritDoc} **/ |
| @Override |
| public Image getImage(Object element) { |
| if (element instanceof ECPProject) { |
| final ECPProject project = (ECPProject) element; |
| return project.isOpen() ? Activator.getImage(PROJECT_OPEN_ICON) : Activator.getImage(PROJECT_CLOSED_ICON); |
| } |
| |
| if (element instanceof ECPRepository) { |
| return Activator.getImage(REPOSITORY_ICON); |
| } |
| |
| return UIProvider.EMF_LABEL_PROVIDER.getImage(element); |
| } |
| |
| /** {@inheritDoc} **/ |
| // TODO is this the right place for this implementation? |
| @Override |
| public void fillContextMenu(IMenuManager manager, ECPContainer context, Object[] elements) { |
| if (elements.length == 1) { |
| final Object element = elements[0]; |
| if (context instanceof ECPProject) { |
| fillContextMenuForProject(manager, (ECPProject) context, element); |
| } |
| } |
| } |
| |
| private void fillContextMenuForProject(IMenuManager manager, final ECPProject project, Object element) { |
| if (element instanceof Resource) { |
| // TODO: does it make sense to show "all" registered EPackages in context menu of a resource? |
| // ZH: Do nothing for now. Instead, we show an "Add new Model Element..." in context menu, |
| // when element is a resource |
| // final Resource resource = (Resource) element; |
| // populateNewRoot(resource, manager); |
| } else if (element instanceof EObject) { |
| final EditingDomain domain = project.getEditingDomain(); |
| final ChildrenDescriptorCollector childrenDescriptorCollector = new ChildrenDescriptorCollector(); |
| final Collection<?> descriptors = childrenDescriptorCollector.getDescriptors((EObject) element); |
| if (descriptors != null) { |
| fillContextMenuWithDescriptors(manager, descriptors, domain, element, project); |
| } |
| } else if (element instanceof ItemProviderAdapter |
| && ((ItemProviderAdapter) element).getTarget() instanceof EObject) { |
| final EditingDomain domain = project.getEditingDomain(); |
| final ItemProviderAdapter adapter = (ItemProviderAdapter) element; |
| element = adapter.getTarget(); |
| final Collection<?> descriptors = adapter.getNewChildDescriptors(element, domain, null); |
| fillContextMenuWithDescriptors(manager, descriptors, domain, element, project); |
| } |
| } |
| |
| /** |
| * @param descriptors |
| */ |
| private void fillContextMenuWithDescriptors(IMenuManager manager, Collection<?> descriptors, |
| final EditingDomain domain, Object object, final ECPProject project) { |
| if (!EObject.class.isInstance(object)) { |
| return; |
| } |
| final EObject eObject = (EObject) object; |
| for (final Object descriptor : descriptors) { |
| if (!CommandParameter.class.isInstance(descriptor)) { |
| continue; |
| } |
| final CommandParameter cp = (CommandParameter) descriptor; |
| if (cp.getEReference() == null) { |
| continue; |
| } |
| if (!cp.getEReference().isMany() && eObject.eIsSet(cp.getEStructuralFeature())) { |
| continue; |
| } else if (cp.getEReference().isMany() && cp.getEReference().getUpperBound() != -1 |
| && cp.getEReference().getUpperBound() <= ((List<?>) eObject.eGet(cp.getEReference())).size()) { |
| continue; |
| } |
| // TODO: Temporal hack to remove all other elements of the view model for 1.1.M1 |
| // final EObject objectToCreate = cp.getEValue(); |
| // if (objectToCreate.eClass().getEPackage().getNsURI().equals("http://org/eclipse/emf/ecp/view/model")) { |
| // if (!objectToCreate.eClass().getName().equals("Control")) { |
| // continue; |
| // } |
| // } |
| // if |
| // (objectToCreate.eClass().getEPackage().getNsURI().equals("http://org/eclipse/emf/ecp/view/rule/model")) { |
| // continue; |
| // } |
| |
| // TODO needed? |
| // if (!cp.getEReference().isMany() || !cp.getEReference().isContainment()) { |
| // continue; |
| // } |
| manager.add(new CreateChildAction(domain, new StructuredSelection(eObject), descriptor) { |
| @Override |
| public void run() { |
| super.run(); |
| |
| final EReference reference = ((CommandParameter) descriptor).getEReference(); |
| if (!reference.isContainment()) { |
| domain.getCommandStack().execute( |
| AddCommand.create(domain, eObject.eContainer(), null, cp.getEValue())); |
| } |
| // try { |
| // TODO what is correct |
| domain.getCommandStack().execute(AddCommand.create(domain, eObject, reference, cp.getEValue())); |
| // object.eResource().save(null); |
| ECPHandlerHelper.openModelElement(cp.getEValue(), project); |
| // } catch (IOException ex) { |
| // Activator.log(ex); |
| // } |
| } |
| }); |
| } |
| } |
| |
| /** {@inheritDoc} **/ |
| @Override |
| public Control createAddRepositoryUI(Composite parent, ECPProperties repositoryProperties, Text repositoryNameText, |
| Text repositoryLabelText, Text repositoryDescriptionText) { |
| return new PropertiesComposite(parent, true, repositoryProperties); |
| } |
| |
| /** {@inheritDoc} **/ |
| @Override |
| public Control createCheckoutUI(Composite parent, ECPCheckoutSource checkoutSource, |
| ECPProperties projectProperties) { |
| return new PropertiesComposite(parent, true, projectProperties); |
| } |
| |
| /** {@inheritDoc} **/ |
| @Override |
| public Control createNewProjectUI(Composite parent, CompositeStateObserver observer, |
| ECPProperties projectProperties) { |
| return null; |
| } |
| |
| protected boolean populateNewRoot(Resource resource, IMenuManager manager) { |
| boolean populated = false; |
| final EPackage.Registry packageRegistry = EPackage.Registry.INSTANCE; |
| for (final Map.Entry<String, Object> entry : getSortedRegistryEntries(packageRegistry)) { |
| final IContributionItem item = populateSubMenu(resource, entry.getKey(), entry.getValue(), packageRegistry); |
| if (item != null) { |
| manager.add(item); |
| populated = true; |
| } |
| } |
| |
| return populated; |
| } |
| |
| private static IContributionItem populateSubMenu(final Resource resource, String nsURI, Object value, |
| final EPackage.Registry packageRegistry) { |
| if (value instanceof EPackage) { |
| final EPackage ePackage = (EPackage) value; |
| |
| final ImageDescriptor imageDescriptor = Activator.getImageDescriptor(EPACKAGE_ICON); |
| final MenuManager submenuManager = new MenuManager(nsURI, imageDescriptor, nsURI); |
| populateSubMenu(resource, ePackage, submenuManager); |
| return submenuManager; |
| } |
| |
| final ImageDescriptor imageDescriptor = Activator.getImageDescriptor(UNKNOWN_PACKAGE_ICON); |
| final MenuManager submenuManager = new MenuManager(nsURI, imageDescriptor, nsURI); |
| submenuManager.setRemoveAllWhenShown(true); |
| submenuManager.add(new Action(Messages.DefaultUIProvider_Calculating) { |
| }); |
| |
| submenuManager.addMenuListener(new IMenuListener() { |
| @Override |
| public void menuAboutToShow(IMenuManager manager) { |
| final String nsURI = submenuManager.getMenuText(); |
| final EPackage ePackage = packageRegistry.getEPackage(nsURI); |
| |
| if (ePackage != null) { |
| populateSubMenu(resource, ePackage, submenuManager); |
| } else { |
| Activator.log(MessageFormat.format(Messages.DefaultUIProvider_CantFindInPackageRegistry, nsURI)); |
| } |
| } |
| }); |
| |
| return submenuManager; |
| } |
| |
| private static void populateSubMenu(final Resource resource, EPackage ePackage, final MenuManager submenuManager) { |
| final List<EObject> objects = new ArrayList<EObject>(); |
| for (final EClassifier eClassifier : ePackage.getEClassifiers()) { |
| if (eClassifier instanceof EClass) { |
| final EClass eClass = (EClass) eClassifier; |
| if (!eClass.isAbstract() && !eClass.isInterface()) { |
| objects.add(EcoreUtil.create(eClass)); |
| } |
| } |
| } |
| |
| if (!objects.isEmpty()) { |
| Collections.sort(objects, new Comparator<EObject>() { |
| @Override |
| public int compare(EObject o1, EObject o2) { |
| return o1.eClass().getName().compareTo(o2.eClass().getName()); |
| } |
| }); |
| |
| for (final EObject object : objects) { |
| final String text = object.eClass().getName(); |
| final Image image = UIProvider.EMF_LABEL_PROVIDER.getImage(object); |
| final ImageDescriptor imageDescriptor = ExtendedImageRegistry.getInstance().getImageDescriptor(image); |
| |
| final Action action = new Action(text, imageDescriptor) { |
| @Override |
| public void run() { |
| resource.getContents().add(object); |
| |
| try { |
| resource.save(Collections.singletonMap(XMLResource.OPTION_ENCODING, "UTF-8")); //$NON-NLS-1$ |
| } catch (final IOException ex) { |
| Activator.log(ex); |
| } |
| } |
| }; |
| |
| submenuManager.add(action); |
| } |
| } |
| } |
| |
| private static Map.Entry<String, Object>[] getSortedRegistryEntries(EPackage.Registry packageRegistry) { |
| final Set<Map.Entry<String, Object>> entries = packageRegistry.entrySet(); |
| @SuppressWarnings("unchecked") |
| final Map.Entry<String, Object>[] array = entries.toArray(new Entry[entries.size()]); |
| Arrays.sort(array, new Comparator<Map.Entry<String, Object>>() { |
| @Override |
| public int compare(Map.Entry<String, Object> o1, Map.Entry<String, Object> o2) { |
| return o1.getKey().compareTo(o2.getKey()); |
| } |
| }); |
| |
| return array; |
| } |
| } |