Package tk.eclipse.plugin.htmleditor.editors

Source Code of tk.eclipse.plugin.htmleditor.editors.HTMLHyperlinkSupport

package tk.eclipse.plugin.htmleditor.editors;

import java.util.ArrayList;

import jp.aonir.fuzzyxml.FuzzyXMLAttribute;
import jp.aonir.fuzzyxml.FuzzyXMLDocument;
import jp.aonir.fuzzyxml.FuzzyXMLElement;
import jp.aonir.fuzzyxml.FuzzyXMLParser;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.ui.JavaUI;
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.IRegion;
import org.eclipse.jface.text.ITextInputListener;
import org.eclipse.jface.text.ITextPresentationListener;
import org.eclipse.jface.text.ITextViewerExtension2;
import org.eclipse.jface.text.ITextViewerExtension4;
import org.eclipse.jface.text.ITextViewerExtension5;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.TextPresentation;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.texteditor.IDocumentProvider;

import tk.eclipse.plugin.htmleditor.HTMLPlugin;
import tk.eclipse.plugin.htmleditor.IHyperlinkProvider;

/**
* This class provides the hyperlink feature.
*
* @author Naoki Takezoe
*/
public class HTMLHyperlinkSupport implements KeyListener,MouseListener,MouseMoveListener,
  FocusListener, PaintListener, IDocumentListener, ITextInputListener, ITextPresentationListener {
 
  private boolean active;
  private IRegion activeRegion;
  private Cursor cursor;
  private Color color;
  private Object open;
  private Position fRememberedPosition;
  private IProject project;
  private HTMLSourceEditor editor;
  private ArrayList providers = new ArrayList();
 
  public HTMLHyperlinkSupport(HTMLSourceEditor editor){
    this.editor = editor;
  }
 
  /**
   * Add Hyperlink Provider.
   *
   * @param provider
   */
  public void addHyperlinkProvider(IHyperlinkProvider provider){
    this.providers.add(provider);
  }
 
  public void install() {
    ISourceViewer sourceViewer= editor.getViewer();
    if (sourceViewer == null)
      return;
     
    StyledText text= sourceViewer.getTextWidget();
    if (text == null || text.isDisposed())
      return;
   
    color = Display.getCurrent().getSystemColor(SWT.COLOR_BLUE);
//    updateColor(sourceViewer);

    sourceViewer.addTextInputListener(this);
   
    IDocument document= sourceViewer.getDocument();
    if (document != null)
      document.addDocumentListener(this);

    text.addKeyListener(this);
    text.addMouseListener(this);
    text.addMouseMoveListener(this);
    text.addFocusListener(this);
    text.addPaintListener(this);
   
    ((ITextViewerExtension4)sourceViewer).addTextPresentationListener(this);
   
//    updateKeyModifierMask();
   
//    IPreferenceStore preferenceStore= getPreferenceStore();
//    preferenceStore.addPropertyChangeListener(this);
  }
 
  public void uninstall() {

//    if (color != null) {
//      color.dispose();
//      color= null;
//    }
   
    if (cursor != null) {
      cursor.dispose();
      cursor= null;
    }
   
    ISourceViewer sourceViewer= editor.getViewer();
    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);
    }
     
