Package org.cfeclipse.cfml.editors.dnd

Source Code of org.cfeclipse.cfml.editors.dnd.SelectionCursorListener

/*
* Created on Oct 28, 2004
*
* The MIT License
* Copyright (c) 2004 Stephen Milligan
*
* 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.dnd;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.cfeclipse.cfml.CFMLPlugin;
import org.cfeclipse.cfml.editors.CFMLEditor;
import org.cfeclipse.cfml.editors.ICFDocument;
import org.cfeclipse.cfml.editors.OccurrencesFinder;
import org.cfeclipse.cfml.editors.partitioner.CFEPartition;
import org.cfeclipse.cfml.editors.partitioner.CFEPartitioner;
import org.cfeclipse.cfml.parser.CFDocument;
import org.cfeclipse.cfml.parser.docitems.CfmlTagItem;
import org.cfeclipse.cfml.parser.docitems.DocItem;
import org.cfeclipse.cfml.parser.docitems.TagItem;
import org.cfeclipse.cfml.properties.CFMLPropertyManager;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.text.ISelectionValidator;
import org.eclipse.jface.text.ISynchronizable;
import org.eclipse.jface.text.ITextInputListener;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.IAnnotationModelExtension;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.projection.ProjectionAnnotation;
import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel;
import org.eclipse.jface.text.source.projection.ProjectionViewer;
import org.eclipse.jface.viewers.IPostSelectionProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.MouseTrackListener;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Point;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.MarkerUtilities;

import cfml.parsing.CFMLParser;
import cfml.parsing.CFMLSource;
import cfml.parsing.ParserTag;


/**
* @author Stephen Milligan
*
* This listener keeps track of where the mouse is relative to the currently selected text
* and whether or not the mouse is currently down.
*/
public class SelectionCursorListener implements MouseListener, MouseMoveListener, MouseTrackListener, ISelectionChangedListener {
    /**
     * The text editor that the selection listener is installed on
     */
    //private ITextEditor editor = null;
    /**
     * The StyledText that belongs to the viewer
     */
    private StyledText textWidget = null;
    /**
     * The projection viewer for this editor
     */
    private ProjectionViewer fViewer = null;
   
    /**
     * This allows us to figure out where a point is in widget co-ordinate space.
     */
    private WidgetPositionTracker widgetOffsetTracker = null;
   
    /**
     * The cursor that indicates stuff can be dragged
     */
    private Cursor arrowCursor = null;
    /**
     * The regular text I-Beam cursor
     */
    private Cursor textCursor = null;
   
    /**
     * The offset of the start of the selected text in viewer co-ordinates
     */
    public int selectionStart = -1;
    /**
     * The contents of the selection according to the viewer
     */
  public String selectionText;
    /**
     * Is the mouse currently hovering over a selected area
     */
    private boolean hovering = false;
    /**
     * Was the mouse down the last time we were notified
     */
    private boolean mouseDown = false;
   
    /**
     * Indicates whether or not the selection needs to be expanded
     * to contain folded text. This is set to true when the
     * selection ends at the end of a line.
     */
    public boolean expandSelection = false;
   
    /**
     * This allows us to handle the case where the user clicks and releases on a selection.
     * Mouse down sets it to true
     * Mouse move sets it to false
     * Mouse up checks it's value and calls reset() if true.
     */
    private boolean downUp = false;


  /*
   * These will be used for word delineation
   */
  private String partOfWordChars;
  private String breakWordChars;
  private String partOfWordCharsAlt;
  private String breakWordCharsAlt;
  private String partOfWordCharsShift;
  private String breakWordCharsShift;
  private CfmlTagItem lastSelectedTag;
  private DocItem selectedTag;
  private boolean selectedTagWasSelected;
  private CFMLEditor editor;
  private static String TYPE = "org.cfeclipse.cfml.occurrencemarker";
  private static String tagBeginEndAnnotation = "org.cfeclipse.cfml.tagbeginendmarker";
  //private static String TYPE = "org.eclipse.core.resources.textmarker";
  //private static String TYPE = "org.cfeclipse.cfml.parserWarningMarker";

