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

Source Code of org.eclipse.wst.sse.ui.internal.handlers.ToggleLineCommentHandler$ToggleLinesRunnable

/*******************************************************************************
* Copyright (c) 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
*******************************************************************************/
package org.eclipse.wst.sse.ui.internal.handlers;

import java.lang.reflect.InvocationTargetException;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
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.IDocumentExtension4;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.jface.text.Position;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
import org.eclipse.wst.sse.ui.StructuredTextEditor;
import org.eclipse.wst.sse.ui.internal.Logger;
import org.eclipse.wst.sse.ui.internal.SSEUIMessages;
import org.eclipse.wst.sse.ui.internal.StructuredTextViewer;
import org.eclipse.wst.sse.ui.internal.comment.BlockCommentingStrategy;
import org.eclipse.wst.sse.ui.internal.comment.CommentingStrategy;
import org.eclipse.wst.sse.ui.internal.comment.CommentingStrategyRegistry;
import org.eclipse.wst.sse.ui.internal.comment.LineCommentingStrategy;

/**
* <p>A comment handler to toggle line comments, this means that if a
* comment already exists on a line then toggling it will remove the comment,
* if the line in question is not already commented then it will not be commented.
* If multiple lines are selected each will be commented separately.  The handler
* first attempts to find a {@link LineCommentingStrategy} for a line, if it can
* not find one then it will try and find a {@link BlockCommentingStrategy} to
* wrap just that line in.</p>
*
* <p>If a great number of lines are being toggled then a progress dialog will be
* displayed because this can be a timely process</p>
*/
public final class ToggleLineCommentHandler extends AbstractCommentHandler {
  /** if toggling more then this many lines then use a busy indicator */
  private static final int TOGGLE_LINES_MAX_NO_BUSY_INDICATOR = 10;
 
  /**
   * @see org.eclipse.wst.sse.ui.internal.handlers.AbstractCommentHandler#processAction(
   *   org.eclipse.ui.texteditor.ITextEditor, org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument,
   *   org.eclipse.jface.text.ITextSelection)
   */
  protected void processAction(ITextEditor textEditor,
      final IStructuredDocument document, ITextSelection textSelection) {
   
    IStructuredModel model = null;
    DocumentRewriteSession session = null;
    boolean changed = false;
   
    try {
      // get text selection lines info
      int selectionStartLine = textSelection.getStartLine();
      int selectionEndLine = textSelection.getEndLine();
     
      int selectionEndLineOffset = document.getLineOffset(selectionEndLine);
      int selectionEndOffset = textSelection.getOffset() + textSelection.getLength();

      // adjust selection end line
      if ((selectionEndLine > selectionStartLine) && (selectionEndLineOffset == selectionEndOffset)) {
        selectionEndLine--;
      }

      // save the selection position since it will be changing
      Position selectionPosition = null;
      selectionPosition = new Position(textSelection.getOffset(), textSelection.getLength());
      document.addPosition(selectionPosition);

     
      model = StructuredModelManager.getModelManager().getModelForEdit(document);
      if (model != null) {
        //makes it so one undo will undo all the edits to the document
        model.beginRecording(this, SSEUIMessages.ToggleComment_label, SSEUIMessages.ToggleComment_description);
       
        //keeps listeners from doing anything until updates are all done
        model.aboutToChangeModel();
        if(document instanceof IDocumentExtension4) {
          session = ((IDocumentExtension4)document).startRewriteSession(DocumentRewriteSessionType.UNRESTRICTED);
        }
        changed = true;
       
        //get the display for the editor if we can
        Display display = null;
        if(textEditor instanceof StructuredTextEditor) {
          StructuredTextViewer viewer = ((StructuredTextEditor)textEditor).getTextViewer();
          if(viewer != null) {
            display = viewer.getControl().getDisplay();
          }
        }
       
        //create the toggling operation
        IRunnableWithProgress toggleCommentsRunnable = new ToggleLinesRunnable(
            model.getContentTypeIdentifier(), document, selectionStartLine, selectionEndLine, display);
       
        //if toggling lots of lines then use progress monitor else just run the operation
        if((selectionEndLine - selectionStartLine) > TOGGLE_LINES_MAX_NO_BUSY_INDICATOR && display != null) {
          ProgressMonitorDialog dialog = new ProgressMonitorDialog(display.getActiveShell());
          dialog.run(false, true, toggleCommentsRunnable);
        } else {
          toggleCommentsRunnable.run(new NullProgressMonitor());
        }
      }
    } catch (InvocationTargetException e) {
      Logger.logException("Problem running toggle comment progess dialog.", e)//$NON-NLS-1$
    } catch (InterruptedException e) {
      Logger.logException("Problem running toggle comment progess dialog.", e)//$NON-NLS-1$
    } catch (BadLocationException e) {
      Logger.logException("The given selection " + textSelection + " must be invalid", e); //$NON-NLS-1$ //$NON-NLS-2$
    } finally {
      //clean everything up
      if(session != null && document instanceof IDocumentExtension4) {
        ((IDocumentExtension4)document).stopRewriteSession(session);
      }
     
      if(model != null) {
        model.endRecording(this);
        if(changed) {
          model.changedModel();
        }
        model.releaseFromEdit();
      }
    }
  }
 
