Package org.cfeclipse.cfml.editors.contentassist

Source Code of org.cfeclipse.cfml.editors.contentassist.CFEPrimaryAssist

/*
* Created on Sep 27, 2004
*
* The MIT License
* Copyright (c) 2004 Oliver Tupman
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.cfeclipse.cfml.editors.contentassist;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import org.cfeclipse.cfml.editors.ICFEFileDocument;
import org.cfeclipse.cfml.preferences.AutoIndentPreferenceConstants;
import org.cfeclipse.cfml.preferences.CFMLPreferenceManager;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.bindings.TriggerSequence;
import org.eclipse.jface.bindings.keys.KeySequence;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.contentassist.ContentAssistEvent;
import org.eclipse.jface.text.contentassist.ContentAssistant;
import org.eclipse.jface.text.contentassist.ICompletionListener;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.contentassist.IContentAssistantExtension2;
import org.eclipse.jface.text.contentassist.IContentAssistantExtension3;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.contentassist.IContextInformationValidator;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.keys.IBindingService;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;

//import org.cfeclipse.cfml.editors.partitioner.CFEPartitioner;
//import org.cfeclipse.cfml.editors.partitioner.CFEPartition;
/**
*
* @author Oliver Tupman
*/
public class CFEPrimaryAssist implements IContentAssistProcessor {
  // stats checking
  private static final boolean DEBUG= false;
   
  protected static CFMLPreferenceManager preferenceManager = new CFMLPreferenceManager();
   
  /** Characters that will trigger content assist */
  private char[] autoActivationChars = null;
  /* cycling stuff */
  private int fRepetition= -1;
  private String fIterationGesture= null;
    private final IContentAssistantExtension2 fContentAssistant;
  private boolean fTemplatesOnly = false;
  private List fCategories;
  private List fCategoryIteration= null;
  private String fErrorMessage;
  private int fNumberOfComputedResults;
  private ISourceViewer fSourceViewer;


  private DefaultAssistState fState;


  private int fLastOffset;


  private int fPrevDocLen = 0;

  private int fPrevOffset = 0;

  private static final Comparator ORDER_COMPARATOR= new Comparator() {

    public int compare(Object o1, Object o2) {
      IAssistContributor d1= (IAssistContributor) o1;
      IAssistContributor d2= (IAssistContributor) o2;
     
      return d1.getSortOrder() - d2.getSortOrder();
    }
   
  };

    /**
     * @param sourceViewer
     * @param assistant
     *
     */
    public CFEPrimaryAssist(ISourceViewer sourceViewer, ContentAssistant assistant) {
        super();
        fContentAssistant = assistant;
        fSourceViewer = sourceViewer;
        generateAutoActivationChars();
        // content assist category cycling
    fContentAssistant.addCompletionListener(new ICompletionListener() {     
      /*
       * @see org.eclipse.jface.text.contentassist.ICompletionListener#assistSessionStarted(org.eclipse.jface.text.contentassist.ContentAssistEvent)
       */
      public void assistSessionStarted(ContentAssistEvent event) {
        if (event.processor != CFEPrimaryAssist.this)
          return;
        fIterationGesture= getIterationGesture();
        KeySequence binding= getIterationBinding();

        // this may show the warning dialog if all categories are disabled
        fCategoryIteration= getCategoryIteration();
        for (Iterator it= fCategories.iterator(); it.hasNext();) {
          IAssistContributor cat= (IAssistContributor) it.next();
          cat.sessionStarted();
        }
        //System.out.println("catItSize "+fCategoryIteration.size());
        fRepetition= 0;
        if (event.assistant instanceof IContentAssistantExtension2) {
          IContentAssistantExtension2 extension= (IContentAssistantExtension2) event.assistant;

          if (fCategoryIteration.size() == 1) {
            extension.setRepeatedInvocationMode(false);
            extension.setShowEmptyList(false);
          } else {
            extension.setRepeatedInvocationMode(true);
            extension.setStatusLineVisible(true);
            extension.setStatusMessage(createIterationMessage());
            extension.setShowEmptyList(true);
            if (extension instanceof IContentAssistantExtension3) {
              IContentAssistantExtension3 ext3= (IContentAssistantExtension3) extension;
              ((ContentAssistant) ext3).setRepeatedInvocationTrigger(binding);
            }
          }
       
        }
      }
     
      /*
       * @see org.eclipse.jface.text.contentassist.ICompletionListener#assistSessionEnded(org.eclipse.jface.text.contentassist.ContentAssistEvent)
       */
      public void assistSessionEnded(ContentAssistEvent event) {
        if (event.processor != CFEPrimaryAssist.this)
          return;
        fCategoryIteration= null;
        fState = null;
        fRepetition= -1;
        fIterationGesture= null;
        if(fCategories == null) {         
          return;
        }
        for (Iterator it= fCategories.iterator(); it.hasNext();) {
          IAssistContributor cat= (IAssistContributor) it.next();
          cat.sessionEnded();
        }

        if (event.assistant instanceof IContentAssistantExtension2) {
          IContentAssistantExtension2 extension= (IContentAssistantExtension2) event.assistant;
          extension.setShowEmptyList(false);
          extension.setRepeatedInvocationMode(false);
          extension.setStatusLineVisible(false);
          if (extension instanceof IContentAssistantExtension3) {
            IContentAssistantExtension3 ext3= (IContentAssistantExtension3) extension;
            ((ContentAssistant) ext3).setRepeatedInvocationTrigger(KeySequence.getInstance());
          }
        }
      }


      /*
       * @see org.eclipse.jface.text.contentassist.ICompletionListener#selectionChanged(org.eclipse.jface.text.contentassist.ICompletionProposal, boolean)
       */
      public void selectionChanged(ICompletionProposal proposal, boolean smartToggle) {
      }
     
    });
    setRootAssistorsToCategories();
  }