  /**
   * Holds the current occurrence annotations.
   * @since 3.1
   */
  private Annotation[] fOccurrenceAnnotations= null;

  private OccurrencesFinderJob fOccurrencesFinderJob;
  private OccurrencesFinderJobCanceler fOccurrencesFinderJobCanceler;
 
  private ITextSelection fForcedMarkOccurrencesSelection;
  private boolean fMarkOccurrenceAnnotations = true;
  private boolean fStickyOccurrenceAnnotations = false;
  private DocItem currentDocItem;
  private MouseEvent lastMouseEvent;
  private String[] wordCharArray;

   
    /**
     * This class listens to the mouse position relative to any selected text
     * and keeps track of whether or not the mouse is currently over a selection.
     */
    public SelectionCursorListener(CFMLEditor editor, ProjectionViewer viewer, String[] wordChars) {
        this.editor = editor;
        this.fViewer = viewer;
        this.textWidget = viewer.getTextWidget();
        this.arrowCursor = new Cursor(this.textWidget.getDisplay(),SWT.CURSOR_ARROW);
        this.textCursor = new Cursor(this.textWidget.getDisplay(),SWT.CURSOR_IBEAM);
        this.widgetOffsetTracker = new WidgetPositionTracker(this.textWidget);
    setWordSelectionChars(wordChars);
    }
   
    /**
     * Resets the listener to a state where the mouse isn't hovering over a selection.
     *
     */
    public void reset() {
        this.hovering = false;
        this.selectionStart = -1;
        this.selectionText = "";
        this.textWidget.setCursor(this.textCursor);
        this.mouseDown = false;
        //System.out.println("Listener reset");
    }

    /**
     * sets the work selection break/continue chars.
     *
     */
  public void setWordSelectionChars(String[] wordChars) {
    // this is nasty.  Be sure to update OccurrencesFinder if changed!
    this.wordCharArray = wordChars;
    this.partOfWordChars = wordChars[0];
    this.breakWordChars = wordChars[1];
    this.partOfWordCharsAlt = wordChars[2];
    this.breakWordCharsAlt = wordChars[3];
    this.partOfWordCharsShift = wordChars[4];
    this.breakWordCharsShift = wordChars[5];   
  }
   
    /**
     * gets the work selection break/continue chars.
     *
     */
  public String[] getWordSelectionChars() {
    return this.wordCharArray;
  }

  public void setSelectedTag() {
    // TODO Auto-generated method stub
    //CFMLEditor curDoc = (CFMLEditor) this.fViewer.getDocument();
    //ICFDocument cfd = (ICFDocument) curDoc.getDocumentProvider().getDocument(curDoc.getEditorInput());
    TextSelection sel = (TextSelection) this.fViewer.getSelection();
    int startPos = sel.getOffset();
    ICFDocument cfd = (ICFDocument) this.fViewer.getDocument();
    DocItem cti = cfd.getTagAt(startPos, startPos, true);
    if(cti != null && this.selectedTag != null) {
      if(cti.getStartPosition() == this.selectedTag.getStartPosition()){       
        this.selectedTagWasSelected = true;
      } else {
        clearTagBeginEndMarkers();
        this.selectedTagWasSelected = false;       
      }
    } else {
      clearTagBeginEndMarkers();     
    }
    this.selectedTag = null;
    try {
      // cfcomponent returns ASTVarDeclaration -- syntax is null for whatever reason (ASTVar's from cfscript?!)
      if(cti != null
        && !cti.getName().equals("CfmlComment") && !cti.getName().equals("cfscript")
          && !cti.getName().startsWith("AST") && !cti.getName().equals("ScriptItem")) {
        if (cti instanceof CfmlTagItem) {
          if (cti.getName().equals("CfmlCustomTag") || ((TagItem) cti).hasClosingTag()) {
            markBeginEndTags((CfmlTagItem) cti);
          }
        }
    }
    } catch (Exception e) {
      System.err.println(cti.getName());
      e.printStackTrace();
    }     
    CFEPartitioner partitioner = (CFEPartitioner)cfd.getDocumentPartitioner();   
    CFEPartition part = partitioner.findClosestPartition(startPos);
    if(part == null) {
      return;
    }
    startPos = part.offset;
    if (cti != null) {
      this.currentDocItem = cti;
      this.selectedTag = cti;
    } else {
      this.currentDocItem = cfd.getTagAt(startPos, startPos, false);
      while (this.currentDocItem == null && startPos >= 0 && part != null) {
        startPos = part.offset;
        this.currentDocItem = cfd.getTagAt(startPos, startPos + part.length + 1, false);
        part = partitioner.getPreviousPartition(startPos);
      }
      this.selectedTag = this.currentDocItem;
    }
  }

