blob: 6f3025fb943e812756ba948c6e60dcd93db6d4d8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2011 Mia-Software.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Nicolas Bros (Mia-Software) - initial API and implementation
*******************************************************************************/
package org.eclipse.gmt.modisco.infra.browser.custom.editor.editors;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.gmt.modisco.infra.browser.custom.AttributeView;
import org.eclipse.gmt.modisco.infra.browser.custom.CustomView;
import org.eclipse.gmt.modisco.infra.browser.custom.CustomViewFeature;
import org.eclipse.gmt.modisco.infra.browser.custom.MetamodelView;
import org.eclipse.gmt.modisco.infra.browser.custom.ReferenceView;
import org.eclipse.gmt.modisco.infra.browser.custom.TypeView;
import org.eclipse.gmt.modisco.infra.browser.uicore.internal.model.AttributeItem;
import org.eclipse.gmt.modisco.infra.browser.uicore.internal.model.LinkItem;
import org.eclipse.gmt.modisco.infra.browser.uicore.internal.model.ModelElementItem;
import org.eclipse.gmt.modisco.infra.browser.uicore.internal.util.ImageProvider;
import org.eclipse.gmt.modisco.infra.common.core.internal.utils.ModelUtils;
import org.eclipse.gmt.modisco.infra.facet.Facet;
import org.eclipse.jface.resource.FontDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.IColorProvider;
import org.eclipse.jface.viewers.IFontProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
/**
* A TreeViewer displaying a list of selectable meta-classes. Display options are handled in
* {@link MetaclassViewConfiguration}, which are made accessible to the user through the
* {@link MetaclassViewToolBar}.
*/
public class MetaclassViewer {
private final TreeViewer treeViewer;
private final MetaclassViewConfiguration metaclassViewConfiguration;
private MetamodelView fMetamodelView;
/** Wraps an EAttribute and adds the containing class */
public static class Attribute {
/** The class on which the attribute will be customized */
private final EClass eClass;
private final EAttribute eAttribute;
public Attribute(final EClass eClass, final EAttribute eAttribute) {
this.eClass = eClass;
this.eAttribute = eAttribute;
}
public EClass getEClass() {
return this.eClass;
}
public EAttribute getEAttribute() {
return this.eAttribute;
}
@Override
public boolean equals(final Object obj) {
if (obj instanceof Attribute) {
final Attribute other = (Attribute) obj;
return this.eClass == other.eClass && this.eAttribute == other.eAttribute;
}
return false;
}
@Override
public int hashCode() {
final int hashPrime1 = 13;
final int hashPrime2 = 47;
return this.eClass.hashCode() * hashPrime2 + this.eAttribute.hashCode() + hashPrime1;
}
}
/** Wraps an EReference and adds the containing class */
public static class Reference {
/** The class on which the reference will be customized */
private final EClass eClass;
private final EReference eReference;
public Reference(final EClass eClass, final EReference eReference) {
this.eClass = eClass;
this.eReference = eReference;
}
public EClass getEClass() {
return this.eClass;
}
public EReference getEReference() {
return this.eReference;
}
@Override
public boolean equals(final Object obj) {
if (obj instanceof Reference) {
final Reference other = (Reference) obj;
return this.eClass == other.eClass && this.eReference == other.eReference;
}
return false;
}
@Override
public int hashCode() {
final int hashPrime1 = 13;
final int hashPrime2 = 47;
return this.eClass.hashCode() * hashPrime2 + this.eReference.hashCode() + hashPrime1;
}
}
/**
* @param parent
* the composite in which this viewer must be created
* @param metaclassViewConfiguration
* the configuration of the metaclass viewer
* @param metamodelView
* used to know whether an element is customized or not
*/
public MetaclassViewer(final Composite parent,
final MetaclassViewConfiguration metaclassViewConfiguration,
final MetamodelView metamodelView) {
this.metaclassViewConfiguration = metaclassViewConfiguration;
this.fMetamodelView = metamodelView;
this.treeViewer = new TreeViewer(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER
| SWT.SINGLE);
initViewer();
}
public void setInput(final Object input) {
this.treeViewer.setInput(input);
}
protected class MetaclassContentProvider implements ITreeContentProvider {
public Object[] getElements(final Object inputElement) {
// Resource : metamodel
if (inputElement instanceof Resource) {
final Resource resource = (Resource) inputElement;
final TreeIterator<EObject> allContents = resource.getAllContents();
final List<EClass> metaclasses = new ArrayList<EClass>();
while (allContents.hasNext()) {
final EObject eObject = allContents.next();
if (eObject instanceof EClass) {
final EClass eClass = (EClass) eObject;
metaclasses.add(eClass);
}
}
return metaclasses.toArray();
}
return new Object[0];
}
public void dispose() {
// nothing
}
public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) {
// nothing
}
public Object[] getChildren(final Object parentElement) {
if (parentElement instanceof EClass) {
final EClass eClass = (EClass) parentElement;
final EList<EAttribute> attributes;
final EList<EReference> references;
if (eClass instanceof Facet) {
Facet facet = (Facet) eClass;
// XXX also super-facets attributes?
attributes = facet.getEAttributes();
// XXX also super-facets references?
references = facet.getEReferences();
} else {
attributes = eClass.getEAllAttributes();
references = eClass.getEAllReferences();
}
/*
* The attributes and references are wrapped with added information about their
* class. This is necessary because a feature view can be defined for a feature of a
* subclass.
*/
final List<Object> children = new ArrayList<Object>();
for (final EAttribute attribute : attributes) {
if (!attribute.isDerived()
|| MetaclassViewer.this.metaclassViewConfiguration.isShowDerivedLinks()) {
children.add(new Attribute(eClass, attribute));
}
}
for (final EReference reference : references) {
if (!reference.isDerived()
|| MetaclassViewer.this.metaclassViewConfiguration.isShowDerivedLinks()) {
children.add(new Reference(eClass, reference));
}
}
return children.toArray();
}
return new Object[0];
}
public Object getParent(final Object element) {
if (element instanceof Reference) {
return ((Reference) element).getEClass();
}
if (element instanceof Attribute) {
return ((Attribute) element).getEClass();
}
return null;
}
public boolean hasChildren(final Object element) {
if (element instanceof EClass) {
return getChildren(element).length > 0;
}
return false;
}
}
protected class MetaclassLabelProvider extends LabelProvider implements IColorProvider,
IFontProvider {
private final RGB rgbGray = new RGB(128, 128, 128);
private final Color colorGrayedOut;
private final Font boldFont;
public MetaclassLabelProvider() {
this.colorGrayedOut = new Color(Display.getDefault(), this.rgbGray);
FontDescriptor fontDescriptor = JFaceResources.getDefaultFontDescriptor();
fontDescriptor = fontDescriptor.setStyle(SWT.BOLD);
this.boldFont = fontDescriptor.createFont(Display.getDefault());
}
@Override
public String getText(final Object element) {
if (element instanceof EClass) {
final EClass eClass = (EClass) element;
return getClassDisplayName(eClass);
}
if (element instanceof Reference) {
final EReference reference = ((Reference) element).getEReference();
final boolean showMultiplicity = MetaclassViewer.this.metaclassViewConfiguration
.isShowMultiplicity();
return LinkItem.getStaticText(reference, showMultiplicity, false, null);
}
if (element instanceof Attribute) {
final EAttribute attribute = ((Attribute) element).getEAttribute();
final boolean showMultiplicity = MetaclassViewer.this.metaclassViewConfiguration
.isShowMultiplicity();
return AttributeItem.getStaticText(attribute, showMultiplicity, null);
}
return element.toString();
}
@Override
public Image getImage(final Object element) {
if (element instanceof EClass) {
return ImageProvider.getInstance().getEClassIcon();
}
if (element instanceof Reference) {
final EReference reference = ((Reference) element).getEReference();
return LinkItem.getImageFor(reference);
}
if (element instanceof Attribute) {
return ImageProvider.getInstance().getAttributeIcon();
}
return null;
}
@Override
public void dispose() {
this.colorGrayedOut.dispose();
this.boldFont.dispose();
super.dispose();
}
public Color getBackground(final Object element) {
return null;
}
public Color getForeground(final Object element) {
if (isCustomized(element)) {
return null;
}
// gray if not customized
return this.colorGrayedOut;
}
private boolean isCustomized(final Object element) {
final MetamodelView metamodelView = MetaclassViewer.this.fMetamodelView;
if (element instanceof EClass) {
final EClass eClass = (EClass) element;
for (final TypeView typeView : metamodelView.getTypes()) {
if (typeView.getMetaclassName().equals(
ModelUtils.getMetaclassQualifiedName(eClass))) {
if (containsInformation(typeView)) {
return true;
}
// test contained attributes and references
final EList<AttributeView> attributes = typeView.getAttributes();
for (final AttributeView attributeView : attributes) {
if (containsInformation(attributeView)) {
return true;
}
}
final EList<ReferenceView> references = typeView.getReferences();
for (final ReferenceView referenceView : references) {
if (containsInformation(referenceView)) {
return true;
}
}
}
}
return false;
} else if (element instanceof Reference) {
final Reference reference = (Reference) element;
final EReference eReference = reference.getEReference();
final EClass eClass = reference.getEClass();
for (final TypeView typeView : metamodelView.getTypes()) {
if (typeView.getMetaclassName().equals(
ModelUtils.getMetaclassQualifiedName(eClass))) {
final EList<ReferenceView> references = typeView.getReferences();
for (final ReferenceView referenceView : references) {
if (referenceView.getReferenceName().equals(eReference.getName())) {
return containsInformation(referenceView);
}
}
}
}
} else if (element instanceof Attribute) {
final Attribute attribute = (Attribute) element;
final EAttribute eAttribute = attribute.getEAttribute();
final EClass eClass = attribute.getEClass();
for (final TypeView typeView : metamodelView.getTypes()) {
if (typeView.getMetaclassName().equals(
ModelUtils.getMetaclassQualifiedName(eClass))) {
final EList<AttributeView> attributes = typeView.getAttributes();
for (final AttributeView attributeView : attributes) {
if (attributeView.getAttributeName().equals(eAttribute.getName())) {
return containsInformation(attributeView);
}
}
}
}
}
return false;
}
private boolean containsInformation(final CustomView customView) {
final EList<CustomViewFeature> customizedFeatures = customView.getCustomizedFeatures();
for (final CustomViewFeature customViewFeature : customizedFeatures) {
if (customViewFeature.getDefaultValue() != null
|| customViewFeature.getValueCases().size() > 0) {
return true;
}
}
return false;
}
public Font getFont(final Object element) {
if (isCustomized(element)) {
return this.boldFont;
}
return null;
}
}
/** Initialize the viewer with a content and label provider */
private void initViewer() {
this.treeViewer.setContentProvider(new MetaclassContentProvider());
final MetaclassLabelProvider labelProvider = new MetaclassLabelProvider();
this.treeViewer.setLabelProvider(labelProvider);
this.treeViewer.setComparator(new ViewerComparator() {
@Override
public int compare(final Viewer viewer, final Object e1, final Object e2) {
if (e1 instanceof EClass && e2 instanceof EClass) {
final EClass eClass1 = (EClass) e1;
final EClass eClass2 = (EClass) e2;
return safeCompare(getClassDisplayName(eClass1), getClassDisplayName(eClass2));
}
if (e1 instanceof Attribute && e2 instanceof Reference) {
return -1;
}
if (e1 instanceof Reference && e2 instanceof Attribute) {
return 1;
}
if (e1 instanceof Attribute && e2 instanceof Attribute) {
final EAttribute attribute1 = ((Attribute) e1).getEAttribute();
final EAttribute attribute2 = ((Attribute) e2).getEAttribute();
final int derived1;
if (attribute1.isDerived()) {
derived1 = 1;
} else {
derived1 = 0;
}
final int derived2;
if (attribute2.isDerived()) {
derived2 = 1;
} else {
derived2 = 0;
}
final int derivedDiff = derived1 - derived2;
if (derivedDiff != 0) {
return derivedDiff;
}
return safeCompare(attribute1.getName(), attribute2.getName());
}
if (e1 instanceof Reference && e2 instanceof Reference) {
final EReference ref1 = ((Reference) e1).getEReference();
final EReference ref2 = ((Reference) e2).getEReference();
if (MetaclassViewer.this.metaclassViewConfiguration.isSortLinksByType()) {
final int rank1 = ModelElementItem.getReferenceRank(ref1);
final int rank2 = ModelElementItem.getReferenceRank(ref2);
final int diffRank = rank1 - rank2;
if (diffRank != 0) {
return diffRank;
}
}
if (MetaclassViewer.this.metaclassViewConfiguration.isSortLinks()) {
return safeCompare(ref1.getName(), ref2.getName());
}
return 0;
}
return 0;
}
private int safeCompare(final String name1, final String name2) {
if (name1 == null) {
return -1;
}
return name1.compareTo(name2);
}
});
}
public String getClassDisplayName(final EClass eClass) {
if (this.metaclassViewConfiguration.isShowMetaclassesFullQualifiedNames()) {
return ModelUtils.getMetaclassQualifiedName(eClass);
}
return eClass.getName();
}
public void refresh() {
if (!this.treeViewer.getTree().isDisposed()) {
try {
this.treeViewer.getTree().setRedraw(false);
this.treeViewer.refresh();
} finally {
this.treeViewer.getTree().setRedraw(true);
}
}
}
public void addSelectionChangedListener(final ISelectionChangedListener selectionChangedListener) {
this.treeViewer.addSelectionChangedListener(selectionChangedListener);
}
public void clearSelection() {
this.treeViewer.setSelection(null);
}
public ISelection getSelection() {
return this.treeViewer.getSelection();
}
public Viewer getViewer() {
return this.treeViewer;
}
public void select(final CustomView customView) {
Object element = findTreeElement(customView);
if (element != null) {
this.treeViewer.setSelection(new StructuredSelection(element), true);
}
}
public Object findTreeElement(final CustomView customView) {
Object input = this.treeViewer.getInput();
ITreeContentProvider contentProvider = (ITreeContentProvider) this.treeViewer
.getContentProvider();
Object[] elements = contentProvider.getElements(input);
for (Object element : elements) {
EClass eClass = (EClass) element;
String qualifiedName = ModelUtils.getMetaclassQualifiedName(eClass);
if (customView instanceof TypeView) {
TypeView typeView = (TypeView) customView;
if (qualifiedName.equals(typeView.getMetaclassName())) {
return eClass;
}
} else if (customView instanceof AttributeView) {
AttributeView attributeView = (AttributeView) customView;
if (qualifiedName.equals(attributeView.getType().getMetaclassName())) {
Object[] children = contentProvider.getChildren(eClass);
for (Object child : children) {
if (child instanceof Attribute) {
Attribute attribute = (Attribute) child;
if (attribute.getEAttribute().getName()
.equals(attributeView.getAttributeName())) {
return attribute;
}
}
}
return eClass;
}
} else if (customView instanceof ReferenceView) {
ReferenceView referenceView = (ReferenceView) customView;
if (qualifiedName.equals(referenceView.getType().getMetaclassName())) {
Object[] children = contentProvider.getChildren(eClass);
for (Object child : children) {
if (child instanceof Reference) {
Reference reference = (Reference) child;
if (reference.getEReference().getName()
.equals(referenceView.getReferenceName())) {
return reference;
}
}
}
return eClass;
}
}
}
return null;
}
public void setMetamodelView(final MetamodelView metamodelView) {
this.fMetamodelView = metamodelView;
}
}