  private void clearState() {
    fErrorMessage=null;
    fNumberOfComputedResults= 0;
  }

  /**
   * Filters and sorts the proposals. The passed list may be modified
   * and returned, or a new list may be created and returned.
   *
   * Nothing happening here right now, but eventually maybe
   *
   * @param proposals the list of collected proposals (element type:
   *        {@link ICompletionProposal})
   * @param monitor a progress monitor
   * @return the list of filtered and sorted proposals, ready for
   *         display (element type: {@link ICompletionProposal})
   */
  protected List filterAndSortProposals(List proposals, IProgressMonitor monitor) {
    return proposals;
  }
   
  /*
   * Currently returns java binding, eventually we need to add our own preferences!
   * @return binding for proposal cycling
   *
   */
  private KeySequence getIterationBinding() {
      final IBindingService bindingSvc= (IBindingService) PlatformUI.getWorkbench().getAdapter(IBindingService.class);
    TriggerSequence binding= bindingSvc.getBestActiveBindingFor(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
    if (binding instanceof KeySequence)
      return (KeySequence) binding;
    return null;
    }

    private String getIterationGesture() {
        TriggerSequence binding = getIterationBinding();
        return binding != null ? binding.format(): "completion key";
    }

  private String createEmptyMessage() {
    return "No " + getCategoryLabel(fRepetition);
  }
 
  private String createIterationMessage() {
    return getCategoryLabel(fRepetition) + " - Press " + fIterationGesture + " to show " + getCategoryLabel(fRepetition + 1);
  }
 
  /*
   * kludge job for getting assistors
   */

  private void setRootAssistorsToCategories() {
    if(fCategories == null) {     
      ICFEFileDocument curDoc = (ICFEFileDocument)fSourceViewer.getDocument();
      if(curDoc != null && curDoc instanceof ICFEFileDocument)
        fCategories = curDoc.getContentAssistManager().getRootAssistors();
    }
  }
 
 
  private String getCategoryLabel(int repetition) {
    int iteration= repetition % fCategoryIteration.size();
    if (iteration == 0)
      return "All proposals";
    return toString((IAssistContributor) ((List) fCategoryIteration.get(iteration)).get(0));
  }
 
  private String toString(IAssistContributor category) {
    return category.getName();
  }

  /**
   * Creates a progress monitor.
   * <p>
   * The default implementation creates a
   * <code>NullProgressMonitor</code>.
   * </p>
   *
   * @return a progress monitor
   */
  protected IProgressMonitor createProgressMonitor() {
    return new NullProgressMonitor();
  }
 
 
  private List getCategories() {
    setRootAssistorsToCategories();
    if (fCategoryIteration == null)
      return fCategories;
   
    int iteration= fRepetition % fCategoryIteration.size();
    fContentAssistant.setStatusMessage(createIterationMessage());
    fContentAssistant.setEmptyMessage(createEmptyMessage());
    // a little hack because it seems like we get the cycle trigger with each keypress?!?! :denny
    if(fLastOffset == fState.getOffset()) {     
      fRepetition++;
    }
    fLastOffset = fState.getOffset();
   
//    fAssistant.setShowMessage(fRepetition % 2 != 0);
//   
    return (List) fCategoryIteration.get(iteration);
  }

  private List getCategoryIteration() {
    List sequence= new ArrayList();
    sequence.add(getDefaultCategories());
    for (Iterator it= getSeparateCategories().iterator(); it.hasNext();) {
      IAssistContributor cat= (IAssistContributor) it.next();
      sequence.add(Collections.singletonList(cat));
    }
    return sequence;
  }

  private List getDefaultCategories() {
    // default mix - enable all included computers
    List included= getDefaultCategoriesUnchecked();
    // TODO:  set up preference page for setting default vs. cycled
    fLastOffset = 0;
    return included;
  }

  private List getDefaultCategoriesUnchecked() {
    setRootAssistorsToCategories();
    List included= new ArrayList();
    for (Iterator it= fCategories.iterator(); it.hasNext();) {
      IAssistContributor category= (IAssistContributor) it.next();
      if (category.isIncluded())
        included.add(category);
    }
    return included;
  }

  /*
   * this and the above two functions would do more if we had preferences
   * for enabling default assistors etc.
   */
  private List getSeparateCategories() {
    ArrayList sorted= new ArrayList();
    for (Iterator it= fCategories.iterator(); it.hasNext();) {
      IAssistContributor category= (IAssistContributor) it.next();
      if (category.isSeparateCommand())
        sorted.add(category);
    }
    Collections.sort(sorted, ORDER_COMPARATOR);
    return sorted;
  }


    private ArrayList arrayToCollection(Object [] array)
    {
        ArrayList  retVal = new ArrayList();
        if(array == null)
          return retVal;
        for(int i = 0; i < array.length; i++)
        {
            retVal.add(array[i]);
        }
        return retVal;
    }
   
    /* (non-Javadoc)
     * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeCompletionProposals(org.eclipse.jface.text.ITextViewer, int)
     */
    public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer,
            int offset) {
      long start= DEBUG ? System.currentTimeMillis() : 0;
   
    clearState();
   
    IProgressMonitor monitor= createProgressMonitor();
    monitor.beginTask("Computing proposals", fCategories.size() + 1);
    long setup= DEBUG ? System.currentTimeMillis() : 0;

    monitor.subTask("Collecting proposals");
    List proposals= collectProposals(viewer, offset, monitor);
    long collect= DEBUG ? System.currentTimeMillis() : 0;

    monitor.subTask("Sorting proposals");
    List filtered= filterAndSortProposals(proposals, monitor);
    fNumberOfComputedResults= filtered.size();
    long filter= DEBUG ? System.currentTimeMillis() : 0;
   
    ICompletionProposal[] result= (ICompletionProposal[]) filtered.toArray(new ICompletionProposal[filtered.size()]);
    monitor.done();
   
    if (DEBUG) {
      System.err.println("Code Assist Stats (" + result.length + " proposals)"); //$NON-NLS-1$ //$NON-NLS-2$
      System.err.println("Code Assist (setup):\t" + (setup - start) ); //$NON-NLS-1$
      System.err.println("Code Assist (collect):\t" + (collect - setup) ); //$NON-NLS-1$
      System.err.println("Code Assist (sort):\t" + (filter - collect) ); //$NON-NLS-1$
    }
   
    return result;
    }