  public DocItem getSelectedTag() {
    return this.selectedTag;
  }
  public DocItem getCurrentDocItem() {
    return this.currentDocItem;
  }
  public boolean getSelectedTagWasSelected() {
    return this.selectedTagWasSelected;
  }
  public MouseEvent getLastMouseEvent() {
    return this.lastMouseEvent;
  }
   
    /**
     * Allows the drag drop listener to know if it's ok to start a drag.
     *
     * @return
     */
    public boolean doDrag() {
        if (this.hovering && this.mouseDown) {
            return true;
        }
        return false;
    }
   
   
    /**
     * Sent when the mouse pointer passes into the area of
     * the screen covered by a control.
     *
     * @param e an event containing information about the mouse enter
     */
    public void mouseEnter(MouseEvent e) {
        // do nothing
        //reset();
    }

    /**
     * Sent when the mouse pointer passes out of the area of
     * the screen covered by a control.
     *
     * @param e an event containing information about the mouse exit
     */
    public void mouseExit(MouseEvent e) {
        //reset();
    }

    /**
     * Sent when the mouse pointer hovers (that is, stops moving
     * for an (operating system specified) period of time) over
     * a control.
     *
     * @param e an event containing information about the hover
     */
    public void mouseHover(MouseEvent e) {
        // do nothing
    }
   
   
    /**
     * Sent when the mouse moves.
     *
     * @param e an event containing information about the mouse move
     */
    public void mouseMove(MouseEvent e) {
        // If the selection is draggable we want to ignore this event.
       
        if (!this.mouseDown) {
         
          Point pt = new Point(e.x,e.y);
         
          if (pointOnSelection(pt)) {
              this.textWidget.setCursor(this.arrowCursor);
              this.hovering = true;
          }
          else {
              this.textWidget.setCursor(this.textCursor);
              this.hovering = false;
          }
        }
        else {
            this.downUp = false;
        }
    }
   
    /**
     * This is notified when the selection is changed in the viewer.
     *
     * If a drag is in progress or the cursor is already over a selection,
     * the selection change is ignored.
     *
     */
   