  /**
   * <p>The actual line toggling takes place in a runnable so it can be
   * run as part of a progress dialog if there are many lines to toggle
   * and thus the operation will take a noticeable amount of time the user
   * should be aware of, this also allows for the operation to be canceled
   * by the user</p>
   *
   */
  private static class ToggleLinesRunnable implements IRunnableWithProgress {
    /** the content type for the document being commented */
    private String fContentType;
   
    /** the document that the lines will be toggled on */
    private IStructuredDocument fDocument;
   
    /** the first line in the document to toggle */
    private int fSelectionStartLine;
   
    /** the last line in the document to toggle */
    private int fSelectionEndLine;
   
    /** the display, so that it can be updated during a long operation */
    private Display fDisplay;
   
    /**
     * @param model {@link IStructuredModel} that the lines will be toggled on
     * @param document {@link IDocument} that the lines will be toggled on
     * @param selectionStartLine first line in the document to toggle
     * @param selectionEndLine last line in the document to toggle
     * @param display {@link Display}, so that it can be updated during a long operation
     */
    protected ToggleLinesRunnable(String contentTypeIdentifier, IStructuredDocument document,
        int selectionStartLine, int selectionEndLine, Display display) {
     
      this.fContentType = contentTypeIdentifier;
      this.fDocument = document;
      this.fSelectionStartLine = selectionStartLine;
      this.fSelectionEndLine = selectionEndLine;
      this.fDisplay = display;
    }
   
    /**
     * @see org.eclipse.jface.operation.IRunnableWithProgress#run(org.eclipse.core.runtime.IProgressMonitor)
     */
    public void run(IProgressMonitor monitor) {
      //start work
      monitor.beginTask(SSEUIMessages.ToggleComment_progress,
          this.fSelectionEndLine-this.fSelectionStartLine);
      try {
        //toggle each line so long as task not canceled
        for (int line = this.fSelectionStartLine;
            line <= this.fSelectionEndLine && !monitor.isCanceled(); ++line) {
         
          //allows the user to be able to click the cancel button
          readAndDispatch(this.fDisplay);
         
          //get the line region
          IRegion lineRegion = this.fDocument.getLineInformation(line);
         
          //don't toggle empty lines
          String content = this.fDocument.get(lineRegion.getOffset(), lineRegion.getLength());
          if (content.trim().length() > 0) {
            //try to get a line comment type
            ITypedRegion[] lineTypedRegions =
              this.fDocument.computePartitioning(lineRegion.getOffset(), lineRegion.getLength());
            CommentingStrategy commentType = CommentingStrategyRegistry.getDefault().getLineCommentingStrategy(
                this.fContentType, lineTypedRegions);
           
            //could not find line comment type so find block comment type to use on line
            if(commentType == null) {
              commentType = CommentingStrategyRegistry.getDefault().getBlockCommentingStrategy(
                  this.fContentType, lineTypedRegions);
            }
           
            //toggle the comment on the line
            if(commentType != null) {
              if(commentType.alreadyCommenting(this.fDocument, lineTypedRegions)) {
                commentType.remove(this.fDocument, lineRegion.getOffset(), lineRegion.getLength(), true);
              } else {
                commentType.apply(this.fDocument, lineRegion.getOffset(), lineRegion.getLength());
              }
            }
          }
          monitor.worked(1);
        }
      } catch(BadLocationException e) {
        Logger.logException("Bad location while toggling comments.", e)//$NON-NLS-1$
      }
      //done work
      monitor.done();
    }
   
    /**
     * <p>When calling {@link Display#readAndDispatch()} the game is off as to whose code you maybe
     * calling into because of event handling/listeners/etc.  The only important thing is that
     * the UI has been given a chance to react to user clicks.  Thus the logging of most {@link Exception}s
     * and {@link Error}s as caused by {@link Display#readAndDispatch()} because they are not caused
     * by this code and do not effect it.</p>
     *
     * @param display the {@link Display} to call <code>readAndDispatch</code>
     * on with exception/error handling.
     */
    private void readAndDispatch(Display display) {
      try {
        display.readAndDispatch();
      }
      catch (Exception e) {
        Logger.log(Logger.WARNING,
            "Exception caused by readAndDispatch, not caused by or fatal to caller", e);
      }
      catch (LinkageError e) {
        Logger.log(Logger.WARNING,
            "LinkageError caused by readAndDispatch, not caused by or fatal to caller", e);
      }
      catch (VirtualMachineError e) {
        // re-throw these
        throw e;
      }
      catch (ThreadDeath e) {
        // re-throw these
        throw e;
      }
      catch (Error e) {
        // catch every error, except for a few that we don't want to handle
        Logger.log(Logger.WARNING,
            "Error caused by readAndDispatch, not caused by or fatal to caller", e);
      }
    }
  }
}
TOP

Related Classes of org.eclipse.wst.sse.ui.internal.handlers.ToggleLineCommentHandler$ToggleLinesRunnable

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.