Package org.jboss.ide.eclipse.freemarker.editor

Source Code of org.jboss.ide.eclipse.freemarker.editor.Editor$Validator

/*
* JBoss by Red Hat
* Copyright 2006-2009, Red Hat Middleware, LLC, and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.ide.eclipse.freemarker.editor;

import java.io.Reader;
import java.io.StringReader;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.ITextViewerExtension2;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.MatchingCharacterPainter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
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.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.editors.text.TextEditor;
import org.eclipse.ui.texteditor.ContentAssistAction;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.eclipse.ui.texteditor.MarkerUtilities;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.jboss.ide.eclipse.freemarker.Plugin;
import org.jboss.ide.eclipse.freemarker.configuration.ConfigurationManager;
import org.jboss.ide.eclipse.freemarker.lang.LexicalConstants;
import org.jboss.ide.eclipse.freemarker.lang.ParserUtils;
import org.jboss.ide.eclipse.freemarker.model.Item;
import org.jboss.ide.eclipse.freemarker.model.ItemSet;
import org.jboss.ide.eclipse.freemarker.outline.OutlinePage;
import org.jboss.ide.eclipse.freemarker.preferences.Preferences;
import org.jboss.ide.eclipse.freemarker.preferences.Preferences.PreferenceKey;
import org.jboss.ide.eclipse.freemarker.target.TargetLanguageSupport;
import org.jboss.ide.eclipse.freemarker.target.TargetLanguages;

import freemarker.core.ParseException;
import freemarker.template.Configuration;
import freemarker.template.Template;

/**
* @author <a href="mailto:joe@binamics.com">Joe Hudson</a>
*/
public class Editor extends TextEditor implements KeyListener, MouseListener {

  private OutlinePage fOutlinePage;
  private org.jboss.ide.eclipse.freemarker.editor.Configuration configuration;

  private ItemSet itemSet;
  private Item selectedItem;
  private Item[] relatedItems;
  private static final char[] VALIDATION_TOKENS = new char[] {
      LexicalConstants.QUOT, LexicalConstants.LEFT_SQUARE_BRACKET,
      LexicalConstants.RIGHT_SQUARE_BRACKET, LexicalConstants.COMMA,
      LexicalConstants.PERIOD, LexicalConstants.LF, '4' };
  private boolean readOnly = false;

  private boolean mouseDown = false;
  private boolean ctrlDown = false;
  private boolean shiftDown = false;

  public Editor() {
    super();
    configuration = new org.jboss.ide.eclipse.freemarker.editor.Configuration(
        getPreferenceStore(), this);
    setSourceViewerConfiguration(configuration);
    setDocumentProvider(new DocumentProvider());

  }

  @Override
  public void dispose() {
    ConfigurationManager.getInstance(getProject()).reload();
    super.dispose();
    if (matchingCharacterPainter != null) {
      matchingCharacterPainter.dispose();
    }
  }

  @Override
  public Object getAdapter(@SuppressWarnings("rawtypes") Class aClass) {
    Object adapter;
    if (aClass.equals(IContentOutlinePage.class)) {
      if (fOutlinePage == null) {
        fOutlinePage = new OutlinePage(this);
        if (getEditorInput() != null) {
          fOutlinePage.setInput(getEditorInput());
        }
      }
      adapter = fOutlinePage;
    } else {
      adapter = super.getAdapter(aClass);
    }
    return adapter;
  }

  protected static final char[] BRACKETS = { LexicalConstants.LEFT_BRACE,
      LexicalConstants.RIGHT_BRACE, LexicalConstants.LEFT_PARENTHESIS,
      LexicalConstants.RIGHT_PARENTHESIS,
      LexicalConstants.LEFT_SQUARE_BRACKET,
      LexicalConstants.RIGHT_SQUARE_BRACKET,
      LexicalConstants.LEFT_ANGLE_BRACKET,
      LexicalConstants.RIGHT_ANGLE_BRACKET };
  private MatchingCharacterPainter matchingCharacterPainter;

  @Override
  public void createPartControl(Composite parent) {
    super.createPartControl(parent);
    getSourceViewer().getTextWidget().addKeyListener(this);
    getSourceViewer().getTextWidget().addMouseListener(this);
    // matchingCharacterPainter = new MatchingCharacterPainter(
    // getSourceViewer(),
    // new JavaPairMatcher(BRACKETS));
    // ((SourceViewer)
    // getSourceViewer()).addPainter(matchingCharacterPainter);
  }

  @Override
  protected void createActions() {
    super.createActions();
    // Add content assist propsal action
    ContentAssistAction action = new ContentAssistAction(Plugin
        .getDefault().getResourceBundle(),
        "FreemarkerEditor.ContentAssist", this); //$NON-NLS-1$
    action.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
    setAction("FreemarkerEditor.ContentAssist", action); //$NON-NLS-1$
    action.setEnabled(true);
  }