    public void selectionChanged(SelectionChangedEvent event) {
    setSelectedTag();
//    editor.getEditorSite().getPage().showActionSet("org.cfeclipse.cfml.actionset");
    if (event.getSelection() instanceof ITextSelection) {
      ITextSelection textSelection= (ITextSelection)event.getSelection();
      this.selectionStart = textSelection.getOffset();
      this.selectionText = textSelection.getText();
          //checkFolding();
    }

        if (!this.hovering) {
          if(editor.isMarkingOccurrences()) {
            ISelection selection = event.getSelection();
        if (event.getSelectionProvider() instanceof IPostSelectionProvider) {
              if (selection instanceof ITextSelection) {
            ITextSelection textSelection= (ITextSelection)selection;
            try{
              updateOccurrenceAnnotations(textSelection, editor.getCFModel());
            } catch (Exception e) {
              e.printStackTrace();
            }
          }
          //markOccurrences(this.selectionText);     
            }
            else {
              //System.out.println("MarkOccurrences got non POST selection changed");
            }
          }
        }
    this.lastMouseEvent = null;
    }
    /**
     * Determines if the selection needs to be expanded
     * to account for a closed fold.
     *
     * If so, it modifies the selection in the editor
     * and updates the selected text.
     *
     */
    private void checkFolding() {
        int widgetOffset = this.fViewer.modelOffset2WidgetOffset(this.selectionStart);
        String[] lines = this.selectionText.split(this.textWidget.getLineDelimiter());
        int widgetLine = this.textWidget.getContent().getLineAtOffset(widgetOffset);
        int lineCount = 0;
       
        if (lines.length > 0) {
            lineCount = lines.length -1;
        }
       
        // If we've already grabbed the text inside a fold we
        // could end up with more lines than the widget knows about.
        if (widgetLine+lineCount > this.textWidget.getLineCount()) {
            return;
        }

        String line = this.textWidget.getContent().getLine(widgetLine+lineCount);
       
        if (lines.length > 0
                && line.equals(lines[lines.length-1])) {
            // Figure out the viewer offset for the start of the line.
            int widgetLineStart = this.textWidget.getContent().getOffsetAtLine(widgetLine + lineCount);
            int viewerLineStart = this.fViewer.widgetOffset2ModelOffset(widgetLineStart);
          
            ProjectionAnnotationModel model = this.fViewer.getProjectionAnnotationModel();
            Iterator i = model.getAnnotationIterator();
            while (i.hasNext()) {
                ProjectionAnnotation annotation = (ProjectionAnnotation)i.next();
                Position pos = model.getPosition(annotation);
                /* Check if the line is the start line of a collapsed
                 * region.
                 */
                if (pos.offset == viewerLineStart
                        && annotation.isCollapsed()) {
                    int selectionLength = viewerLineStart - this.selectionStart + pos.length;
                    // Grab the current caret position so we can put it back after changing the selection
                    Point oldCaret = this.textWidget.getCaret().getLocation();
                    TextSelection sel = new TextSelection(this.fViewer.getDocument(),this.selectionStart,selectionLength);
                    this.fViewer.setSelection(sel,false);
                    /* Restore the caret. Using this rather than textWidget.setCaretOffset()
                     * because setCaretOffset() clears the selection
                     */
                    this.textWidget.getCaret().setLocation(oldCaret);
                }
            }
        }
       
    }
   
