iot.jcypher.eclipse.JCypherCompletionProposalComputer.java Source code

Java tutorial

Introduction

Here is the source code for iot.jcypher.eclipse.JCypherCompletionProposalComputer.java

Source

/************************************************************************
 * Copyright (c) 2014 IoT-Solutions e.U.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *  http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ************************************************************************/

package iot.jcypher.eclipse;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import jcypher_ext.Activator;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jdt.core.CompletionProposal;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.ui.text.java.AbstractJavaCompletionProposal;
import org.eclipse.jdt.internal.ui.text.java.FillArgumentNamesCompletionProposalCollector;
import org.eclipse.jdt.internal.ui.text.java.JavaMethodCompletionProposal;
import org.eclipse.jdt.ui.PreferenceConstants;
import org.eclipse.jdt.ui.text.java.CompletionProposalCollector;
import org.eclipse.jdt.ui.text.java.ContentAssistInvocationContext;
import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
import org.eclipse.jdt.ui.text.java.IJavaCompletionProposalComputer;
import org.eclipse.jdt.ui.text.java.JavaContentAssistInvocationContext;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Shell;

@SuppressWarnings("restriction")
public class JCypherCompletionProposalComputer implements IJavaCompletionProposalComputer {

    private static final long JAVA_CODE_ASSIST_TIMEOUT = Long.getLong("org.eclipse.jdt.ui.codeAssistTimeout", 5000) //$NON-NLS-1$
            .longValue(); // ms 

    private String fErrorMessage;
    private final IProgressMonitor fTimeoutProgressMonitor;

    public JCypherCompletionProposalComputer() {
        super();
        fTimeoutProgressMonitor = createTimeoutProgressMonitor(JAVA_CODE_ASSIST_TIMEOUT);
    }

    @Override
    public void sessionStarted() {
    }

    @Override
    public List<ICompletionProposal> computeCompletionProposals(ContentAssistInvocationContext context,
            IProgressMonitor monitor) {

        try {
            IPreferenceStore prefs = Activator.getDefault().getPreferenceStore();
            boolean enabled = prefs.getBoolean(JCypherConstants.PREF_ENABLE_COMPLETION);

            if (enabled) {
                if (context instanceof JavaContentAssistInvocationContext) {
                    JavaContentAssistInvocationContext javaContext = (JavaContentAssistInvocationContext) context;
                    return internalComputeCompletionProposals(context.getInvocationOffset(), javaContext);
                }
            }
        } catch (Throwable e) {
            // do nothing, just prevent destroying original proposals
        }
        return Collections.emptyList();
    }

    private List<ICompletionProposal> internalComputeCompletionProposals(int offset,
            JavaContentAssistInvocationContext context) {
        ICompilationUnit unit = context.getCompilationUnit();
        if (unit == null)
            return Collections.emptyList();

        ITextViewer viewer = context.getViewer();

        CompletionProposalCollector collector = createCollector(context);
        collector.setInvocationContext(context);

        collector.setAllowsRequiredProposals(CompletionProposal.FIELD_REF, CompletionProposal.TYPE_REF, true);
        collector.setAllowsRequiredProposals(CompletionProposal.FIELD_REF, CompletionProposal.TYPE_IMPORT, true);
        collector.setAllowsRequiredProposals(CompletionProposal.FIELD_REF, CompletionProposal.FIELD_IMPORT, true);

        collector.setAllowsRequiredProposals(CompletionProposal.METHOD_REF, CompletionProposal.TYPE_REF, true);
        collector.setAllowsRequiredProposals(CompletionProposal.METHOD_REF, CompletionProposal.TYPE_IMPORT, true);
        collector.setAllowsRequiredProposals(CompletionProposal.METHOD_REF, CompletionProposal.METHOD_IMPORT, true);

        collector.setAllowsRequiredProposals(CompletionProposal.CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF,
                true);

        collector.setAllowsRequiredProposals(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION,
                CompletionProposal.TYPE_REF, true);
        collector.setAllowsRequiredProposals(CompletionProposal.ANONYMOUS_CLASS_DECLARATION,
                CompletionProposal.TYPE_REF, true);

        collector.setAllowsRequiredProposals(CompletionProposal.TYPE_REF, CompletionProposal.TYPE_REF, true);

        try {
            Point selection = viewer.getSelectedRange();
            if (selection.y > 0)
                collector.setReplacementLength(selection.y);
            unit.codeComplete(offset, collector, fTimeoutProgressMonitor);
        } catch (OperationCanceledException x) {
            fErrorMessage = "Code assist took too long and is incomplete. Please close the list and type more characters";
        } catch (JavaModelException x) {
            Shell shell = viewer.getTextWidget().getShell();
            if (x.isDoesNotExist() && !unit.getJavaProject().isOnClasspath(unit))
                MessageDialog.openInformation(shell, "Cannot Perform Operation",
                        "The compilation unit is not on the build path of a Java project.");
            else
                ErrorDialog.openError(shell, "Error Accessing Compilation Unit", "Cannot access compilation unit",
                        x.getStatus());
        }

        ICompletionProposal[] javaProposals = collector.getJavaCompletionProposals();

        List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>(Arrays.asList(javaProposals));
        if (proposals.size() == 0) {
            String error = collector.getErrorMessage();
            if (error.length() > 0)
                fErrorMessage = error;
        }
        return buildJCypherProposals(proposals);
    }