//    IPreferenceStore preferenceStore= getPreferenceStore();
//    if (preferenceStore != null)
//      preferenceStore.removePropertyChangeListener(this);
   
    if (sourceViewer == null)
      return;
   
    StyledText text= sourceViewer.getTextWidget();
    if (text == null || text.isDisposed())
      return;
     
    text.removeKeyListener(this);
    text.removeMouseListener(this);
    text.removeMouseMoveListener(this);
    text.removeFocusListener(this);
    text.removePaintListener(this);
   
    ((ITextViewerExtension4)sourceViewer).removeTextPresentationListener(this);
  }
 
  public void deactivate() {
    deactivate(false);
  }
 
  public void deactivate(boolean redrawAll) {
    if (!active)
      return;
      repairRepresentation(redrawAll);
    active = false;
  }
 
  private void resetCursor(ISourceViewer viewer) {
    StyledText text= viewer.getTextWidget();
    if (text != null && !text.isDisposed())
      text.setCursor(null);
         
    if (cursor != null) {
      cursor.dispose();
      cursor= null;
    }
  }
 
  private void repairRepresentation() {
    repairRepresentation(false);
  }
 
  private void repairRepresentation(boolean redrawAll) {
    if (activeRegion == null)
      return;
   
    int offset= activeRegion.getOffset();
    int length= activeRegion.getLength();
    activeRegion= null;
     
    ISourceViewer viewer= editor.getViewer();
    if (viewer != null) {
     
      resetCursor(viewer);
     
      // Invalidate ==> remove applied text presentation
      if (!redrawAll && viewer instanceof ITextViewerExtension2)
        ((ITextViewerExtension2) viewer).invalidateTextPresentation(offset, length);
      else
        viewer.invalidateTextPresentation();
     
      // Remove underline
      if (viewer instanceof ITextViewerExtension5) {
        ITextViewerExtension5 extension= (ITextViewerExtension5) viewer;
        offset= extension.modelOffset2WidgetOffset(offset);
      } else {
        offset -= viewer.getVisibleRegion().getOffset();
      }
      try {
        StyledText text= viewer.getTextWidget();

        text.redrawRange(offset, length, false);
      } catch (IllegalArgumentException x) {
//        JavaPlugin.log(x);
      }
    }
  }
 
  public void keyPressed(KeyEvent e) {
    if (active) {
      deactivate();
      return
    }
    if (e.keyCode != SWT.CTRL) {
      deactivate();
      return;
    }
    active = true;
  }
 
  public void keyReleased(KeyEvent event) {
    if (!active)
      return;
    deactivate();
  }

 
  public void mouseUp(MouseEvent e) {
    if (!active)
      return;
     
    if (e.button != 1) {
      deactivate();
      return;
    }
   
    boolean wasActive= cursor != null;
    deactivate();
   
    if (wasActive) {
      try {
        if(open instanceof IFile){
          IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
          IDE.openEditor(window.getActivePage(),(IFile)open,true);
        } else if(open instanceof IJavaElement){
          JavaUI.revealInEditor(JavaUI.openInEditor((IJavaElement)open), (IJavaElement)open);
        }
      } catch(Exception ex){
        HTMLPlugin.logException(ex);
      }
    }
  }
 
  public void mouseDoubleClick(MouseEvent e) {}
 
  public void mouseDown(MouseEvent event) {
    if (!active)
      return;
     
    if (event.stateMask != SWT.CTRL) {
      deactivate();
      return
    }
    if (event.button != 1) {
      deactivate();
      return
    }     
  }
 
  public void mouseMove(MouseEvent event) {
   
    if (event.widget instanceof Control && !((Control) event.widget).isFocusControl()) {
      deactivate();
      return;
    }
   
    if (!active) {
      if (event.stateMask != SWT.CTRL)
        return;
      // modifier was already pressed
      active = true;
    }

    ISourceViewer viewer= editor.getViewer();
    if (viewer == null) {
      deactivate();
      return;
    }
     
    StyledText text= viewer.getTextWidget();
    if (text == null || text.isDisposed()) {
      deactivate();
      return;
    }
     
    if ((event.stateMask & SWT.BUTTON1) != 0 && text.getSelectionCount() != 0) {
      deactivate();
      return;
    }
 
    IRegion region= getCurrentTextRegion(viewer);
    if (region == null || region.getLength() == 0) {
      repairRepresentation();
      return;
    }
   
    highlightRegion(viewer, region);
    activateCursor(viewer);
  }
 
  private void activateCursor(ISourceViewer viewer) {
    StyledText text= viewer.getTextWidget();
    if (text == null || text.isDisposed())
      return;
    Display display= text.getDisplay();
    if (cursor == null)
      cursor= new Cursor(display, SWT.CURSOR_HAND);
    text.setCursor(cursor);
  }
 
  private IRegion selectWord(IDocument doc,int offset){
    FuzzyXMLDocument document = new FuzzyXMLParser().parse(editor.getHTMLSource());
    FuzzyXMLElement element = document.getElementByOffset(offset);
    if(element==null){
      return null;
    }
    FuzzyXMLAttribute[] attrs = element.getAttributes();
    for(int i=0;i<attrs.length;i++){
      if(attrs[i].getOffset() < offset && offset < attrs[i].getOffset()+attrs[i].getLength()){
        int attrOffset = getAttributeValueOffset(doc.get(),attrs[i]);
        int attrLength = attrs[i].getValue().length();
        if(attrOffset >= 0 && attrLength >= 0 && attrOffset <= offset){
          HTMLHyperlinkInfo info = getOpenFileInfo(document,element,attrs[i].getName(),attrs[i].getValue(),offset-attrOffset);
          if(info==null || info.getObject()==null){
            open = null;
            return null;
          } else {
            open = info.getObject();
            return new Region(attrOffset+info.getOffset(),info.getLength());
          }
        }
      }
    }
    return null;
  }
 
  /**
   * Returns a target of hyperlink.
   */
  private HTMLHyperlinkInfo getOpenFileInfo(FuzzyXMLDocument doc,FuzzyXMLElement element,String attrName,String attrValue,int offset){
    try {
      if(project==null){
        return null;
      }
      IFile file = ((IFileEditorInput)editor.getEditorInput()).getFile();
      for(int i=0;i<providers.size();i++){
        IHyperlinkProvider provider = (IHyperlinkProvider)this.providers.get(i);
        HTMLHyperlinkInfo info = provider.getHyperlinkInfo(file,doc,element,attrName,attrValue,offset);
        if(info!=null && info.getObject()!=null){
          return info;
        }
      }
      if(attrName.equalsIgnoreCase("href")){
        String href = attrValue;
        if(href.indexOf("#") > 0){
          href = href.substring(0,href.indexOf("#"));
        }
        IPath path = file.getParent().getProjectRelativePath();
        IResource resource = project.findMember(path.append(href));
        if(resource!=null && resource.exists() && resource instanceof IFile){
          HTMLHyperlinkInfo info = new HTMLHyperlinkInfo();
          info.setObject(resource);
          info.setOffset(0);
          info.setLength(attrValue.length());
          return info;
        }
      }
    } catch(Exception ex){
      HTMLPlugin.logException(ex);
    }
    return null;
  }
 
  /**
   * Returns an attribute value offset.
   */
  private int getAttributeValueOffset(String source,FuzzyXMLAttribute attr){
    int offset = source.indexOf('=',attr.getOffset());
    if(offset == -1){
      return -1;
    }
    char c = ' ';
    while(c==' ' || c=='\t' || c=='\r' || c=='\n' || c=='"' || c=='\''){
      offset++;
      if(source.length() == offset+1){
        break;
      }
      c = source.charAt(offset);
    }
    return offset;
  }
 
  private IRegion getCurrentTextRegion(ISourceViewer viewer) {

    int offset= getCurrentTextOffset(viewer);
    if (offset == -1)
      return null;

    return selectWord(viewer.getDocument(), offset);
  }

  private int getCurrentTextOffset(ISourceViewer viewer) {

    try {
      StyledText text= viewer.getTextWidget();
      if (text == null || text.isDisposed())
        return -1;

      Display display= text.getDisplay();
      Point absolutePosition= display.getCursorLocation();
      Point relativePosition= text.toControl(absolutePosition);
     
      int widgetOffset= text.getOffsetAtLocation(relativePosition);
      if (viewer instanceof ITextViewerExtension5) {
        ITextViewerExtension5 extension= (ITextViewerExtension5) viewer;
        return extension.widgetOffset2ModelOffset(widgetOffset);
      } else {
        return widgetOffset + viewer.getVisibleRegion().getOffset();
      }

    } catch (IllegalArgumentException e) {
      return -1;
    }
  }
 
  private void highlightRegion(ISourceViewer viewer, IRegion region) {

    if (region.equals(activeRegion))
      return;

    repairRepresentation();
   
    StyledText text= viewer.getTextWidget();
    if (text == null || text.isDisposed())
      return;
   
    // Underline
    int offset= 0;
    int length= 0;
    if (viewer instanceof ITextViewerExtension5) {
      ITextViewerExtension5 extension= (ITextViewerExtension5) viewer;
      IRegion widgetRange= extension.modelRange2WidgetRange(region);
      if (widgetRange == null)
        return;
       
      offset= widgetRange.getOffset();
      length= widgetRange.getLength();
     
    } else {
      offset= region.getOffset() - viewer.getVisibleRegion().getOffset();
      length= region.getLength();
    }
    text.redrawRange(offset, length, false);
   
    // Invalidate region ==> apply text presentation
    activeRegion = region;
    if (viewer instanceof ITextViewerExtension2)
      ((ITextViewerExtension2) viewer).invalidateTextPresentation(region.getOffset(), region.getLength());
    else
      viewer.invalidateTextPresentation();
  }
 
  public void focusGained(FocusEvent e) {}

  public void focusLost(FocusEvent event) {
    deactivate();
  }
 
  /*
   * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent)
   */
  public void documentAboutToBeChanged(DocumentEvent event) {
    if (active && activeRegion != null) {
      fRememberedPosition= new Position(activeRegion.getOffset(), activeRegion.getLength());
      try {
        event.getDocument().addPosition(fRememberedPosition);
      } catch (BadLocationException x) {
        fRememberedPosition= null;
      }
    }
  }

  /*
   * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent)
   */
  public void documentChanged(DocumentEvent event) {
    if (fRememberedPosition != null) {
      if (!fRememberedPosition.isDeleted()) {
       
        event.getDocument().removePosition(fRememberedPosition);
        activeRegion= new Region(fRememberedPosition.getOffset(), fRememberedPosition.getLength());
        fRememberedPosition= null;
       
        ISourceViewer viewer= editor.getViewer();
        if (viewer != null) {
          StyledText widget= viewer.getTextWidget();
          if (widget != null && !widget.isDisposed()) {
            widget.getDisplay().asyncExec(new Runnable() {
              public void run() {
                deactivate();
              }
            });
          }
        }
       
      } else {
        activeRegion= null;
        fRememberedPosition= null;
        deactivate();
      }
    }
  }

  public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) {
    if (oldInput == null)
      return;
    deactivate();
    oldInput.removeDocumentListener(this);
  }

  public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {
    if (newInput == null)
      return;
    newInput.addDocumentListener(this);
  }
 
  public void applyTextPresentation(TextPresentation textPresentation) {
    if (activeRegion == null)
      return;
    IRegion region= textPresentation.getExtent();
    if (activeRegion.getOffset() + activeRegion.getLength() >= region.getOffset() && region.getOffset() + region.getLength() > activeRegion.getOffset())
      textPresentation.mergeStyleRange(new StyleRange(activeRegion.getOffset(), activeRegion.getLength(), color, null));
  }

  public void paintControl(PaintEvent event) { 
    if (activeRegion == null)
      return;

    ISourceViewer viewer= editor.getViewer();
    if (viewer == null)
      return;
     
    StyledText text= viewer.getTextWidget();
    if (text == null || text.isDisposed())
      return;
     
     
    int offset= 0;
    int length= 0;

    if (viewer instanceof ITextViewerExtension5) {
     
      ITextViewerExtension5 extension= (ITextViewerExtension5) viewer;
      IRegion widgetRange= extension.modelRange2WidgetRange(activeRegion);
      if (widgetRange == null)
        return;
       
      offset= widgetRange.getOffset();
      length= widgetRange.getLength();
     
    } else {
     
      IRegion region= viewer.getVisibleRegion();     
      if (!includes(region, activeRegion))
        return;       
     
      offset= activeRegion.getOffset() - region.getOffset();
      length= activeRegion.getLength();
    }
   
    // support for bidi
    Point minLocation= getMinimumLocation(text, offset, length);
    Point maxLocation= getMaximumLocation(text, offset, length);

    int x1= minLocation.x;
    int x2= minLocation.x + maxLocation.x - minLocation.x - 1;
    int y= minLocation.y + text.getLineHeight() - 1;
   
    GC gc= event.gc;
    if (color != null && !color.isDisposed())
    gc.setForeground(color);
    gc.drawLine(x1, y, x2, y);
  }
 
  private boolean includes(IRegion region, IRegion position) {
    return
      position.getOffset() >= region.getOffset() &&
      position.getOffset() + position.getLength() <= region.getOffset() + region.getLength();
  }
 
  private Point getMinimumLocation(StyledText text, int offset, int length) {
    Point minLocation= new Point(Integer.MAX_VALUE, Integer.MAX_VALUE);

    for (int i= 0; i <= length; i++) {
      Point location= text.getLocationAtOffset(offset + i);
     
      if (location.x < minLocation.x)
        minLocation.x= location.x;     
      if (location.y < minLocation.y)
        minLocation.y= location.y;     
   
   
    return minLocation;
  }

  private Point getMaximumLocation(StyledText text, int offset, int length) {
    Point maxLocation= new Point(Integer.MIN_VALUE, Integer.MIN_VALUE);
    for (int i= 0; i <= length; i++) {
      Point location= text.getLocationAtOffset(offset + i);
     
      if (location.x > maxLocation.x)
        maxLocation.x= location.x;     
      if (location.y > maxLocation.y)
        maxLocation.y= location.y;     
   
   
    return maxLocation;
  }
 
  public void setProject(IProject project){
    this.project = project;
  }
 
}
TOP

Related Classes of tk.eclipse.plugin.htmleditor.editors.HTMLHyperlinkSupport

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.