Package org.eclipse.wst.sse.ui.internal

Source Code of org.eclipse.wst.sse.ui.internal.StructuredTextViewer

/*******************************************************************************
* Copyright (c) 2001, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*     Jens Lukowski/Innoopract - initial renaming/restructuring
*    
*******************************************************************************/
package org.eclipse.wst.sse.ui.internal;

import java.util.ArrayList;

import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentRewriteSession;
import org.eclipse.jface.text.DocumentRewriteSessionType;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentAdapter;
import org.eclipse.jface.text.IDocumentExtension4;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextPresentationListener;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.ITextViewerExtension2;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.text.contentassist.IContentAssistant;
import org.eclipse.jface.text.contentassist.IContentAssistantExtension2;
import org.eclipse.jface.text.contentassist.IContentAssistantExtension4;
import org.eclipse.jface.text.formatter.FormattingContext;
import org.eclipse.jface.text.formatter.FormattingContextProperties;
import org.eclipse.jface.text.formatter.IContentFormatterExtension;
import org.eclipse.jface.text.formatter.IFormattingContext;
import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
import org.eclipse.jface.text.information.IInformationPresenter;
import org.eclipse.jface.text.projection.ProjectionDocument;
import org.eclipse.jface.text.quickassist.IQuickAssistAssistant;
import org.eclipse.jface.text.reconciler.IReconciler;
import org.eclipse.jface.text.source.ContentAssistantFacade;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.IOverviewRuler;
import org.eclipse.jface.text.source.IVerticalRuler;
import org.eclipse.jface.text.source.SourceViewerConfiguration;
import org.eclipse.jface.text.source.projection.ProjectionViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.wst.sse.core.internal.cleanup.StructuredContentCleanupHandler;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
import org.eclipse.wst.sse.core.internal.undo.IDocumentSelectionMediator;
import org.eclipse.wst.sse.core.internal.undo.IStructuredTextUndoManager;
import org.eclipse.wst.sse.core.internal.undo.UndoDocumentEvent;
import org.eclipse.wst.sse.ui.StructuredTextViewerConfiguration;
import org.eclipse.wst.sse.ui.internal.provisional.style.AbstractLineStyleProvider;
import org.eclipse.wst.sse.ui.internal.provisional.style.CompatibleHighlighter;
import org.eclipse.wst.sse.ui.internal.provisional.style.Highlighter;
import org.eclipse.wst.sse.ui.internal.provisional.style.LineStyleProvider;
import org.eclipse.wst.sse.ui.internal.provisional.style.ReconcilerHighlighter;
import org.eclipse.wst.sse.ui.internal.reconcile.StructuredRegionProcessor;
import org.eclipse.wst.sse.ui.internal.util.PlatformStatusLineUtil;

/**
* <p>
* Like {@link org.eclipse.wst.sse.ui.StructuredTextEditor}, this class is not
* meant to be subclassed.<br />
*/
public class StructuredTextViewer extends ProjectionViewer implements IDocumentSelectionMediator {
  /** Text operation codes */
  private static final int BASE = ProjectionViewer.COLLAPSE_ALL; // see
  // ProjectionViewer.COLLAPSE_ALL
  private static final int CLEANUP_DOCUMENT = BASE + 4;
  public static final int FORMAT_ACTIVE_ELEMENTS = BASE + 3;

  private static final String FORMAT_ACTIVE_ELEMENTS_TEXT = SSEUIMessages.Format_Active_Elements_UI_; //$NON-NLS-1$
  public static final int FORMAT_DOCUMENT = BASE + 2;
  private static final String FORMAT_DOCUMENT_TEXT = SSEUIMessages.Format_Document_UI_; //$NON-NLS-1$
  private static final String TEXT_CUT = SSEUIMessages.Text_Cut_UI_; //$NON-NLS-1$
  private static final String TEXT_PASTE = SSEUIMessages.Text_Paste_UI_; //$NON-NLS-1$
  private static final String TEXT_SHIFT_LEFT = SSEUIMessages.Text_Shift_Left_UI_; //$NON-NLS-1$ = "Text Shift Left"
  private static final String TEXT_SHIFT_RIGHT = SSEUIMessages.Text_Shift_Right_UI_; //$NON-NLS-1$ = "Text Shift Right"
  private static final boolean TRACE_EXCEPTIONS = true;