    private List<ICompletionProposal> buildJCypherProposals(List<ICompletionProposal> proposals) {
        List<ICompletionProposal> ret = new ArrayList<>(proposals.size());
        List<String> classNames = new ArrayList<String>();
        List<String> classNames_ext = new ArrayList<String>();
        for (ICompletionProposal prop : proposals) {
            if (prop instanceof IJavaCompletionProposal) {
                if (prop instanceof JavaMethodCompletionProposal) {
                    JavaMethodCompletionProposal jmcp = (JavaMethodCompletionProposal) prop;
                    IJavaElement elem = jmcp.getJavaElement();
                    IJavaElement classfile = elem.getParent().getParent();
                    if (classfile.getElementType() == IJavaElement.CLASS_FILE
                            || classfile.getElementType() == IJavaElement.COMPILATION_UNIT) {
                        IJavaElement pkg = classfile.getParent();
                        if (JCypherPackages.addsToProposal(pkg.getElementName())) {
                            IJavaCompletionProposal delegate = (IJavaCompletionProposal) prop;
                            IJavaElement mthd = ((AbstractJavaCompletionProposal) delegate).getJavaElement();
                            IJavaElement clsfile = elem.getParent().getParent();
                            String className = clsfile.getElementName();
                            if (!classNames_ext.contains(className)) {
                                classNames_ext.add(className);
                                // trim className extension which can either be .class or .java
                                classNames.add(className.substring(0, className.indexOf('.')));
                            }
                            // classNames always contains (class, superClass, superSuperClass, ..)
                            int relevance = ProposalOrderConfig.INSTANCE.getRelevance(classNames.get(0),
                                    mthd.getElementName(), JCypherConstants.DEFAULT_RELEVANCE);
                            ret.add(new JCypherCompletionProposal((IJavaCompletionProposal) prop, relevance));
                        }
                    }
                }
            }
        }
        if (ret.size() > 0) {
            ProposalOrderConfig.INSTANCE.addSeparators(classNames.get(0), ret, JCypherConstants.DEFAULT_RELEVANCE);
            ret.add(CompletionSeparator.INSTANCE);
        }
        return ret;
    }

    protected CompletionProposalCollector createCollector(JavaContentAssistInvocationContext context) {
        CompletionProposalCollector collector;
        if (PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.CODEASSIST_FILL_ARGUMENT_NAMES))
            collector = new FillArgumentNamesCompletionProposalCollector(context);
        else
            collector = new CompletionProposalCollector(context.getCompilationUnit(), true);

        collector.setIgnored(CompletionProposal.METHOD_NAME_REFERENCE, false);
        collector.setIgnored(CompletionProposal.METHOD_REF, false);

        return collector;
    }

    private IProgressMonitor createTimeoutProgressMonitor(final long timeout) {
        return new IProgressMonitor() {

            private long fEndTime;

            public void beginTask(String name, int totalWork) {
                fEndTime = System.currentTimeMillis() + timeout;
            }

            public boolean isCanceled() {
                return fEndTime <= System.currentTimeMillis();
            }

            public void done() {
            }

            public void internalWorked(double work) {
            }

            public void setCanceled(boolean value) {
            }

            public void setTaskName(String name) {
            }

            public void subTask(String name) {
            }

            public void worked(int work) {
            }
        };
    }

    @Override
    public List<IContextInformation> computeContextInformation(ContentAssistInvocationContext context,
            IProgressMonitor monitor) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public String getErrorMessage() {
        return fErrorMessage;
    }

    @Override
    public void sessionEnded() {
        fErrorMessage = null;
    }

}