de.gebit.integrity.ui.contentassist.IntegrityConfigurableCompletionProposal.java Source code

Java tutorial

Introduction

Here is the source code for de.gebit.integrity.ui.contentassist.IntegrityConfigurableCompletionProposal.java

Source

/*******************************************************************************
 * Copyright (c) 2013 Rene Schneider, GEBIT Solutions GmbH 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 de.gebit.integrity.ui.contentassist;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jface.internal.text.html.BrowserInformationControl;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.DefaultInformationControl;
import org.eclipse.jface.text.IInformationControl;
import org.eclipse.jface.text.IInformationControlCreator;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension3;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.xtext.ui.editor.contentassist.ConfigurableCompletionProposal;
import org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext;

import com.google.inject.Provider;

import de.gebit.integrity.dsl.CallDefinition;
import de.gebit.integrity.dsl.PackageDefinition;
import de.gebit.integrity.dsl.SuiteDefinition;
import de.gebit.integrity.dsl.TestDefinition;
import de.gebit.integrity.dsl.VariableOrConstantEntity;
import de.gebit.integrity.utils.IntegrityDSLUtil;

/**
 * A context-aware configurable completion proposal. This proposal knows its content assist context and uses this in
 * order to resolve the EObject proxy if necessary on request of additional proposal info, but only if the fully
 * resolved object is necessary to display certain content assist info later (via
 * {@link de.gebit.integrity.ui.documentation.IntegrityEObjectDocumentationProvider}).
 * 
 * @author Rene Schneider - initial API and implementation
 * 
 */
