Package org.eclipse.php.internal.ui.text.correction

Source Code of org.eclipse.php.internal.ui.text.correction.PHPCorrectionProcessor$SafeCorrectionCollector

/*******************************************************************************
* Copyright (c) 2009 IBM Corporation 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
*
* Contributors:
*     IBM Corporation - initial API and implementation
*     Zend Technologies
*******************************************************************************/
package org.eclipse.php.internal.ui.text.correction;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Scanner;

import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.*;
import org.eclipse.dltk.compiler.problem.IProblemIdentifier;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.ui.DLTKUIPlugin;
import org.eclipse.dltk.ui.editor.IScriptAnnotation;
import org.eclipse.dltk.ui.text.IScriptCorrectionContext;
import org.eclipse.dltk.ui.text.IScriptCorrectionProcessor;
import org.eclipse.dltk.ui.text.MarkerResolutionProposal;
import org.eclipse.dltk.ui.text.completion.CompletionProposalComparator;
import org.eclipse.dltk.ui.text.completion.IScriptCompletionProposal;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.contentassist.ContentAssistEvent;
import org.eclipse.jface.text.contentassist.ICompletionListener;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.ltk.core.refactoring.NullChange;
import org.eclipse.osgi.util.NLS;
import org.eclipse.php.internal.ui.PHPUiPlugin;
import org.eclipse.php.internal.ui.editor.PHPStructuredTextViewer;
import org.eclipse.php.internal.ui.text.correction.proposals.ChangeCorrectionProposal;
import org.eclipse.php.ui.editor.SharedASTProvider;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IMarkerHelpRegistry;
import org.eclipse.ui.IMarkerResolution;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.keys.IBindingService;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.eclipse.ui.texteditor.SimpleMarkerAnnotation;

