org.summer.ss.ide.hyperlinking.SsHyperlinkHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.summer.ss.ide.hyperlinking.SsHyperlinkHelper.java

Source

/*******************************************************************************
 * Copyright (c) 2011 itemis AG (http://www.itemis.eu) and others.
 * 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
 *******************************************************************************/
package org.summer.ss.ide.hyperlinking;

import java.util.List;
import java.util.Set;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.hyperlink.IHyperlink;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.ui.editor.hyperlinking.IHyperlinkAcceptor;
import org.eclipse.xtext.util.TextRegion;
import org.summer.dsl.model.xbase.XAbstractFeatureCall;
import org.summer.dsl.model.xbase.XConstructorCall;
import org.summer.dsl.xbase.jvmmodel.IJvmModelAssociations;
import org.summer.dsl.xbase.typesystem.IBatchTypeResolver;
import org.summer.dsl.xbase.typesystem.computation.IAmbiguousLinkingCandidate;
import org.summer.dsl.xbase.typesystem.computation.IConstructorLinkingCandidate;
import org.summer.dsl.xbase.typesystem.computation.IFeatureLinkingCandidate;
import org.summer.dsl.xbase.typesystem.computation.ILinkingCandidate;
import org.summer.dsl.xbase.typesystem.computation.ISuspiciouslyOverloadedCandidate;
import org.summer.dsl.xbase.ui.navigation.TypeLiteralAwareHyperlinkHelper;

import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.inject.Inject;

/**
 * Customized hyperlinker for Xtend source files.
 * 
 * First and foremost, it redirects hyperlinks to the source elements 
 * if the referenced target is an inferred element. That means, all
 * contributing dispatch methods are available on hyperlink requests.
 * 
 * This implementation also provides hyperlinks to all ambiguous candidates if
 * a feature or constructor call was resolved to multiple equally valid
 * features.
 * 
 * @author Jan Koehnlein - Initial contribution and API
 * @author Sebastian Zarnekow - Navigation to all ambiguous candidates.
 */
public class SsHyperlinkHelper extends TypeLiteralAwareHyperlinkHelper {

    @Inject
    private IJvmModelAssociations associations;

    @Inject
    private IBatchTypeResolver typeResolver;

    /**
     * This redirects the hyperlinks to all source elements of an inferred element.
     */
    @Override
    public void createHyperlinksTo(XtextResource from, Region region, EObject to, IHyperlinkAcceptor acceptor) {
        Set<EObject> sourceElements = associations.getSourceElements(to);
        if (sourceElements.isEmpty()) {
            super.createHyperlinksTo(from, region, to, acceptor);
        } else {
            for (EObject sourceElement : sourceElements) {
                super.createHyperlinksTo(from, region, sourceElement, acceptor);
            }
        }
    }

    /**
     * If multiple links are requested, all ambiguous candidates are provided for feature
     * and constructor calls. 
     */
    @Override
    public IHyperlink[] createHyperlinksByOffset(XtextResource resource, int offset,
            boolean createMultipleHyperlinks) {
        if (!createMultipleHyperlinks) {
            return super.createHyperlinksByOffset(resource, offset, createMultipleHyperlinks);
        }
        List<IHyperlink> links = Lists.newArrayList();
        IHyperlinkAcceptor acceptor = new HyperlinkAcceptor(links);

        createMultipleHyperlinksByOffset(resource, offset, acceptor);
        if (!links.isEmpty())
            return Iterables.toArray(links, IHyperlink.class);
        return null;
    }

    protected void createMultipleHyperlinksByOffset(XtextResource resource, int offset,
            IHyperlinkAcceptor acceptor) {
        INode crossRefNode = getEObjectAtOffsetHelper().getCrossReferenceNode(resource, new TextRegion(offset, 0));
        if (crossRefNode == null)
            return;
        EObject crossLinkedEObject = getEObjectAtOffsetHelper().getCrossReferencedElement(crossRefNode);
        if (crossLinkedEObject != null && !crossLinkedEObject.eIsProxy()) {
            EObject containedElementAt = getEObjectAtOffsetHelper().resolveContainedElementAt(resource, offset);
            if (containedElementAt instanceof XAbstractFeatureCall) {
                XAbstractFeatureCall casted = (XAbstractFeatureCall) containedElementAt;
                if (casted.getFeature() == crossLinkedEObject) {
                    IFeatureLinkingCandidate candidate = typeResolver.resolveTypes(casted)
                            .getLinkingCandidate(casted);
                    if (candidate instanceof IAmbiguousLinkingCandidate) {
                        createMultipleLinks(resource, crossRefNode,
                                ((IAmbiguousLinkingCandidate) candidate).getAlternatives(), acceptor);
                    } else if (candidate instanceof ISuspiciouslyOverloadedCandidate) {
                        ISuspiciouslyOverloadedCandidate castedCandidate = (ISuspiciouslyOverloadedCandidate) candidate;
                        createMultipleLinks(resource, crossRefNode,
                                Lists.newArrayList(castedCandidate.getChosenCandidate(),
                                        castedCandidate.getRejectedCandidate()),
                                acceptor);
                    } else {
                        createHyperlinksTo(resource, crossRefNode, crossLinkedEObject, acceptor);
                    }
                }
            } else if (containedElementAt instanceof XConstructorCall) {
                XConstructorCall casted = (XConstructorCall) containedElementAt;
                if (casted.getConstructor() == crossLinkedEObject) {
                    IConstructorLinkingCandidate candidate = typeResolver.resolveTypes(casted)
                            .getLinkingCandidate(casted);
                    if (candidate instanceof IAmbiguousLinkingCandidate) {
                        createMultipleLinks(resource, crossRefNode,
                                ((IAmbiguousLinkingCandidate) candidate).getAlternatives(), acceptor);
                    } else {
                        createHyperlinksTo(resource, crossRefNode, crossLinkedEObject, acceptor);
                    }
                }
            } else {
                createHyperlinksTo(resource, crossRefNode, crossLinkedEObject, acceptor);
            }
        }
    }

    private void createMultipleLinks(XtextResource resource, INode crossRefNode,
            List<? extends ILinkingCandidate> alternatives, IHyperlinkAcceptor acceptor) {
        for (ILinkingCandidate alternative : alternatives) {
            createHyperlinksTo(resource, crossRefNode, alternative.getFeature(), acceptor);
        }
    }
}