  @Override
  protected void handleCursorPositionChanged() {
    super.handleCursorPositionChanged();
    if (!mouseDown) {
      int offset = getCaretOffset();
      Item item = getItemSet().getSelectedItem(offset);
      if (null == item && offset > 0)
        item = getItemSet().getSelectedItem(offset - 1);
      if (Preferences.getInstance().getBoolean(
          PreferenceKey.HIGHLIGHT_RELATED_ITEMS)) {
        if (null != item && null != item.getRelatedItems()
            && item.getRelatedItems().length > 0) {
          highlightRelatedRegions(item.getRelatedItems(), item);
        } else {
          highlightRelatedRegions(null, item);
        }
      }
      if (null == item) {
        item = getItemSet().getContextItem(getCaretOffset());
      }
      if (null != fOutlinePage) {
        fOutlinePage.update(item);
      }
    }
  }

  @Override
  public void mouseDoubleClick(MouseEvent e) {
  }

  @Override
  public void mouseDown(MouseEvent e) {
    mouseDown = true;
  }

  @Override
  public void mouseUp(MouseEvent e) {
    mouseDown = false;
    handleCursorPositionChanged();
  }

  public void select(Item item) {
    selectAndReveal(item.getRegion().getOffset(), item.getRegion()
        .getLength());
  }

  public IDocument getDocument() {
    ISourceViewer viewer = getSourceViewer();
    if (viewer != null) {
      return viewer.getDocument();
    }
    return null;
  }

  public ITextViewer getTextViewer() {
    return getSourceViewer();
  }

  public void addProblemMarker(String aMessage, int aLine) {
    IFile file = ((IFileEditorInput) getEditorInput()).getFile();
    try {
      Map<String, Object> attributes = new HashMap<String, Object>(5);
      attributes.put(IMarker.SEVERITY,
          Integer.valueOf(IMarker.SEVERITY_ERROR));
      attributes.put(IMarker.LINE_NUMBER, Integer.valueOf(aLine));
      attributes.put(IMarker.MESSAGE, aMessage);
      attributes.put(IMarker.TEXT, aMessage);
      MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
    } catch (CoreException e) {
      Plugin.log(e);
    }
  }

  private synchronized void highlightRelatedRegions(Item[] items,
      Item selectedItem) {
    if (null == items || items.length == 0) {
      if (null != relatedItems && relatedItems.length > 0) {
        for (int i = 0; i < relatedItems.length; i++) {
          if (getDocument().getLength() >= relatedItems[i]
              .getRegion().getOffset()
              + relatedItems[i].getRegion().getLength()) {
            if (null == this.selectedItem
                || !relatedItems[i].equals(this.selectedItem))
              resetRange(relatedItems[i].getRegion());
          }
        }
      }
      relatedItems = null;
    }
    if (null != relatedItems) {
      for (int i = 0; i < relatedItems.length; i++) {
        if (getDocument().getLength() >= relatedItems[i].getRegion()
            .getOffset() + relatedItems[i].getRegion().getLength()) {
          if (null == this.selectedItem
              || !relatedItems[i].equals(this.selectedItem))
            resetRange(relatedItems[i].getRegion());
        }
      }
    }
    if (null != items && items.length > 0) {
      for (int i = 0; i < items.length; i++) {
        if (getDocument().getLength() >= items[i].getRegion()
            .getOffset() + items[i].getRegion().getLength()
            && !items[i].equals(selectedItem)) {
          ITypedRegion region = items[i].getRegion();
          getSourceViewer().getTextWidget().setStyleRange(
              new StyleRange(region.getOffset(), region
                  .getLength(), null, Preferences
                  .getInstance().getColor(
                      PreferenceKey.COLOR_RELATED_ITEM)));
        }
      }
    }
    relatedItems = items;
    this.selectedItem = selectedItem;
  }

  private void resetRange(ITypedRegion region) {
    if (getSourceViewer() instanceof ITextViewerExtension2)
      ((ITextViewerExtension2) getSourceViewer())
          .invalidateTextPresentation(region.getOffset(),
              region.getLength());
    else
      getSourceViewer().invalidateTextPresentation();
  }

  public Item getSelectedItem(boolean allowFudge) {
    int caretOffset = getCaretOffset();
    Item item = getItemSet().getSelectedItem(getCaretOffset());
    if (null == item && caretOffset > 0)
      item = getItemSet().getSelectedItem(caretOffset - 1);
    return item;
  }

  public Item getSelectedItem() {
    return getItemSet().getSelectedItem(getCaretOffset());
  }

  public int getCaretOffset() {
    return getSourceViewer().getTextWidget().getCaretOffset();
  }