  /*
   * Max length of chars to format before it is considered a "big format"
   * This is used to indication a small unrestricted rewrite session.
   */
  private final int MAX_SMALL_FORMAT_LENGTH = 1000;
  private boolean fBackgroundupdateInProgress;
  private StructuredContentCleanupHandler fContentCleanupHandler = null;
  //private IDocumentAdapter fDocAdapter;

  private Highlighter fHighlighter;
 
  private ReconcilerHighlighter fRecHighlighter = null;

  // private ViewerSelectionManager fViewerSelectionManager;
  private SourceViewerConfiguration fConfiguration;
  /*
   * True if formatter has been set
   */
  private boolean fFormatterSet = false;

  private ContentAssistantFacade fContentAssistantFacade;

  /**
   * @see org.eclipse.jface.text.source.SourceViewer#SourceViewer(Composite,
   *      IVerticalRuler, IOverviewRuler, boolean, int)
   */
  public StructuredTextViewer(Composite parent, IVerticalRuler verticalRuler, IOverviewRuler overviewRuler, boolean showAnnotationsOverview, int styles) {
    super(parent, verticalRuler, overviewRuler, showAnnotationsOverview, styles);
  }

  /**
   *
   */
  private void beep() {
    getTextWidget().getDisplay().beep();
  }

  public void beginBackgroundUpdate() {
    fBackgroundupdateInProgress = true;
    setRedraw(false);
  }