    private boolean isWhiteSpace(char c) {
      return Character.isWhitespace(c);
    }
   
  private List collectProposals(ITextViewer viewer, int offset, IProgressMonitor monitor) {
    if(viewer == null)
      return new ArrayList();
    fState = AssistUtils.initialiseDefaultAssistState(viewer, offset);
    boolean isDocLenDiff = viewer.getDocument().getLength() != fPrevDocLen;
    fPrevDocLen = viewer.getDocument().getLength();
    String partType = fState.getOffsetPartition().getType();
    List proposals= new ArrayList();
    List providers= getCategories();
    IAssistContributor cat = null;
    if (isDocLenDiff && fState.getTriggerData() == ' '
        && (!partType.endsWith("tag_attributes") && !partType.endsWith("tag_begin") && !partType.endsWith("tag_begin_end") && !partType
            .endsWith("start_tag_end"))) {
      fPrevOffset = offset;
      return new ArrayList();
    }
    if (fPrevOffset > offset && fPrevOffset != 0 && !isDocLenDiff || offset > fPrevOffset && !isDocLenDiff) {
      fPrevOffset = offset;
      return new ArrayList();
    }
    fPrevOffset = offset;
    for (Iterator it= providers.iterator(); it.hasNext();) {
      Object assistor = it.next();
      if(assistor instanceof CFContentAssist) {
        cat= (IAssistContributor) assistor;
            fState.setPrevDelim(0)// TODO: Bodge job, need to assign correct previous delim position
            //assistState.setDataSoFar(assistState.getDataSoFar().trim()); // FIXME: see trac ticket #472
        ICompletionProposal[] computed= cat.getTagProposals(fState);
        proposals.addAll(arrayToCollection(computed));
      }
      else if(assistor instanceof IAssistContributor) {
        cat= (IAssistContributor) assistor;
        ICompletionProposal[] computed= cat.getTagProposals(fState);
        proposals.addAll(arrayToCollection(computed));
      } else {
        System.out.println(assistor.getClass().getName());
      }
      if (fErrorMessage == null)
        fErrorMessage= cat.getErrorMessage();
    }
//      if (fErrorMessage == null)
//        fErrorMessage= cat.getErrorMessage();   

    return proposals;
  }
   
   
   