  public ItemSet getItemSet() {
    if (null == this.itemSet) {
      this.itemSet = createItemSet(Collections.<ITypedRegion> emptyList());
    }
    return this.itemSet;
  }

  /**
   * Creates a new {@link ItemSet} based on the given {@link List} or regions.
   * This method is public for the sake of testing.
   *
   * @param regions
   * @return
   */
  public ItemSet createItemSet(List<ITypedRegion> regions) {
    IResource resource = null;
    if (getEditorInput() instanceof IFileEditorInput) {
      resource = ((IFileEditorInput) getEditorInput()).getFile();
      // } else if (getEditorInput() instanceof JarEntryEditorInput) {
      // resource = null;
    }
    return new ItemSet(getSourceViewer(), regions, resource);
  }

  public OutlinePage getOutlinePage() {
    return fOutlinePage;
  }

  @Override
  public void keyPressed(KeyEvent e) {
    if (e.keyCode == SWT.CTRL) {
      ctrlDown = true;
    }
    if (e.keyCode == SWT.SHIFT) {
      shiftDown = true;
    }
    if (e.keyCode == LexicalConstants.RIGHT_SQUARE_BRACKET) {
      try {
        char c = getDocument().getChar(getCaretOffset());
        if (c == LexicalConstants.RIGHT_SQUARE_BRACKET) {
          // remove this
          getDocument().replace(getCaretOffset(), 1, ""); //$NON-NLS-1$
        }
      } catch (BadLocationException e1) {
      }
    } else if (e.keyCode == LexicalConstants.RIGHT_BRACE) {
      try {
        char c = getDocument().getChar(getCaretOffset());
        if (c == LexicalConstants.RIGHT_BRACE) {
          // remove this
          getDocument().replace(getCaretOffset(), 1, ""); //$NON-NLS-1$
        }
      } catch (BadLocationException e1) {
      }
    }
  }

  @Override
  public void keyReleased(KeyEvent e) {
    if (e.keyCode == SWT.CTRL) {
      ctrlDown = false;
    } else if (e.keyCode == SWT.SHIFT) {
      shiftDown = false;
    }
    try {
      IDocument document = getSourceViewer().getDocument();
      if (shiftDown && (e.keyCode == '3' || e.keyCode == '2')) {
        int offset = getCaretOffset();
        char c = document.getChar(offset - 2);
        if (c == LexicalConstants.LEFT_SQUARE_BRACKET
            || c == LexicalConstants.LEFT_ANGLE_BRACKET) {
          // directive
          char endChar = ParserUtils.getMatchingRightBracket(c);
          if (document.getLength() > offset) {
            if (offset > 0) {
              for (int i = offset + 1; i < document.getLength(); i++) {
                char c2 = document.getChar(i);
                if (c2 == endChar) {
                  return;
                } else if (c2 == LexicalConstants.LF) {
                  break;
                }
              }
              document.replace(offset, 0, String.valueOf(endChar));
            }
          } else {
            document.replace(offset, 0, String.valueOf(endChar));
          }
        }
      } else if (shiftDown && e.keyCode == LexicalConstants.LEFT_BRACE) {
        int offset = getCaretOffset();
        char c = document.getChar(offset - 2);
        if (c == LexicalConstants.DOLLAR) {
          // interpolation
          if (document.getLength() > offset) {
            if (offset > 0) {
              for (int i = offset + 1; i < document.getLength(); i++) {
                char c2 = document.getChar(i);
                if (c2 == LexicalConstants.RIGHT_BRACE) {
                  return;
                } else if (c2 == LexicalConstants.LF) {
                  break;
                }
              }
              document.replace(offset, 0, String
                  .valueOf(LexicalConstants.RIGHT_BRACE));
            }
          } else {
            document.replace(offset, 0,
                String.valueOf(LexicalConstants.RIGHT_BRACE));
          }
        }
      }
    } catch (BadLocationException exc) {
      // do nothing
    }

    boolean stale = false;
    if (e.keyCode == SWT.DEL || e.keyCode == SWT.BS) {
      stale = true;
    } else if (null != getSelectedItem(true)) {
      stale = true;
    } else {
      char c = (char) e.keyCode;
      for (int j = 0; j < VALIDATION_TOKENS.length; j++) {
        if (c == VALIDATION_TOKENS[j]) {
          stale = true;
          break;
        }
      }
      if (ctrlDown && (e.keyCode == 'v' || e.keyCode == 'x')) {
        stale = true;
      }
    }
    if (stale) {
      int offset = getCaretOffset();
      Item item = getItemSet().getSelectedItem(offset);
      if (null == item && offset > 0)
        item = getItemSet().getSelectedItem(offset - 1);
      if (Preferences.getInstance().getBoolean(
          PreferenceKey.HIGHLIGHT_RELATED_ITEMS)) {
        if (null != item && null != item.getRelatedItems()
            && item.getRelatedItems().length > 0) {
          highlightRelatedRegions(item.getRelatedItems(), item);
        } else {
          highlightRelatedRegions(null, item);
        }
      }
      validateContents();
    }
  }