  protected void createControl(Composite parent, int styles) {
    // Forces LEFT_TO_RIGHT orientation unless otherwise suggested
    if ((styles & SWT.LEFT_TO_RIGHT) == 0 && (styles & SWT.RIGHT_TO_LEFT) == 0)
      styles |= SWT.LEFT_TO_RIGHT;
    super.createControl(parent, styles);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.jface.text.ITextOperationTarget#canDoOperation(int)
   */
  public boolean canDoOperation(int operation) {
    if (fBackgroundupdateInProgress) {
      return false;
    }
    switch (operation) {
      case CONTENTASSIST_PROPOSALS : {
        // (pa) if position isn't READ_ONLY (containsReadOnly()
        // returns false),
        // Otherwise, you DO want content assist (return true)
        IDocument doc = getDocument();
        if (doc != null && doc instanceof IStructuredDocument) {
          return isEditable() && (!((IStructuredDocument) doc).containsReadOnly(getSelectedRange().x, 0));
        }
        break;
      }
      case CLEANUP_DOCUMENT : {
        return (fContentCleanupHandler != null && isEditable());
      }
      case FORMAT_DOCUMENT :
      case FORMAT_ACTIVE_ELEMENTS : {
        // if formatter not set yet, contentformatter can be null
        return ((fContentFormatter != null || !fFormatterSet) && isEditable());
      }
    }
    return super.canDoOperation(operation);
  }

  /**
   * Should be identical to superclass version. Plus, we get our own special
   * Highlighter. Plus we uninstall before installing.
   */
  public void configure(SourceViewerConfiguration configuration) {

    if (getTextWidget() == null)
      return;

    setDocumentPartitioning(configuration.getConfiguredDocumentPartitioning(this));

    // always uninstall highlighter and null it out on new configuration
    if (fHighlighter != null) {
      fHighlighter.uninstall();
      fHighlighter = null;
    }

    if(fRecHighlighter != null) {
      fRecHighlighter.uninstall();
      fRecHighlighter = null;
    }
   
    // Bug 230297 - Uninstall presentation reconciler in preparation of a new one
    if(fPresentationReconciler != null) {
      fPresentationReconciler.uninstall();
      fPresentationReconciler = null;
    }

    IReconciler newReconciler = configuration.getReconciler(this);

    if (newReconciler != fReconciler || newReconciler == null || fReconciler == null) {

      if (fReconciler != null) {
        fReconciler.uninstall();
      }

      fReconciler = newReconciler;

      if (fReconciler != null) {
        fReconciler.install(this);
        // https://w3.opensource.ibm.com/bugzilla/show_bug.cgi?id=3858
        // still need set document on the reconciler (strategies)
        if (fReconciler instanceof StructuredRegionProcessor)
          ((StructuredRegionProcessor) fReconciler).setDocument(getDocument());
      }
    }

    IContentAssistant newAssistant = configuration.getContentAssistant(this);
    if (newAssistant != fContentAssistant || newAssistant == null || fContentAssistant == null) {
      if (fContentAssistant != null)
        fContentAssistant.uninstall();

      fContentAssistant = newAssistant;

      if (fContentAssistant != null) {
        fContentAssistant.install(this);
        if (fContentAssistant instanceof IContentAssistantExtension2 && fContentAssistant instanceof IContentAssistantExtension4)
          fContentAssistantFacade= new ContentAssistantFacade(fContentAssistant);
        fContentAssistantInstalled = true;
      }
      else {
        // 248036
        // disable the content assist operation if no content
        // assistant
        enableOperation(CONTENTASSIST_PROPOSALS, false);
        fContentAssistantInstalled = false;
      }
    }

    IQuickAssistAssistant quickAssistant = configuration.getQuickAssistAssistant(this);
    if (quickAssistant != fQuickAssistAssistant || quickAssistant == null || fQuickAssistAssistant == null) {
      if (fQuickAssistAssistant != null)
        fQuickAssistAssistant.uninstall();

      fQuickAssistAssistant = quickAssistant;

      if (fQuickAssistAssistant != null) {
        fQuickAssistAssistant.install(this);
        fQuickAssistAssistantInstalled = true;
      }
      else {
        // 248036
        // disable the content assist operation if no content
        // assistant
        enableOperation(QUICK_ASSIST, false);
        fQuickAssistAssistantInstalled = false;
      }
    }

    fContentFormatter = configuration.getContentFormatter(this);

    // do not uninstall old information presenter if it's the same
    IInformationPresenter newInformationPresenter = configuration.getInformationPresenter(this);
    if (newInformationPresenter == null || fInformationPresenter == null || !(newInformationPresenter.equals(fInformationPresenter))) {
      if (fInformationPresenter != null)
        fInformationPresenter.uninstall();
      fInformationPresenter = newInformationPresenter;
      if (fInformationPresenter != null)
        fInformationPresenter.install(this);
    }

    // disconnect from the old undo manager before setting the new one
    if (fUndoManager != null) {
      fUndoManager.disconnect();
    }
    setUndoManager(configuration.getUndoManager(this));

    // release old annotation hover before setting new one
    if (fAnnotationHover instanceof StructuredTextAnnotationHover) {
      ((StructuredTextAnnotationHover) fAnnotationHover).release();
    }
    setAnnotationHover(configuration.getAnnotationHover(this));

    // release old annotation hover before setting new one
    if (fOverviewRulerAnnotationHover instanceof StructuredTextAnnotationHover) {
      ((StructuredTextAnnotationHover) fOverviewRulerAnnotationHover).release();
    }
    setOverviewRulerAnnotationHover(configuration.getOverviewRulerAnnotationHover(this));

    getTextWidget().setTabs(configuration.getTabWidth(this));
    setHoverControlCreator(configuration.getInformationControlCreator(this));

    // if hyperlink manager has already been created, uninstall it
    if (fHyperlinkManager != null) {
      setHyperlinkDetectors(null, SWT.NONE);
    }
    setHyperlinkPresenter(configuration.getHyperlinkPresenter(this));
    IHyperlinkDetector[] hyperlinkDetectors = configuration.getHyperlinkDetectors(this);
    int eventStateMask = configuration.getHyperlinkStateMask(this);
    setHyperlinkDetectors(hyperlinkDetectors, eventStateMask);

    String[] types = configuration.getConfiguredContentTypes(this);

    // clear autoindent/autoedit strategies
    fAutoIndentStrategies = null;
   
    for (int i = 0; i < types.length; i++) {
      String t = types[i];
      setAutoEditStrategies(configuration.getAutoEditStrategies(this, t), t);
      setTextDoubleClickStrategy(configuration.getDoubleClickStrategy(this, t), t);

      int[] stateMasks = configuration.getConfiguredTextHoverStateMasks(this, t);
      if (stateMasks != null) {
        for (int j = 0; j < stateMasks.length; j++) {
          int stateMask = stateMasks[j];
          setTextHover(configuration.getTextHover(this, t, stateMask), t, stateMask);
        }
      }
      else {
        setTextHover(configuration.getTextHover(this, t), t, ITextViewerExtension2.DEFAULT_HOVER_STATE_MASK);
      }

      String[] prefixes = configuration.getIndentPrefixes(this, t);
      if (prefixes != null && prefixes.length > 0)
        setIndentPrefixes(prefixes, t);

      prefixes = configuration.getDefaultPrefixes(this, t);
      if (prefixes != null && prefixes.length > 0)
        setDefaultPrefixes(prefixes, t);

      // Bug 230297 - Add LineStyleProviders from the new configuration if
      // the document is set
      if(getDocument() != null) {
        // add highlighter/linestyleprovider
        LineStyleProvider[] providers = ((StructuredTextViewerConfiguration) configuration).getLineStyleProviders(this, t);
        if (providers != null) {
          for (int j = 0; j < providers.length; ++j) {
           
            if(fRecHighlighter == null) {
              fRecHighlighter = new ReconcilerHighlighter();
              ((StructuredTextViewerConfiguration) configuration).setHighlighter(fRecHighlighter);
            }
            if (providers[j] instanceof AbstractLineStyleProvider) {
              ((AbstractLineStyleProvider) providers[j]).init((IStructuredDocument) getDocument(), fRecHighlighter);
              fRecHighlighter.addProvider(t, providers[j]);
            }
            else {
              // init with compatibility instance
              if (fHighlighter == null) {
                fHighlighter = new CompatibleHighlighter();
              }
              Logger.log(Logger.INFO_DEBUG, "CompatibleHighlighter installing compatibility for " + providers[j].getClass()); //$NON-NLS-1$
              providers[j].init((IStructuredDocument) getDocument(), fHighlighter);
              fHighlighter.addProvider(t, providers[j]);
            }
          }
        }
      }
    }

    // initialize highlighter after linestyleproviders were added
    if (fHighlighter != null) {
      fHighlighter.setDocumentPartitioning(configuration.getConfiguredDocumentPartitioning(this));
      fHighlighter.setDocument((IStructuredDocument) getDocument());
      fHighlighter.install(this);
    }
   
    if (fRecHighlighter != null)
      fRecHighlighter.install(this);

    activatePlugins();

    fConfiguration = configuration;
   
    // Update the viewer's presentation reconciler
    fPresentationReconciler = configuration.getPresentationReconciler(this);
   
    if(fPresentationReconciler != null)
      fPresentationReconciler.install(this);
  }

  /**
   * @param document
   * @param startOffset
   * @param endOffset
   * @return
   */
  private boolean containsReadOnly(IDocument document, int startOffset, int endOffset) {

    int start = startOffset;
    int end = endOffset;
    IStructuredDocument structuredDocument = null;
    if (document instanceof IStructuredDocument) {
      structuredDocument = (IStructuredDocument) document;
    }
    else {
      if (document instanceof ProjectionDocument) {
        IDocument doc = ((ProjectionDocument) document).getMasterDocument();
        if (doc instanceof IStructuredDocument) {
          structuredDocument = (IStructuredDocument) doc;
          int adjust = ((ProjectionDocument) document).getProjectionMapping().getCoverage().getOffset();
          start = adjust + start;
          end = adjust + end;
        }
      }
    }
    if (structuredDocument == null) {
      return false;
    }
    else {
      int length = end - start;
      return structuredDocument.containsReadOnly(start, length);
    }
  }

  /**
   * @deprecated - present for compatibility only
   */
  protected IDocumentAdapter createDocumentAdapter() {
    return super.createDocumentAdapter();
  }


  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.jface.text.ITextOperationTarget#doOperation(int)
   */
  public void doOperation(int operation) {

    Point selection = getTextWidget().getSelection();
    int cursorPosition = selection.x;
    int selectionLength = selection.y - selection.x;
    switch (operation) {
      case CUT :
        beginRecording(TEXT_CUT, TEXT_CUT, cursorPosition, selectionLength);
        super.doOperation(operation);
        selection = getTextWidget().getSelection();
        cursorPosition = selection.x;
        selectionLength = selection.y - selection.x;
        endRecording(cursorPosition, selectionLength);
        break;
      case PASTE :
        beginRecording(TEXT_PASTE, TEXT_PASTE, cursorPosition, selectionLength);
        super.doOperation(operation);
        selection = getTextWidget().getSelection();
        cursorPosition = selection.x;
        selectionLength = selection.y - selection.x;
        endRecording(cursorPosition, selectionLength);
        break;
      case CONTENTASSIST_PROPOSALS :
        // maybe not configured?
        if (fContentAssistant != null && isEditable()) {
          // CMVC 263269
          // need an explicit check here because the
          // contentAssistAction is no longer being updated on
          // cursor
          // position
          if (canDoOperation(CONTENTASSIST_PROPOSALS)) {
            String err = fContentAssistant.showPossibleCompletions();
            if (err != null) {
              // don't wanna beep if there is no error
              PlatformStatusLineUtil.displayTemporaryErrorMessage(this, err);
            }
          }
          else
            beep();
        }
        break;
      case CONTENTASSIST_CONTEXT_INFORMATION :
        if (fContentAssistant != null) {
          String err = fContentAssistant.showContextInformation();
          if (err != null) {
            // don't wanna beep if there is no error
            PlatformStatusLineUtil.displayTemporaryErrorMessage(this, err);
          }
        }
        break;
      case SHIFT_RIGHT :
        beginRecording(TEXT_SHIFT_RIGHT, TEXT_SHIFT_RIGHT, cursorPosition, selectionLength);
        updateIndentationPrefixes();
        super.doOperation(SHIFT_RIGHT);
        selection = getTextWidget().getSelection();
        cursorPosition = selection.x;
        selectionLength = selection.y - selection.x;
        endRecording(cursorPosition, selectionLength);
        break;
      case SHIFT_LEFT :
        beginRecording(TEXT_SHIFT_LEFT, TEXT_SHIFT_LEFT, cursorPosition, selectionLength);
        updateIndentationPrefixes();
        super.doOperation(SHIFT_LEFT);
        selection = getTextWidget().getSelection();
        cursorPosition = selection.x;
        selectionLength = selection.y - selection.x;
        endRecording(cursorPosition, selectionLength);
        break;
      case FORMAT_DOCUMENT :
        DocumentRewriteSession rewriteSession = null;
        IDocument document = getDocument();
        try {
          /*
           * This command will actually format selection if text is
           * selected, otherwise format entire document
           */
          // begin recording
          beginRecording(FORMAT_DOCUMENT_TEXT, FORMAT_DOCUMENT_TEXT, cursorPosition, selectionLength);
          boolean formatDocument = false;
          IRegion region = null;
          Point s = getSelectedRange();
          if (s.y > 0) {
            // only format currently selected text
            region = new Region(s.x, s.y);
          }
          else {
            // no selection, so format entire document
            region = getModelCoverage();
            formatDocument = true;
          }

          if (document instanceof IDocumentExtension4) {
            IDocumentExtension4 extension = (IDocumentExtension4) document;
            DocumentRewriteSessionType type = (selection.y == 0 || selection.y > MAX_SMALL_FORMAT_LENGTH) ? DocumentRewriteSessionType.UNRESTRICTED : DocumentRewriteSessionType.UNRESTRICTED_SMALL;
            rewriteSession = (extension.getActiveRewriteSession() != null) ? null : extension.startRewriteSession(type);
          }
          else {
            setRedraw(false);
          }

          if (fContentFormatter instanceof IContentFormatterExtension) {
            IContentFormatterExtension extension = (IContentFormatterExtension) fContentFormatter;
            IFormattingContext context = new FormattingContext();
            context.setProperty(FormattingContextProperties.CONTEXT_DOCUMENT, Boolean.valueOf(formatDocument));
            context.setProperty(FormattingContextProperties.CONTEXT_REGION, region);
            extension.format(document, context);
          }
          else {
            fContentFormatter.format(document, region);
          }
        }
        finally {
          try {
            if (rewriteSession != null) {
              IDocumentExtension4 extension = (IDocumentExtension4) document;
              extension.stopRewriteSession(rewriteSession);
            }
            else {
              setRedraw(true);
            }
          }
          finally {
            // end recording
            selection = getTextWidget().getSelection();
            cursorPosition = selection.x;
            selectionLength = selection.y - selection.x;
            endRecording(cursorPosition, selectionLength);
          }
        }
        break;
      case FORMAT_ACTIVE_ELEMENTS :
        rewriteSession = null;
        document = getDocument();
        try {
          /*
           * This command will format the node at cursor position
           * (and all its children)
           */
          // begin recording
          beginRecording(FORMAT_ACTIVE_ELEMENTS_TEXT, FORMAT_ACTIVE_ELEMENTS_TEXT, cursorPosition, selectionLength);
          IRegion region = null;
          Point s = getSelectedRange();
          if (s.y > -1) {
            // only format node at cursor position
            region = new Region(s.x, s.y);
          }

          if (document instanceof IDocumentExtension4) {
            IDocumentExtension4 extension = (IDocumentExtension4) document;
            DocumentRewriteSessionType type = (selection.y == 0 || selection.y > MAX_SMALL_FORMAT_LENGTH) ? DocumentRewriteSessionType.UNRESTRICTED : DocumentRewriteSessionType.UNRESTRICTED_SMALL;
            rewriteSession = (extension.getActiveRewriteSession() != null) ? null : extension.startRewriteSession(type);
          }
          else {
            setRedraw(false);
          }

          if (fContentFormatter instanceof IContentFormatterExtension) {
            IContentFormatterExtension extension = (IContentFormatterExtension) fContentFormatter;
            IFormattingContext context = new FormattingContext();
            context.setProperty(FormattingContextProperties.CONTEXT_DOCUMENT, Boolean.FALSE);
            context.setProperty(FormattingContextProperties.CONTEXT_REGION, region);
            extension.format(getDocument(), context);
          }
          else {
            fContentFormatter.format(getDocument(), region);
          }
        }
        finally {
          try {
            if (rewriteSession != null) {
              IDocumentExtension4 extension = (IDocumentExtension4) document;
              extension.stopRewriteSession(rewriteSession);
            }
            else {
              setRedraw(true);
            }
          }
          finally {
            // end recording
            selection = getTextWidget().getSelection();
            cursorPosition = selection.x;
            selectionLength = selection.y - selection.x;
            endRecording(cursorPosition, selectionLength);
          }
        }
        break;
      default :
        super.doOperation(operation);
    }
  }

  private void endRecording(int cursorPosition, int selectionLength) {
    IDocument doc = getDocument();
    if (doc instanceof IStructuredDocument) {
      IStructuredDocument structuredDocument = (IStructuredDocument) doc;
      IStructuredTextUndoManager undoManager = structuredDocument.getUndoManager();

      // https://bugs.eclipse.org/bugs/show_bug.cgi?id=198617
      // undo after paste in document with folds - wrong behavior
      IRegion widgetSelection = new Region(cursorPosition, selectionLength);
      IRegion documentSelection = widgetRange2ModelRange(widgetSelection);
      if (documentSelection == null)
        documentSelection = widgetSelection;
      undoManager.endRecording(this, documentSelection.getOffset(), documentSelection.getLength());
    }
    else {
      // TODO: how to handle other document types?
    }
  }

  private void beginRecording(String label, String description, int cursorPosition, int selectionLength) {
    IDocument doc = getDocument();
    if (doc instanceof IStructuredDocument) {
      IStructuredDocument structuredDocument = (IStructuredDocument) doc;
      IStructuredTextUndoManager undoManager = structuredDocument.getUndoManager();

      // https://bugs.eclipse.org/bugs/show_bug.cgi?id=198617
      // undo after paste in document with folds - wrong behavior
      IRegion widgetSelection = new Region(cursorPosition, selectionLength);
      IRegion documentSelection = widgetRange2ModelRange(widgetSelection);
      if (documentSelection == null)
        documentSelection = widgetSelection;
      undoManager.beginRecording(this, label, description, documentSelection.getOffset(), documentSelection.getLength());
    }
    else {
      // TODO: how to handle other document types?
    }
  }

  public void endBackgroundUpdate() {
    fBackgroundupdateInProgress = false;
    setRedraw(true);
  }

  protected void handleDispose() {
    Logger.trace("Source Editor", "StructuredTextViewer::handleDispose entry"); //$NON-NLS-1$ //$NON-NLS-2$

    // before we dispose, we set a special "empty" selection, to prevent
    // the "leak one document" that
    // otherwise occurs when editor closed (since last selection stays in
    // SelectedResourceManager.
    // the occurance of the "leak" isn't so bad, but makes debugging other
    // leaks very hard.
    setSelection(TextSelection.emptySelection());

    if (fHighlighter != null) {
      fHighlighter.uninstall();
      fHighlighter = null;
    }
   
    if (fRecHighlighter != null) {
      fRecHighlighter.uninstall();
      fRecHighlighter = null;
    }
    super.handleDispose();

    Logger.trace("Source Editor", "StructuredTextViewer::handleDispose exit"); //$NON-NLS-1$ //$NON-NLS-2$
  }

  /*
   * Overridden for special support of background update and read-only
   * regions
   */
  protected void handleVerifyEvent(VerifyEvent e) {
    IRegion modelRange = event2ModelRange(e);
    if (exposeModelRange(modelRange)) {
      e.doit = false;
      return;
    }

    if (fEventConsumer != null) {
      fEventConsumer.processEvent(e);
      if (!e.doit)
        return;
    }
    if (fBackgroundupdateInProgress) {
      e.doit = false;
      beep();
      return;
    }
   
    // for read-only support
    if (containsReadOnly(getVisibleDocument(), e.start, e.end)) {
      e.doit = false;
      beep();
      return;
    }

    try {
      super.handleVerifyEvent(e);
    }
    catch (Exception x) {
      /*
       * Note, we catch and log any exception, since an otherwise can
       * actually prevent typing! see
       * https://bugs.eclipse.org/bugs/show_bug.cgi?id=111318
       */

      if (TRACE_EXCEPTIONS)
        Logger.logException("StructuredTextViewer.exception.verifyText", x); //$NON-NLS-1$
    }
  }

  public int modelLine2WidgetLine(int modelLine) {
    /**
     * need to override this method as a workaround for Bug 85709
     */
    if (fInformationMapping == null) {
      IDocument document = getDocument();
      if (document != null) {
        try {
          IRegion modelLineRegion = getDocument().getLineInformation(modelLine);
          IRegion region = getModelCoverage();
          if (modelLineRegion != null && region != null) {
            int modelEnd = modelLineRegion.getOffset() + modelLineRegion.getLength();
            int regionEnd = region.getOffset() + region.getLength();
            // returns -1 if modelLine is invalid
            if ((modelLineRegion.getOffset() < region.getOffset()) || (modelEnd > regionEnd))
              return -1;
          }
        }
        catch (BadLocationException e) {
          // returns -1 if modelLine is invalid
          return -1;
        }
      }
    }
    return super.modelLine2WidgetLine(modelLine);
  }

  public int modelOffset2WidgetOffset(int modelOffset) {
    /**
     * need to override this method as a workaround for Bug 85709
     */
    if (fInformationMapping == null) {
      IRegion region = getModelCoverage();
      if (region != null) {
        // returns -1 if modelOffset is invalid
        if (modelOffset < region.getOffset() || modelOffset > (region.getOffset() + region.getLength()))
          return -1;
      }
    }
    return super.modelOffset2WidgetOffset(modelOffset);
  }

  public IRegion modelRange2WidgetRange(IRegion modelRange) {
    // need to override this method as workaround for Bug85709
    if (fInformationMapping == null) {
      IRegion region = getModelCoverage();
      if (region != null && modelRange != null) {
        int modelEnd = modelRange.getOffset() + modelRange.getLength();
        int regionEnd = region.getOffset() + region.getLength();
        // returns null if modelRange is invalid
        if ((modelRange.getOffset() < region.getOffset()) || (modelEnd > regionEnd))
          return null;
      }
    }
    return super.modelRange2WidgetRange(modelRange);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.jface.text.source.ISourceViewer#setDocument(org.eclipse.jface.text.IDocument,
   *      org.eclipse.jface.text.source.IAnnotationModel, int, int)
   */
  public void setDocument(IDocument document, IAnnotationModel annotationModel, int modelRangeOffset, int modelRangeLength) {
    // partial fix for:
    // https://w3.opensource.ibm.com/bugzilla/show_bug.cgi?id=1970
    // when our document is set, especially to null during close,
    // immediately uninstall the reconciler.
    // this is to avoid an unnecessary final "reconcile"
    // that blocks display thread
    if (document == null) {
      if (fReconciler != null) {
        fReconciler.uninstall();
      }
    }

    super.setDocument(document, annotationModel, modelRangeOffset, modelRangeLength);

    if (document instanceof IStructuredDocument) {
      IStructuredDocument structuredDocument = (IStructuredDocument) document;

      // notify highlighter
      updateHighlighter(structuredDocument);

      // set the formatter again now that document has been set
      if (!fFormatterSet && fConfiguration != null) {
        fContentFormatter = fConfiguration.getContentFormatter(this);
        fFormatterSet = true;
      }

      // set document in the viewer-based undo manager
      if (fUndoManager != null) {
        fUndoManager.disconnect();
        fUndoManager.connect(this);
      }
      // CaretEvent is not sent to ViewerSelectionManager after Save As.
      // Need to notify ViewerSelectionManager here.
      // notifyViewerSelectionManager(getSelectedRange().x,
      // getSelectedRange().y);
    }
  }

  public ContentAssistantFacade getContentAssistFacade() {
    return fContentAssistantFacade;
  }

  /**
   * Uninstalls anything that was installed by configure
   */
  public void unconfigure() {
    Logger.trace("Source Editor", "StructuredTextViewer::unconfigure entry"); //$NON-NLS-1$ //$NON-NLS-2$
    if (fHighlighter != null) {
      fHighlighter.uninstall();
      fHighlighter = null;
    }
   
    if (fRecHighlighter != null) {
      fRecHighlighter.uninstall();
      fRecHighlighter = null;
    }

    if (fAnnotationHover instanceof StructuredTextAnnotationHover) {
      ((StructuredTextAnnotationHover) fAnnotationHover).release();
    }

    if (fOverviewRulerAnnotationHover instanceof StructuredTextAnnotationHover) {
      ((StructuredTextAnnotationHover) fOverviewRulerAnnotationHover).release();
    }

    super.unconfigure();
    fConfiguration = null;
    Logger.trace("Source Editor", "StructuredTextViewer::unconfigure exit"); //$NON-NLS-1$ //$NON-NLS-2$
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.wst.sse.core.undo.IDocumentSelectionMediator#undoOperationSelectionChanged(org.eclipse.wst.sse.core.undo.UndoDocumentEvent)
   */
  public void undoOperationSelectionChanged(UndoDocumentEvent event) {
    if (event.getRequester() != null && event.getRequester().equals(this) && event.getDocument().equals(getDocument())) {
      // BUG107687: Undo/redo do not scroll editor
      ITextSelection selection = new TextSelection(event.getOffset(), event.getLength());
      setSelection(selection, true);
    }
  }

  private void updateHighlighter(IStructuredDocument document) {
    boolean documentSet = false;
   
    // if highlighter has not been created yet, initialize and install it
    if (fRecHighlighter == null && fConfiguration instanceof StructuredTextViewerConfiguration) {
      String[] types = fConfiguration.getConfiguredContentTypes(this);
      for (int i = 0; i < types.length; i++) {
        String t = types[i];

        // add highlighter/linestyleprovider
        LineStyleProvider[] providers = ((StructuredTextViewerConfiguration) fConfiguration).getLineStyleProviders(this, t);
        if (providers != null) {
          for (int j = 0; j < providers.length; ++j) {
           
            if(fRecHighlighter == null) {
              fRecHighlighter = new ReconcilerHighlighter();
              ((StructuredTextViewerConfiguration) fConfiguration).setHighlighter(fRecHighlighter);
            }
            if (providers[j] instanceof AbstractLineStyleProvider) {
              ((AbstractLineStyleProvider) providers[j]).init(document, fRecHighlighter);
              fRecHighlighter.addProvider(t, providers[j]);
            }
            else {
              // init with compatibility instance
              if (fHighlighter == null) {
                fHighlighter = new CompatibleHighlighter();
              }
              Logger.log(Logger.INFO_DEBUG, "CompatibleHighlighter installing compatibility for " + providers[j].getClass()); //$NON-NLS-1$
              providers[j].init(document, fHighlighter);
              fHighlighter.addProvider(t, providers[j]);
            }
          }
        }
      }
     
      if(fRecHighlighter != null)
        fRecHighlighter.install(this);
      if(fHighlighter != null) {
        fHighlighter.setDocumentPartitioning(fConfiguration.getConfiguredDocumentPartitioning(this));
        // https://bugs.eclipse.org/bugs/show_bug.cgi?id=203347
        // make sure to set document before install
        fHighlighter.setDocument(document);
        fHighlighter.install(this);
        documentSet = true;
      }
    }
    if (fHighlighter != null && !documentSet)
      fHighlighter.setDocument(document);
   
    // install content type independent plugins
    if (fPresentationReconciler != null)
      fPresentationReconciler.uninstall();
    // 228847 - XSL Content Assist tests fail with Null Pointer on Highlighter
    if(fConfiguration != null)
      fPresentationReconciler = fConfiguration.getPresentationReconciler(this);
   
    if (fPresentationReconciler != null)
      fPresentationReconciler.install(this);

  }

  /**
   * Make sure indentation is correct before using.
   */
  private void updateIndentationPrefixes() {
    SourceViewerConfiguration configuration = fConfiguration;
    if (fConfiguration != null) {
      String[] types = configuration.getConfiguredContentTypes(this);
      for (int i = 0; i < types.length; i++) {
        String[] prefixes = configuration.getIndentPrefixes(this, types[i]);
        if (prefixes != null && prefixes.length > 0)
          setIndentPrefixes(prefixes, types[i]);
      }
    }
  }
 
  /**
   * Prepends the text presentation listener at the beginning of the viewer's
   * list of text presentation listeners.  If the listener is already registered
   * with the viewer this call moves the listener to the beginning of
   * the list.
   *
   * @param listener the text presentation listener
   * @since 3.1
   */
  public void prependTextPresentationListener(ITextPresentationListener listener) {

    Assert.isNotNull(listener);

    if (fTextPresentationListeners == null)
      fTextPresentationListeners= new ArrayList();

    fTextPresentationListeners.remove(listener);
    fTextPresentationListeners.add(0, listener);
  }
}
TOP

Related Classes of org.eclipse.wst.sse.ui.internal.StructuredTextViewer

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.