  /*
   * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeContextInformation(org.eclipse.jface.text.ITextViewer, int)
   */
  public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
    clearState();

    IProgressMonitor monitor= createProgressMonitor();
    monitor.beginTask("Computing contexts", fCategories.size() + 1);
   
    monitor.subTask("Collecting contexts");
    List proposals= collectContextInformation(viewer, offset, monitor);

    monitor.subTask("Sorting contexts");
    List filtered= filterAndSortContextInformation(proposals, monitor);
    fNumberOfComputedResults= filtered.size();
   
    IContextInformation[] result= (IContextInformation[]) filtered.toArray(new IContextInformation[filtered.size()]);
    monitor.done();
    return result;
  }

  private List collectContextInformation(ITextViewer viewer, int offset, IProgressMonitor monitor) {
    List proposals= new ArrayList();
   
    List providers= getCategories();
    for (Iterator it= providers.iterator(); it.hasNext();) {
      IContentAssistProcessor cat= (IContentAssistProcessor) it.next();
      IContextInformation[] computed= cat.computeContextInformation(viewer,offset);
      proposals.addAll(arrayToCollection(computed));
      if (fErrorMessage == null)
        fErrorMessage= cat.getErrorMessage();
    }
   
    return proposals;
  }

  /**
   * Filters and sorts the context information objects. The passed
   * list may be modified and returned, or a new list may be created
   * and returned.
   *
   * @param contexts the list of collected proposals (element type:
   *        {@link IContextInformation})
   * @param monitor a progress monitor
   * @return the list of filtered and sorted proposals, ready for
   *         display (element type: {@link IContextInformation})
   */
  protected List filterAndSortContextInformation(List contexts, IProgressMonitor monitor) {
    return contexts;
  }


  /**
   * Creates the array of characters that will trigger content assist
   */
  private void generateAutoActivationChars() {
    String autoActivationString = preferenceManager.getStringPref(AutoIndentPreferenceConstants.P_AUTOACTIVATION_CHARS);
      char[] chars = autoActivationString.toCharArray();     
      this.autoActivationChars = chars;     
  }
   
  public char[] removeCharFromCharArray(char[] symbols, char c) {
    for (int i = 0; i < symbols.length; i++) {
      if (symbols[i] == c) {
        char[] copy = new char[symbols.length - 1];
        System.arraycopy(symbols, 0, copy, 0, i);
        System.arraycopy(symbols, i + 1, copy, i, symbols.length - i - 1);
        return copy;
      }
    }
    return symbols;
  }

  /**
   * What characters cause us to wake up (for tags and attributes)
   */
  public char[] getCompletionProposalAutoActivationCharacters() {
      //System.out.println("Auto-activation chars retrieved: " + new String(this.autoActivationChars));
    // return new char[] { '<', 'f', 'F', '~', '\t', '\n', '\r', '>', '\"', '.' };
    return this.autoActivationChars;
  }

  /*
    public char[] getCompletionProposalAutoActivationCharacters() {
        return new char[] { '<', 'f', ' ', 'F', '~', '\t', '\n', '\r', '>', '\"', '.' };
    }
    */

    /* (non-Javadoc)
     * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getContextInformationAutoActivationCharacters()
     */
    public char[] getContextInformationAutoActivationCharacters() {
        return null;
        //return new char[] {',', '('};
    }

  /*
   * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getErrorMessage()
   */
  public String getErrorMessage() {
    if (fNumberOfComputedResults > 0)
      return null;
    if (fErrorMessage != null)
      return fErrorMessage;
    return "No proposals";
  }


    /* (non-Javadoc)
     * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getContextInformationValidator()
     */
    public IContextInformationValidator getContextInformationValidator() {
        return null;
    }
   
}
TOP

Related Classes of org.cfeclipse.cfml.editors.contentassist.CFEPrimaryAssist

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.