  /**
   * Sent when a mouse button is pressed twice within the (operating system
   * specified) double click period.
   *
   * @param e
   *            an event containing information about the mouse double click
   *
   * @see org.eclipse.swt.widgets.Display#getDoubleClickTime()
   */
  public void mouseDoubleClick(MouseEvent e) {

    TextSelection sel = (TextSelection) this.fViewer.getSelection();

    int startpos = sel.getOffset()+1;

    if ((e.stateMask & SWT.MOD1) != 0) {

      CFMLPropertyManager propertyManager = new CFMLPropertyManager();
      String dict = propertyManager.getCurrentDictionary(((IFileEditorInput) editor.getEditorInput()).getFile().getProject());
      CFMLParser fCfmlParser = CFMLPlugin.newCFMLParser(dict);
      ICFDocument cfd = (ICFDocument) this.fViewer.getDocument();
      CFMLSource cfmlSource = fCfmlParser.addCFMLSource(cfd.getCFDocument().getFilename(),cfd.get());
      ParserTag tag = cfmlSource.getEnclosingTag(startpos);
      int start = 0;
      int length = 0;
      if (tag != null) {

        if ((e.stateMask & SWT.SHIFT) != 0) {
          start = tag.getBegin();
          length = tag.getEnd() - tag.getBegin();
        } else {
          if (tag.getEndTagBegin() <= startpos
              && tag.getEndTagEnd() >= startpos) {
            start = tag.getEndTagBegin();
            length = tag.getEndTagEnd() - tag.getEndTagBegin();
          } else {
            start = tag.getStartTagBegin();
            length = tag.getStartTagEnd() - tag.getStartTagBegin();
          }
        }

        TextSelection newSel = new TextSelection(cfd, start, length);
        this.fViewer.setSelection(newSel);

      } else {
        startpos = this.fViewer.getSelectedRange().x;
        selectWord(startpos, e);
      }
    } else {

      startpos = this.fViewer.getSelectedRange().x;
      selectWord(startpos, e);
    }

  }
  // TODO:  move this to org.cfeclipse.cfml.editors.selection.CFTextSelector
  protected boolean selectWord(int caretPos, MouseEvent e) {

    IDocument doc = this.fViewer.getDocument();
    int startPos, endPos, pos;
    char c;
    String normalWordChars = this.partOfWordChars;
    String breakWordChars = this.breakWordChars;
    String wordChars = normalWordChars;
    String altWordChars = this.partOfWordCharsAlt;
    String altBreakWordChars = this.breakWordCharsAlt;
    String shiftWordChars = this.partOfWordCharsShift;
    String shiftBreakWordChars = this.breakWordCharsShift;
    try {
      if ((e.stateMask == SWT.ALT || e.stateMask == SWT.SHIFT + SWT.ALT)) {
        wordChars = wordChars + altWordChars;
        breakWordChars = altBreakWordChars;
      }
      if ((e.stateMask == SWT.SHIFT || e.stateMask == SWT.SHIFT + SWT.ALT)) {
        wordChars = wordChars + shiftWordChars;
        breakWordChars = shiftBreakWordChars;
      }

      pos = caretPos;
      int length = doc.getLength();
      while (pos < length) {
        c = doc.getChar(pos);
        if (breakWordChars.indexOf(c) >= 0 || !Character.isJavaIdentifierPart(c) && wordChars.indexOf(c) < 0)
          break;
        ++pos;
      }
      endPos = pos;

      pos = caretPos;

      while (pos >= 0) {
        c = doc.getChar(pos);
        if (breakWordChars.indexOf(c) >= 0 || !Character.isJavaIdentifierPart(c) && wordChars.indexOf(c) < 0)
          break;
        --pos;
      }

      startPos = pos;

     
      if(startPos != endPos) { 
        selectRange(startPos, endPos);
//        markOccurrences(this.selectionText);
      }
      return true;

    } catch (BadLocationException x) {
      // ?
    }

    return false;
  }
  private void selectRange(int startPos, int stopPos)
  {
    int offset = startPos + 1;
    int length = stopPos - offset;
    this.fViewer.setSelectedRange(offset, length);
  }   
   
   
    /**
     * Sent when a mouse button is pressed.
     *
     * @param e an event containing information about the mouse button press
     */
    public void mouseDown(MouseEvent e) {
        if ((e.stateMask & SWT.CONTROL) == 0) {
            this.mouseDown = true;
            this.downUp = true;
        }
        this.lastMouseEvent = e;
    }

    /**
     * Sent when a mouse button is released.
     *
     * @param e an event containing information about the mouse button release
     */
    public void mouseUp(MouseEvent e) {
        if ((e.stateMask & SWT.CONTROL) == 0) {
            this.mouseDown = false;
          if (this.downUp) {
              reset();
          }
          if (this.selectionStart >= 0) {
              checkFolding();
          }
         
        }
    }

 
  /**
   * Returns true if the given point is on top of a selection.
   *
   * @param pt - Point in widget co-ordinates
   * @return
   */
  private boolean pointOnSelection(Point pt) {
      try {
          if (this.selectionStart >= 0) {
              int offset = this.widgetOffsetTracker.getWidgetOffset(pt);
              // Convert to viewer co-ordinates
              offset = this.fViewer.widgetOffset2ModelOffset(offset);
             
              if(this.selectionStart <= offset
                      && this.selectionStart + this.selectionText.length() > offset) {
                   return true;
              }
          }
      }
        catch (Exception ex) {
            // do nothing
        }
        return false;
  }
   