  public static Validator VALIDATOR;

  public synchronized void validateContents() {
    if (null == VALIDATOR) {
      VALIDATOR = new Validator(this);
      VALIDATOR.start();
    }
  }

  public IProject getProject() {
    return ((IFileEditorInput) getEditorInput()).getFile().getProject();
  }

  public IFile getFile() {
    return (null != getEditorInput()) ? ((IFileEditorInput) getEditorInput())
        .getFile() : null;
  }

  private Configuration fmConfiguration;
  private TargetLanguageSupport targetLanguageSupport;

  public class Validator extends Thread {
    Editor editor;

    public Validator(Editor editor) {
      this.editor = editor;
    }

    @Override
    public void run() {
      try {
        if (null != getFile()) {
          if (null == fmConfiguration) {
            fmConfiguration = new Configuration();
            fmConfiguration
                .setTagSyntax(Configuration.AUTO_DETECT_TAG_SYNTAX);
          }
          getFile().deleteMarkers(IMarker.PROBLEM, true,
              IResource.DEPTH_INFINITE);
          String pageContents = getDocument().get();
          Reader reader = new StringReader(pageContents);
          /*
           * dummy is here to be able to suppres the warning about the
           * unused new Template()
           */
          @SuppressWarnings("unused")
          Template dummy = new Template(getFile().getName(), reader,
              fmConfiguration);
          reader.close();
        }
      } catch (ParseException e) {
        if (e.getMessage() != null) {
          String errorStr = e.getMessage();
          int errorLine = 0;
          try {
            errorLine = e.getLineNumber();
            if (errorLine == 0) {
              // sometimes they forget to put it in
              int index = e.getMessage().indexOf("line: "); //$NON-NLS-1$
              if (index > 0) {
                int index2 = e.getMessage().indexOf(
                    " ", index + 6); //$NON-NLS-1$
                int index3 = e.getMessage().indexOf(
                    ",", index + 6); //$NON-NLS-1$
                if (index3 < index2 && index3 > 0)
                  index2 = index3;
                String s = e.getMessage().substring(index + 6,
                    index2);
                try {
                  errorLine = Integer.parseInt(s);
                } catch (Exception e2) {
                }
              }
            }
          } catch (NullPointerException npe) {
            errorLine = 0;
          }
          editor.addProblemMarker(errorStr, errorLine);
        }
      } catch (Exception e) {
        Plugin.log(e);
      } finally {
        Editor.VALIDATOR = null;
      }
    }
  }

  @Override
  protected void editorSaved() {
    super.editorSaved();
    validateContents();
  }

  @Override
  public boolean isEditorInputReadOnly() {
    return readOnly;
  }

  public void setReadOnly(boolean readOnly) {
    this.readOnly = readOnly;
  }

  /**
   * Reconciles in the current thread using a newly create
   * {@link ReconcilingStrategy}.
   * <p>
   * For test purposes. Useful when testing functionality related to
   * {@link #getItemSet()} The {@link ReconcilingStrategy} configured inside
   * presentation reconciler works asynchronously and therefore
   * {@link #getItemSet()} returns an empty {@link ItemSet} when called from
   * the UI thread just after opening the editor. Calling this method before
   * {@link #getItemSet()} fixes the problem.
   * <p>
   * This method can be called from the UI thread.
   *
   */
  public void reconcileInstantly() {
    ReconcilingStrategy s = new ReconcilingStrategy(this);
    s.setDocument(getDocument());
    List<ITypedRegion> regions = s.parseRegions();
    reconcile(regions);
  }

  public void reconcile(List<ITypedRegion> regions) {
    /* re-create the model in the reconciler thread */
    final ItemSet newItemSet = createItemSet(regions);

    Runnable newItemSetTask = new Runnable() {
      @Override
      public void run() {
        Editor.this.itemSet = newItemSet;
        if (null != Editor.this.fOutlinePage) {
          Editor.this.fOutlinePage.refresh();
        }
      }
    };
    /* make sure to run in the UI thread */
    if (Thread.currentThread() == Display.getDefault().getThread()) {
      /* we are in the UI thread - run synchrounously */
      newItemSetTask.run();
    } else {
      /* run asynchronously */
      Display.getDefault().asyncExec(newItemSetTask);
    }

  }

  public TargetLanguageSupport getTargetLanguageSupport() {
    if (targetLanguageSupport == null) {
      targetLanguageSupport = TargetLanguages.findSupport(getEditorInput());
    }
    return targetLanguageSupport;
  }
}
TOP

Related Classes of org.jboss.ide.eclipse.freemarker.editor.Editor$Validator

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.