@SuppressWarnings("restriction")
public class IntegrityConfigurableCompletionProposal extends ConfigurableCompletionProposal
        implements ICompletionProposalExtension3 {

    /**
     * The context.
     */
    private ContentAssistContext context;

    /**
     * This is set if this proposal is suggesting a variable defined in a suite definition header (that is, a suite
     * parameter). These are subject to a few specialties when it comes to proposals and scopes. If I one day find out
     * how to model this construction a little more elegant, I'll do it. Until then this hack should do the job ;-).
     */
    private SuiteDefinition suiteDefiningProposedParameter;

    /**
     * Whether to use a HTML browser window to display the proposal info, if possible.
     */
    private boolean useHtmlAdditionalProposalInfo;

    /**
     * The additional proposal info object. Stored here because the superclass one is private.
     */
    private Object additionalProposalInfoObject;

    /**
     * The resolved {@link #additionalProposalInfoObject} is cached here.
     */
    private EObject resolvedAdditionalProposalInfoObject;

    /**
     * The context resource. Stored here because the superclass one is private.
     */
    private Resource proposalContextResource;

    public void setUseHtmlAdditionalProposalInfo(boolean aUseHtmlAdditionalProposalInfoFlag) {
        this.useHtmlAdditionalProposalInfo = aUseHtmlAdditionalProposalInfoFlag;
    }

    /**
     * Creates a new instance.
     * 
     * @param aReplacementString
     * @param aReplacementOffset
     * @param aReplacementLength
     * @param aCursorPosition
     * @param anImage
     * @param aDisplayString
     * @param aContextInformation
     * @param anAdditionalProposalInfo
     */
    // SUPPRESS CHECKSTYLE ParameterNumber
    public IntegrityConfigurableCompletionProposal(String aReplacementString, int aReplacementOffset,
            int aReplacementLength, int aCursorPosition, Image anImage, StyledString aDisplayString,
            IContextInformation aContextInformation, ContentAssistContext aContext) {
        super(aReplacementString, aReplacementOffset, aReplacementLength, aCursorPosition, anImage, aDisplayString,
                aContextInformation, null);
        context = aContext;
    }

    @Override
    public void setAdditionalProposalInfo(final Object anAdditionalProposalInfo) {
        Object tempAdditionalProposalInfo = anAdditionalProposalInfo;

        if (anAdditionalProposalInfo instanceof EObject && ((EObject) anAdditionalProposalInfo).eIsProxy()
                && requiresResolvingForContentAssist((EObject) anAdditionalProposalInfo)) {

            // resolve the proxy before continuing
            tempAdditionalProposalInfo = new Provider<EObject>() {

                @Override
                public EObject get() {
                    return EcoreUtil.resolve((EObject) anAdditionalProposalInfo, context.getResource());
                }
            }.get();
        }

        if (tempAdditionalProposalInfo instanceof VariableOrConstantEntity
                && ((VariableOrConstantEntity) tempAdditionalProposalInfo)
                        .eContainer() instanceof SuiteDefinition) {
            suiteDefiningProposedParameter = (SuiteDefinition) ((VariableOrConstantEntity) tempAdditionalProposalInfo)
                    .eContainer();

            // suite parameter proposals are NEVER scoped, even though XText might think so...
            String[] tempReplacementStringParts = getReplacementString().split("\\.");
            setReplacementString(tempReplacementStringParts[tempReplacementStringParts.length - 1]);
        }

        additionalProposalInfoObject = tempAdditionalProposalInfo;
        super.setAdditionalProposalInfo(tempAdditionalProposalInfo);
    }

    @Override
    public void setProposalContextResource(Resource aContextResource) {
        proposalContextResource = aContextResource;
        super.setProposalContextResource(aContextResource);
    }

    /**
     * Returns the additional proposal info object, if possible. This only returns the plain object (but attempts to
     * resolve it, if necessary).
     * 
     * @return the object or null
     */
    public EObject getAdditionalProposalInfoObject() {
        if (resolvedAdditionalProposalInfoObject == null) {
            EObject tempResult = null;
            if (additionalProposalInfoObject instanceof EObject) {
                tempResult = (EObject) additionalProposalInfoObject;
            } else {
                if (additionalProposalInfoObject instanceof Provider) {
                    Object tempObject = ((Provider<?>) additionalProposalInfoObject).get();
                    if (tempObject instanceof EObject) {
                        tempResult = (EObject) tempObject;
                    }
                }
            }
            if (tempResult != null && tempResult.eIsProxy()) {
                tempResult = EcoreUtil.resolve(tempResult, proposalContextResource);
            }

            resolvedAdditionalProposalInfoObject = tempResult;
        }

        return resolvedAdditionalProposalInfoObject;
    }

    private boolean requiresResolvingForContentAssist(EObject anObject) {
        return (anObject instanceof TestDefinition || anObject instanceof CallDefinition);
    }

    public SuiteDefinition getSuiteDefiningProposedParameter() {
        return suiteDefiningProposedParameter;
    }

    @Override
    public IInformationControlCreator getInformationControlCreator() {
        if (useHtmlAdditionalProposalInfo) {
            return new IInformationControlCreator() {

                @Override
                public IInformationControl createInformationControl(Shell aParent) {
                    if (BrowserInformationControl.isAvailable(aParent)) {
                        return new BrowserInformationControl(aParent, JFaceResources.DIALOG_FONT, true);
                    } else {
                        return new DefaultInformationControl(aParent);
                    }
                }
            };
        } else {
            // just use the default
            return super.getInformationControlCreator();
        }
    }

    /**
     * Checks whether the proposed element is in the "local" suite.
     * 
     * @return
     */
    public boolean isReferencingObjectInLocalSuite() {
        if (getAdditionalProposalInfoObject() != null) {
            SuiteDefinition tempContainingSuite = IntegrityDSLUtil.findUpstreamContainer(SuiteDefinition.class,
                    (EObject) getAdditionalProposalInfoObject());
            if (tempContainingSuite != null) {
                SuiteDefinition tempCurrentSuite = IntegrityDSLUtil.findUpstreamContainer(SuiteDefinition.class,
                        context.getCurrentModel());
                return tempCurrentSuite == tempContainingSuite;
            }
        }

        return false;
    }

    /**
     * Checks whether the proposed element is in the "local" package.
     * 
     * @return
     */
    public boolean isReferencingObjectInLocalPackage() {
        if (getAdditionalProposalInfoObject() != null) {
            PackageDefinition tempContainingPackage = IntegrityDSLUtil
                    .findUpstreamContainer(PackageDefinition.class, (EObject) getAdditionalProposalInfoObject());
            if (tempContainingPackage != null) {
                PackageDefinition tempCurrentPackage = IntegrityDSLUtil
                        .findUpstreamContainer(PackageDefinition.class, context.getCurrentModel());
                return tempCurrentPackage == tempContainingPackage;
            }
        }

        return false;
    }
}