  protected void markBeginEndTags(CfmlTagItem tagItem) {
    if(tagItem.getMatchingItem() != null) {     
      Map<String, String> tagOpen = new HashMap<String, String>();
      Map<String, String> tagClose = new HashMap<String, String>();
      MarkerUtilities.setMessage(tagOpen, "Open " + tagItem.getName());
      MarkerUtilities.setLineNumber(tagOpen, tagItem.getLineNumber());
      tagOpen.put(IMarker.LOCATION, "line " + tagItem.getLineNumber() + ", Chars " + tagItem.getStartPosition() + "-" + tagItem.getEndPosition());
      tagOpen.put(IMarker.CHAR_START, Integer.toString(tagItem.getStartPosition()));
      tagOpen.put(IMarker.CHAR_END, Integer.toString(tagItem.getEndPosition()));

      MarkerUtilities.setMessage(tagClose, "Close " + tagItem.getName());
      MarkerUtilities.setLineNumber(tagClose, tagItem.getMatchingItem().getLineNumber());
      tagClose.put(IMarker.LOCATION, "line " + tagItem.getMatchingItem().getLineNumber() + ", Chars " + tagItem.getMatchingItem().getStartPosition() + "-" + tagItem.getMatchingItem().getEndPosition());
      tagClose.put(IMarker.CHAR_START, Integer.toString(tagItem.getMatchingItem().getStartPosition()));
      tagClose.put(IMarker.CHAR_END, Integer.toString(tagItem.getMatchingItem().getEndPosition()));
     
      try {
        ICFDocument doc = ((ICFDocument) this.fViewer.getDocument());
        MarkerUtilities.createMarker(doc.getResource(), tagOpen, SelectionCursorListener.tagBeginEndAnnotation);
        MarkerUtilities.createMarker(doc.getResource(), tagClose, SelectionCursorListener.tagBeginEndAnnotation);
      } catch (CoreException excep) {
        excep.printStackTrace();
      } catch (Exception anyExcep) {
        anyExcep.printStackTrace();
      }   
    }
  }