public class PHPCorrectionProcessor implements
    org.eclipse.jface.text.quickassist.IQuickAssistProcessor,
    IScriptCorrectionProcessor {

  private static final String QUICKFIX_PROCESSOR_CONTRIBUTION_ID = "quickFixProcessors"; //$NON-NLS-1$
  private static final String QUICKASSIST_PROCESSOR_CONTRIBUTION_ID = "quickAssistProcessors"; //$NON-NLS-1$

  private static ContributedProcessorDescriptor[] fgContributedAssistProcessors = null;
  private static ContributedProcessorDescriptor[] fgContributedCorrectionProcessors = null;

  private static ContributedProcessorDescriptor[] getProcessorDescriptors(
      String contributionId, boolean testMarkerTypes) {
    IConfigurationElement[] elements = Platform.getExtensionRegistry()
        .getConfigurationElementsFor(PHPUiPlugin.ID, contributionId);
    ArrayList res = new ArrayList(elements.length);

    for (int i = 0; i < elements.length; i++) {
      ContributedProcessorDescriptor desc = new ContributedProcessorDescriptor(
          elements[i], testMarkerTypes);
      IStatus status = desc.checkSyntax();
      if (status.isOK()) {
        res.add(desc);
      } else {
        PHPUiPlugin.log(status);
      }
    }
    return (ContributedProcessorDescriptor[]) res
        .toArray(new ContributedProcessorDescriptor[res.size()]);
  }

  private static ContributedProcessorDescriptor[] getCorrectionProcessors() {
    if (fgContributedCorrectionProcessors == null) {
      fgContributedCorrectionProcessors = getProcessorDescriptors(
          QUICKFIX_PROCESSOR_CONTRIBUTION_ID, true);
    }
    return fgContributedCorrectionProcessors;
  }

  private static ContributedProcessorDescriptor[] getAssistProcessors() {
    if (fgContributedAssistProcessors == null) {
      fgContributedAssistProcessors = getProcessorDescriptors(
          QUICKASSIST_PROCESSOR_CONTRIBUTION_ID, false);
    }
    return fgContributedAssistProcessors;
  }

  public static boolean hasCorrections(ISourceModule cu,
      IProblemIdentifier identifier, String markerType) {
    ContributedProcessorDescriptor[] processors = getCorrectionProcessors();
    SafeHasCorrections collector = new SafeHasCorrections(cu, identifier);
    for (int i = 0; i < processors.length; i++) {
      if (processors[i].canHandleMarkerType(markerType)) {
        collector.process(processors[i]);
        if (collector.hasCorrections()) {
          return true;
        }
      }
    }
    return false;
  }

  public static boolean isQuickFixableType(Annotation annotation) {
    return (annotation instanceof IScriptAnnotation || annotation instanceof SimpleMarkerAnnotation)
        && !annotation.isMarkedDeleted();
  }

  public static boolean hasCorrections(Annotation annotation) {
    if (annotation instanceof IScriptAnnotation) {
      IScriptAnnotation javaAnnotation = (IScriptAnnotation) annotation;
      if (javaAnnotation.getId() != null) {
        ISourceModule cu = javaAnnotation.getSourceModule();
        return hasCorrections(cu, javaAnnotation.getId(),
            javaAnnotation.getMarkerType());
      }

    }
    if (annotation instanceof SimpleMarkerAnnotation) {
      return hasCorrections(((SimpleMarkerAnnotation) annotation)
          .getMarker());
    }
    return false;
  }

  private static boolean hasCorrections(IMarker marker) {
    if (marker == null || !marker.exists())
      return false;

    IMarkerHelpRegistry registry = IDE.getMarkerHelpRegistry();
    return registry != null && registry.hasResolutions(marker);
  }

  public static boolean hasAssists(IInvocationContext context) {
    ContributedProcessorDescriptor[] processors = getAssistProcessors();
    SafeHasAssist collector = new SafeHasAssist(context);

    for (int i = 0; i < processors.length; i++) {
      collector.process(processors[i]);
      if (collector.hasAssists()) {
        return true;
      }
    }
    return false;
  }

  private PHPCorrectionAssistant fAssistant;
  private String fErrorMessage;

  /*
   * Constructor for JavaCorrectionProcessor.
   */
  public PHPCorrectionProcessor() {
  }

  protected void initAssistant(PHPStructuredTextViewer textViewer) {
    if (fAssistant != null) {
      return;
    }

    fAssistant = (PHPCorrectionAssistant) textViewer
        .getQuickAssistAssistant();

    fAssistant.addCompletionListener(new ICompletionListener() {

      public void assistSessionEnded(ContentAssistEvent event) {
        fAssistant.setStatusLineVisible(false);
      }

      public void assistSessionStarted(ContentAssistEvent event) {
        fAssistant.setStatusLineVisible(true);
        fAssistant.setStatusMessage(getJumpHintStatusLineMessage());
      }

      public void selectionChanged(ICompletionProposal proposal,
          boolean smartToggle) {
        if (proposal instanceof IStatusLineProposal) {
          IStatusLineProposal statusLineProposal = (IStatusLineProposal) proposal;
          String message = statusLineProposal.getStatusMessage();
          if (message != null) {
            fAssistant.setStatusMessage(message);
            return;
          }
        }
        fAssistant.setStatusMessage(getJumpHintStatusLineMessage());
      }

      private String getJumpHintStatusLineMessage() {
        if (fAssistant.isUpdatedOffset()) {
          String key = getQuickAssistBinding();
          if (key == null)
            return CorrectionMessages.JavaCorrectionProcessor_go_to_original_using_menu;
          else
            return NLS
                .bind(CorrectionMessages.JavaCorrectionProcessor_go_to_original_using_key,
                    key);
        } else if (fAssistant.isProblemLocationAvailable()) {
          String key = getQuickAssistBinding();
          if (key == null)
            return CorrectionMessages.JavaCorrectionProcessor_go_to_closest_using_menu;
          else
            return NLS
                .bind(CorrectionMessages.JavaCorrectionProcessor_go_to_closest_using_key,
                    key);
        } else
          return ""; //$NON-NLS-1$
      }

      private String getQuickAssistBinding() {
        final IBindingService bindingSvc = (IBindingService) PlatformUI
            .getWorkbench().getAdapter(IBindingService.class);
        return bindingSvc
            .getBestActiveBindingFormattedFor(ITextEditorActionDefinitionIds.QUICK_ASSIST);
      }
    });
  }

  /*
   * @see IContentAssistProcessor#computeCompletionProposals(ITextViewer, int)
   */
  public ICompletionProposal[] computeQuickAssistProposals(
      IQuickAssistInvocationContext quickAssistContext) {

    ICompletionProposal[] res = null;

    ISourceViewer viewer = quickAssistContext.getSourceViewer();
    if (viewer instanceof PHPStructuredTextViewer) {

      PHPStructuredTextViewer textViewer = (PHPStructuredTextViewer) viewer;
      initAssistant(textViewer);

      int documentOffset = quickAssistContext.getOffset();

      IEditorPart part = fAssistant.getEditor();

      ISourceModule cu = DLTKUIPlugin.getEditorInputModelElement(part
          .getEditorInput());
      IAnnotationModel model = DLTKUIPlugin.getDocumentProvider()
          .getAnnotationModel(part.getEditorInput());

      int length = viewer != null ? viewer.getSelectedRange().y : 0;
      AssistContext context = new AssistContext(cu, viewer, part,
          documentOffset, length, SharedASTProvider.WAIT_YES);

      Annotation[] annotations = fAssistant.getAnnotationsAtOffset();

      fErrorMessage = null;
      if (model != null && annotations != null) {
        ArrayList proposals = new ArrayList(10);
        IStatus status = collectProposals(context, model, annotations,
            true, !fAssistant.isUpdatedOffset(), proposals);
        res = (ICompletionProposal[]) proposals
            .toArray(new ICompletionProposal[proposals.size()]);
        if (!status.isOK()) {
          fErrorMessage = status.getMessage();
          PHPUiPlugin.log(status);
        }
      }
    }

    if (res == null || res.length == 0) {
      return new ICompletionProposal[] { new ChangeCorrectionProposal(
          CorrectionMessages.NoCorrectionProposal_description,
          new NullChange(""), 0, null) }; //$NON-NLS-1$
    }
    if (res.length > 1) {
      Arrays.sort(res, new CompletionProposalComparator());
    }
    return res;
  }

  public static IStatus collectProposals(IInvocationContext context,
      IAnnotationModel model, Annotation[] annotations,
      boolean addQuickFixes, boolean addQuickAssists, Collection proposals) {
    ArrayList problems = new ArrayList();

    // collect problem locations and corrections from marker annotations
    for (int i = 0; i < annotations.length; i++) {
      Annotation curr = annotations[i];
      ProblemLocation problemLocation = null;
      if (curr instanceof IScriptAnnotation) {
        problemLocation = getProblemLocation((IScriptAnnotation) curr,
            model);
        if (problemLocation != null) {
          problems.add(problemLocation);
        }
      }
      if (problemLocation == null && addQuickFixes
          && curr instanceof SimpleMarkerAnnotation) {
        collectMarkerProposals((SimpleMarkerAnnotation) curr, proposals);
      }
    }
    MultiStatus resStatus = null;

    IProblemLocation[] problemLocations = (IProblemLocation[]) problems
        .toArray(new IProblemLocation[problems.size()]);
    if (addQuickFixes) {
      IStatus status = collectCorrections(context, problemLocations,
          proposals);
      if (!status.isOK()) {
        resStatus = new MultiStatus(
            PHPUiPlugin.ID,
            IStatus.ERROR,
            CorrectionMessages.JavaCorrectionProcessor_error_quickfix_message,
            null);
        resStatus.add(status);
      }
    }
    if (addQuickAssists) {
      IStatus status = collectAssists(context, problemLocations,
          proposals);
      if (!status.isOK()) {
        if (resStatus == null) {
          resStatus = new MultiStatus(
              PHPUiPlugin.ID,
              IStatus.ERROR,
              CorrectionMessages.JavaCorrectionProcessor_error_quickassist_message,
              null);
        }
        resStatus.add(status);
      }
    }
    if (resStatus != null) {
      return resStatus;
    }
    return Status.OK_STATUS;
  }

  private static ProblemLocation getProblemLocation(
      IScriptAnnotation javaAnnotation, IAnnotationModel model) {
    if (javaAnnotation.getId() != null) {
      Position pos = model.getPosition((Annotation) javaAnnotation);
      if (pos != null) {
        return new ProblemLocation(pos.getOffset(), pos.getLength(),
            javaAnnotation); // java problems
                      // all handled
                      // by the
                      // quick assist
                      // processors
      }
    }
    return null;
  }

  private static void collectMarkerProposals(
      SimpleMarkerAnnotation annotation, Collection proposals) {
    IMarker marker = annotation.getMarker();
    IMarkerResolution[] res = IDE.getMarkerHelpRegistry().getResolutions(
        marker);
    if (res.length > 0) {
      for (int i = 0; i < res.length; i++) {
        proposals.add(new MarkerResolutionProposal(res[i], marker));
      }
    }
  }

  private static abstract class SafeCorrectionProcessorAccess implements
      ISafeRunnable {
    private MultiStatus fMulti = null;
    private ContributedProcessorDescriptor fDescriptor;

    public void process(ContributedProcessorDescriptor[] desc) {
      for (int i = 0; i < desc.length; i++) {
        fDescriptor = desc[i];
        SafeRunner.run(this);
      }
    }

    public void process(ContributedProcessorDescriptor desc) {
      fDescriptor = desc;
      SafeRunner.run(this);
    }

    public void run() throws Exception {
      safeRun(fDescriptor);
    }

    protected abstract void safeRun(ContributedProcessorDescriptor processor)
        throws Exception;

    public void handleException(Throwable exception) {
      if (fMulti == null) {
        fMulti = new MultiStatus(
            PHPUiPlugin.ID,
            IStatus.OK,
            CorrectionMessages.JavaCorrectionProcessor_error_status,
            null);
      }
      fMulti.merge(new Status(IStatus.ERROR, PHPUiPlugin.ID,
          IStatus.ERROR,
          CorrectionMessages.JavaCorrectionProcessor_error_status,
          exception));
    }

    public IStatus getStatus() {
      if (fMulti == null) {
        return Status.OK_STATUS;
      }
      return fMulti;
    }

  }

  private static class SafeCorrectionCollector extends
      SafeCorrectionProcessorAccess {
    private final IInvocationContext fContext;
    private final Collection fProposals;
    private IProblemLocation[] fLocations;

    public SafeCorrectionCollector(IInvocationContext context,
        Collection proposals) {
      fContext = context;
      fProposals = proposals;
    }

    public void setProblemLocations(IProblemLocation[] locations) {
      fLocations = locations;
    }

    public void safeRun(ContributedProcessorDescriptor desc)
        throws Exception {
      IQuickFixProcessor curr = (IQuickFixProcessor) desc.getProcessor(
          fContext.getCompilationUnit(), IQuickFixProcessor.class);
      if (curr != null) {
        IScriptCompletionProposal[] res = curr.getCorrections(fContext,
            fLocations);
        if (res != null) {
          for (int k = 0; k < res.length; k++) {
            fProposals.add(res[k]);
          }
        }
      }
    }
  }

  private static class SafeAssistCollector extends
      SafeCorrectionProcessorAccess {
    private final IInvocationContext fContext;
    private final IProblemLocation[] fLocations;
    private final Collection fProposals;

    public SafeAssistCollector(IInvocationContext context,
        IProblemLocation[] locations, Collection proposals) {
      fContext = context;
      fLocations = locations;
      fProposals = proposals;
    }

    public void safeRun(ContributedProcessorDescriptor desc)
        throws Exception {
      IQuickAssistProcessor curr = (IQuickAssistProcessor) desc
          .getProcessor(fContext.getCompilationUnit(),
              IQuickAssistProcessor.class);
      if (curr != null) {
        IScriptCompletionProposal[] res = curr.getAssists(fContext,
            fLocations);
        if (res != null) {
          for (int k = 0; k < res.length; k++) {
            fProposals.add(res[k]);
          }
        }
      }
    }
  }

  private static class SafeHasAssist extends SafeCorrectionProcessorAccess {
    private final IInvocationContext fContext;
    private boolean fHasAssists;

    public SafeHasAssist(IInvocationContext context) {
      fContext = context;
      fHasAssists = false;
    }

    public boolean hasAssists() {
      return fHasAssists;
    }

    public void safeRun(ContributedProcessorDescriptor desc)
        throws Exception {
      IQuickAssistProcessor processor = (IQuickAssistProcessor) desc
          .getProcessor(fContext.getCompilationUnit(),
              IQuickAssistProcessor.class);
      if (processor != null && processor.hasAssists(fContext)) {
        fHasAssists = true;
      }
    }
  }

  private static class SafeHasCorrections extends
      SafeCorrectionProcessorAccess {
    private final ISourceModule fCu;
    private final int fProblemId;
    private final IProblemIdentifier fIdentifier;
    private boolean fHasCorrections;

    public SafeHasCorrections(ISourceModule cu,
        IProblemIdentifier identifier) {
      fCu = cu;
      Scanner problemScanner = new Scanner(identifier.name());
      if (problemScanner.hasNextInt()) {
        fProblemId = problemScanner.nextInt();
      } else {
        fProblemId = -1;
      }
      this.fIdentifier = identifier;

      fHasCorrections = false;
    }

    public boolean hasCorrections() {
      return fHasCorrections;
    }

    public void safeRun(ContributedProcessorDescriptor desc)
        throws Exception {
      IQuickFixProcessor processor = (IQuickFixProcessor) desc
          .getProcessor(fCu, IQuickFixProcessor.class);
      if (processor != null && processor.hasCorrections(fCu, fProblemId)) {
        fHasCorrections = true;
      } else if (processor != null
          && processor instanceof IQuickFixProcessorExtension
          && ((IQuickFixProcessorExtension) processor)
              .hasCorrections(fCu, fIdentifier)) {
        fHasCorrections = true;
      }
    }
  }

  public static IStatus collectCorrections(IInvocationContext context,
      IProblemLocation[] locations, Collection proposals) {
    ContributedProcessorDescriptor[] processors = getCorrectionProcessors();
    SafeCorrectionCollector collector = new SafeCorrectionCollector(
        context, proposals);
    for (int i = 0; i < processors.length; i++) {
      ContributedProcessorDescriptor curr = processors[i];
      IProblemLocation[] handled = getHandledProblems(locations, curr);
      if (handled != null) {
        collector.setProblemLocations(handled);
        collector.process(curr);
      }
    }
    return collector.getStatus();
  }

  private static IProblemLocation[] getHandledProblems(
      IProblemLocation[] locations,
      ContributedProcessorDescriptor processor) {
    // implementation tries to avoid creating a new array
    boolean allHandled = true;
    ArrayList res = null;
    for (int i = 0; i < locations.length; i++) {
      IProblemLocation curr = locations[i];
      if (processor.canHandleMarkerType(curr.getMarkerType())) {
        if (!allHandled) { // first handled problem
          if (res == null) {
            res = new ArrayList(locations.length - i);
          }
          res.add(curr);
        }
      } else if (allHandled) {
        if (i > 0) { // first non handled problem
          res = new ArrayList(locations.length - i);
          for (int k = 0; k < i; k++) {
            res.add(locations[k]);
          }
        }
        allHandled = false;
      }
    }
    if (allHandled) {
      return locations;
    }
    if (res == null) {
      return null;
    }
    return (IProblemLocation[]) res
        .toArray(new IProblemLocation[res.size()]);
  }

  public static IStatus collectAssists(IInvocationContext context,
      IProblemLocation[] locations, Collection proposals) {
    ContributedProcessorDescriptor[] processors = getAssistProcessors();
    SafeAssistCollector collector = new SafeAssistCollector(context,
        locations, proposals);
    collector.process(processors);

    return collector.getStatus();
  }

  /*
   * @see IContentAssistProcessor#getErrorMessage()
   */
  public String getErrorMessage() {
    return fErrorMessage;
  }

  /*
   * @see
   * org.eclipse.jface.text.quickassist.IQuickAssistProcessor#canFix(org.eclipse
   * .jface.text.source.Annotation)
   *
   * @since 3.2
   */
  public boolean canFix(Annotation annotation) {
    return hasCorrections(annotation);
  }

  /*
   * @see
   * org.eclipse.jface.text.quickassist.IQuickAssistProcessor#canAssist(org
   * .eclipse.jface.text.quickassist.IQuickAssistInvocationContext)
   *
   * @since 3.2
   */
  public boolean canAssist(IQuickAssistInvocationContext invocationContext) {
    if (invocationContext instanceof IInvocationContext)
      return hasAssists((IInvocationContext) invocationContext);
    return false;
  }

  public boolean canFix(IScriptAnnotation annotation) {
    if (annotation instanceof Annotation) {
      return canFix((Annotation) annotation);
    }
    return false;
  }

  public boolean canFix(IMarker marker) {
    return false;
  }

  public void computeQuickAssistProposals(IScriptAnnotation annotation,
      IScriptCorrectionContext context) {
  }

  public void computeQuickAssistProposals(IMarker marker,
      IScriptCorrectionContext context) {
  }
}
TOP

Related Classes of org.eclipse.php.internal.ui.text.correction.PHPCorrectionProcessor$SafeCorrectionCollector

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.