  /**
   * Clears any begin end tag markers
   */
  public void clearTagBeginEndMarkers() {
    if (this.fViewer == null)
      return;

        try {
      IMarker[] markers = ((ICFDocument)this.fViewer.getDocument()).getResource().findMarkers(this.tagBeginEndAnnotation, true, IResource.DEPTH_INFINITE);
      for(IMarker mark : markers) {
        mark.delete();
      }
    } catch (CoreException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

  }
 
  /**
   * Finds and marks occurrence annotations.
   *
   * @since 3.1
   */
  class OccurrencesFinderJob extends Job {
   
    private IDocument fDocument;
    private ISelection fSelection;
    private ISelectionValidator fPostSelectionValidator;
    private boolean fCanceled= false;
    private IProgressMonitor fProgressMonitor;
    private List fPositions;
   
    public OccurrencesFinderJob(IDocument document, List positions, ISelection selection) {
      super("Occurrences Marker"); //$NON-NLS-1$
      fDocument= document;
      fSelection= selection;
      fPositions= positions;
     
      if (editor.getSelectionProvider() instanceof ISelectionValidator)
        fPostSelectionValidator= (ISelectionValidator)editor.getSelectionProvider();
    }
   
    // cannot use cancel() because it is declared final
    void doCancel() {
      fCanceled= true;
      cancel();
    }
   
    private boolean isCanceled() {
      return fCanceled || fProgressMonitor.isCanceled() || fForcedMarkOccurrencesSelection == fSelection;

      //      return fCanceled || fProgressMonitor.isCanceled()
//        ||  fPostSelectionValidator != null && !(fPostSelectionValidator.isValid(fSelection) || fForcedMarkOccurrencesSelection == fSelection)
//        || LinkedModeModel.hasInstalledModel(fDocument);
    }
   
    /*
     * @see Job#run(org.eclipse.core.runtime.IProgressMonitor)
     */
    public IStatus run(IProgressMonitor progressMonitor) {
     
      fProgressMonitor= progressMonitor;
     
      if (isCanceled())
        return Status.CANCEL_STATUS;
     
      ITextViewer textViewer= (ITextViewer) fViewer;
      if (textViewer == null)
        return Status.CANCEL_STATUS;
     
      IDocument document= textViewer.getDocument();
      if (document == null)
        return Status.CANCEL_STATUS;
     
      IDocumentProvider documentProvider= editor.getDocumentProvider();
      if (documentProvider == null)
        return Status.CANCEL_STATUS;
   
      IAnnotationModel annotationModel= documentProvider.getAnnotationModel(editor.getEditorInput());
      if (annotationModel == null)
        return Status.CANCEL_STATUS;
     
      // Add occurrence annotations
      int length= fPositions.size();
      Map<Annotation, Position> annotationMap = new ConcurrentHashMap<Annotation, Position>(length);
      for (int i= 0; i < length; i++) {
       
        if (isCanceled())
          return Status.CANCEL_STATUS;
       
        String message;
        Position position= (Position) fPositions.get(i);
       
        // Create & add annotation
        try {
          message= document.get(position.offset, position.length);
        } catch (BadLocationException ex) {
          fPositions.remove(i);
          // Skip this match
          continue;
        }
        annotationMap.put(
            new Annotation("org.cfeclipse.cfml.occurrenceAnnotation", false, message), //$NON-NLS-1$
            position);
      }
     
      if (isCanceled()) {
        return Status.CANCEL_STATUS;
            }
     
      Object lock = ((ISynchronizable) annotationModel).getLockObject();
      if (lock == null) {
        updateAnnotations(annotationModel, annotationMap);
      } else {
        synchronized (lock) {
          updateAnnotations(annotationModel, annotationMap);
        }
      }

      return Status.OK_STATUS;
    }

        private void updateAnnotations(IAnnotationModel annotationModel, Map annotationMap) {
            if (annotationModel instanceof IAnnotationModelExtension) {
        if (fOccurrenceAnnotations != null && fOccurrenceAnnotations.length > 0) {
                ((IAnnotationModelExtension)annotationModel).replaceAnnotations(fOccurrenceAnnotations, annotationMap);
              }
            } else {
              removeOccurrenceAnnotations();
              Iterator iter= annotationMap.entrySet().iterator();
              while (iter.hasNext()) {
                Map.Entry mapEntry= (Map.Entry)iter.next();
                annotationModel.addAnnotation((Annotation)mapEntry.getKey(), (Position)mapEntry.getValue());
              }
            }
            fOccurrenceAnnotations= (Annotation[])annotationMap.keySet().toArray(new Annotation[annotationMap.keySet().size()]);
        }
  } 
 
  /**
   * Cancels the occurrences finder job upon document changes.
   *
   * @since 3.1
   */
  class OccurrencesFinderJobCanceler implements IDocumentListener, ITextInputListener {

    public void install() {
      ISourceViewer sourceViewer= fViewer;
      if (sourceViewer == null)
        return;
       
      StyledText text= sourceViewer.getTextWidget();
      if (text == null || text.isDisposed())
        return;

      sourceViewer.addTextInputListener(this);
     
      IDocument document= sourceViewer.getDocument();
      if (document != null)
        document.addDocumentListener(this);
    }
   
    public void uninstall() {
      ISourceViewer sourceViewer= fViewer;
      if (sourceViewer != null)
        sourceViewer.removeTextInputListener(this);

      IDocumentProvider documentProvider= editor.getDocumentProvider();
      if (documentProvider != null) {
        IDocument document= documentProvider.getDocument(editor.getEditorInput());
        if (document != null)
          document.removeDocumentListener(this);
      }
    }
       

    /*
     * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent)
     */
    public void documentAboutToBeChanged(DocumentEvent event) {
      if (fOccurrencesFinderJob != null)
        fOccurrencesFinderJob.doCancel();
    }

    /*
     * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent)
     */
    public void documentChanged(DocumentEvent event) {
    }

    /*
     * @see org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument)
     */
    public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) {
      if (oldInput == null)
        return;

      oldInput.removeDocumentListener(this);
    }

    /*
     * @see org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument)
     */
    public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {
      if (newInput == null)
        return;
      newInput.addDocumentListener(this);
    }
  }
 
 
  public void installOccurrencesFinder() {
    fMarkOccurrenceAnnotations= true;
   
    if (editor.getSelectionProvider() != null) {
      ISelection selection= editor.getSelectionProvider().getSelection();
      if (selection instanceof ITextSelection) {
        fForcedMarkOccurrencesSelection= (ITextSelection) selection;
        updateOccurrenceAnnotations(fForcedMarkOccurrencesSelection, editor.getCFModel());
      }
    }
    if (fOccurrencesFinderJobCanceler == null) {
      fOccurrencesFinderJobCanceler= new OccurrencesFinderJobCanceler();
      fOccurrencesFinderJobCanceler.install();
    }
  }
 
  public void uninstallOccurrencesFinder() {
    fMarkOccurrenceAnnotations= false;
   
    if (fOccurrencesFinderJob != null) {
      fOccurrencesFinderJob.cancel();
      fOccurrencesFinderJob= null;
    }

    if (fOccurrencesFinderJobCanceler != null) {
      fOccurrencesFinderJobCanceler.uninstall();
      fOccurrencesFinderJobCanceler= null;
    }
   
    removeOccurrenceAnnotations();
  }

  /**
   * Updates the occurrences annotations based
   * on the current selection.
   *
   * @param selection the text selection
   * @param antModel the model for the buildfile
   * @since 3.1
   */
  public void updateOccurrenceAnnotations(ITextSelection selection, CFDocument antModel) {

    if (fOccurrencesFinderJob != null)
      fOccurrencesFinderJob.cancel();

    if (!fMarkOccurrenceAnnotations) {
      return;
    }
   
    if (selection == null || antModel == null) {
      return;
    }
   
    IDocument document= fViewer.getDocument();
    if (document == null) {
      return;
    }
   
    List positions= null;

    OccurrencesFinder finder= new OccurrencesFinder(editor, antModel, document, selection.getOffset());
    positions= finder.perform();
   
    if (positions == null || positions.size() == 0) {
      if (!fStickyOccurrenceAnnotations) {
        removeOccurrenceAnnotations();
      }
      return;
    }
   
    fOccurrencesFinderJob= new OccurrencesFinderJob(document, positions, selection);
    fOccurrencesFinderJob.run(new NullProgressMonitor());
  }
 
  public void removeOccurrenceAnnotations() {
    IDocumentProvider documentProvider= editor.getDocumentProvider();
    if (documentProvider == null) {
      return;
    }
   
    IAnnotationModel annotationModel= documentProvider.getAnnotationModel(editor.getEditorInput());
    if (annotationModel == null || fOccurrenceAnnotations == null) {
      return;
    }

    IDocument document= documentProvider.getDocument(editor.getEditorInput());
        Object lock= editor.getLockObject(document);
        if (lock == null) {
            updateAnnotationModelForRemoves(annotationModel);
        } else {
            synchronized (lock) {
                updateAnnotationModelForRemoves(annotationModel);
            }
        }
  }


    private void updateAnnotationModelForRemoves(IAnnotationModel annotationModel) {
        if (annotationModel instanceof IAnnotationModelExtension) {
          ((IAnnotationModelExtension)annotationModel).replaceAnnotations(fOccurrenceAnnotations, null);
        } else {
          for (int i= 0, length= fOccurrenceAnnotations.length; i < length; i++) {
            annotationModel.removeAnnotation(fOccurrenceAnnotations[i]);
          }
        }
        fOccurrenceAnnotations= null;
   
  public boolean isMarkingOccurrences() {
    return fMarkOccurrenceAnnotations;
 
 
}
TOP

Related Classes of org.cfeclipse.cfml.editors.dnd.SelectionCursorListener

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.