diff options
Diffstat (limited to 'bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/reconcile/DirtyRegionProcessor.java')
-rw-r--r-- | bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/reconcile/DirtyRegionProcessor.java | 757 |
1 files changed, 0 insertions, 757 deletions
diff --git a/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/reconcile/DirtyRegionProcessor.java b/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/reconcile/DirtyRegionProcessor.java deleted file mode 100644 index 1a500b943c..0000000000 --- a/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/reconcile/DirtyRegionProcessor.java +++ /dev/null @@ -1,757 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001, 2007 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.reconcile; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.OperationCanceledException; -import org.eclipse.core.runtime.Platform; -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.DocumentRewriteSessionEvent; -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.IDocumentExtension3; -import org.eclipse.jface.text.IDocumentExtension4; -import org.eclipse.jface.text.IDocumentListener; -import org.eclipse.jface.text.IDocumentRewriteSessionListener; -import org.eclipse.jface.text.ITextInputListener; -import org.eclipse.jface.text.ITextViewer; -import org.eclipse.jface.text.ITypedRegion; -import org.eclipse.jface.text.TextUtilities; -import org.eclipse.jface.text.reconciler.DirtyRegion; -import org.eclipse.jface.text.reconciler.IReconciler; -import org.eclipse.jface.text.reconciler.IReconcilerExtension; -import org.eclipse.jface.text.reconciler.IReconcilingStrategy; -import org.eclipse.ui.PlatformUI; -import org.eclipse.wst.sse.ui.internal.Logger; -import org.eclipse.wst.sse.ui.internal.SSEUIMessages; - -/** - * This Job holds a queue of updates from the editor (DirtyRegions) to - * process. When a new request comes in, the current run is canceled, the new - * request is added to the queue, then the job is re-scheduled. - * - * @author pavery - */ -public class DirtyRegionProcessor extends Job implements IReconciler, IReconcilerExtension, IConfigurableReconciler { - class DocumentListener implements IDocumentListener { - public void documentAboutToBeChanged(DocumentEvent event) { - /* - * if in rewrite session and already going to reprocess entire - * document after rewrite session, do nothing - */ - if (isInRewriteSession() && fReprocessAfterRewrite) - return; - // save partition type (to see if it changes in documentChanged()) - fLastPartitions = getPartitionRegions(event.getOffset(), event.getLength()); - } - - public void documentChanged(DocumentEvent event) { - /* - * if in rewrite session and already going to reprocess entire - * document after rewrite session, do nothing - */ - if (isInRewriteSession() && fReprocessAfterRewrite) - return; - - if (partitionsChanged(event)) { - // pa_TODO - // this is a simple way to ensure old - // annotations are removed when partition changes - - // it might be a performance hit though - setEntireDocumentDirty(getDocument()); - } - else { - /* - * Note that creating DirtyRegions *now* means that the wrong - * text may be included - */ - DirtyRegion dr = null; - if (event.getLength() == 0) { - /* - * It's an insert-- we use text length though so that the - * new region gets validated... - */ - dr = createDirtyRegion(event.getOffset(), 0, DirtyRegion.INSERT); - } - else { - if ("".equals(event.getText())) { //$NON-NLS-1$ - // it's a delete - dr = createDirtyRegion(event.getOffset(), event.getLength(), DirtyRegion.REMOVE); - } - else { - // it's a replace - dr = createDirtyRegion(event.getOffset(), event.getLength(), DirtyRegion.INSERT); - } - } - if (isInRewriteSession()) { - /* - * while in rewrite session, found a dirty region, so flag - * that entire document needs to be reprocesed after - * rewrite session - */ - if (!fReprocessAfterRewrite && (dr != null)) { - fReprocessAfterRewrite = true; - } - } - else { - processDirtyRegion(dr); - } - } - } - - /** - * Checks previous partitions from the span of the event w/ the new - * partitions from the span of the event. If partitions changed, - * return true, else return false - * - * @param event - * @return - */ - private boolean partitionsChanged(DocumentEvent event) { - boolean changed = false; - int length = event.getLength(); - - if (event.getLength() == 0 && event.getText().length() > 0) { - // it's an insert, we want partitions of the new text - length = event.getText().length(); - } - - ITypedRegion[] newPartitions = getPartitionRegions(event.getOffset(), length); - if (fLastPartitions != null) { - if (fLastPartitions.length != newPartitions.length) { - changed = true; - } - else { - for (int i = 0; i < fLastPartitions.length; i++) { - if (!fLastPartitions[i].getType().equals(newPartitions[i].getType())) { - changed = true; - break; - } - } - } - } - return changed; - } - - - } - - /** - * Reconciles the entire document when the document in the viewer is - * changed. This happens when the document is initially opened, as well as - * after a save-as. - * - * Also see processPostModelEvent(...) for similar behavior when document - * for the model is changed. - */ - class TextInputListener implements ITextInputListener { - public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) { - // do nothing - } - - public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { - handleInputDocumentChanged(oldInput, newInput); - } - } - - class DocumentRewriteSessionListener implements IDocumentRewriteSessionListener { - long time0 = 0; - - public void documentRewriteSessionChanged(DocumentRewriteSessionEvent event) { - boolean oldValue = fInRewriteSession; - fInRewriteSession = event != null && event.getChangeType().equals(DocumentRewriteSessionEvent.SESSION_START); - - if (event.getChangeType().equals(DocumentRewriteSessionEvent.SESSION_START)) { - if (DEBUG) { - time0 = System.currentTimeMillis(); - } - flushDirtyRegionQueue(); - fReprocessAfterRewrite = false; - } - else if (event.getChangeType().equals(DocumentRewriteSessionEvent.SESSION_STOP)) { - if (fInRewriteSession ^ oldValue && fDocument != null) { - if (DEBUG) { - Logger.log(Logger.INFO, "Rewrite session lasted " + (System.currentTimeMillis() - time0) + "ms"); - time0 = System.currentTimeMillis(); - } - if (fReprocessAfterRewrite) { - DirtyRegion entireDocument = createDirtyRegion(0, fDocument.getLength(), DirtyRegion.INSERT); - processDirtyRegion(entireDocument); - } - if (DEBUG) { - Logger.log(Logger.INFO, "Full document reprocess took " + (System.currentTimeMillis() - time0) + "ms"); - } - fReprocessAfterRewrite = false; - } - } - } - } - - /** debug flag */ - protected static final boolean DEBUG; - private static final long UPDATE_DELAY = 750; - - static { - String value = Platform.getDebugOption("org.eclipse.wst.sse.ui/debug/reconcilerjob"); //$NON-NLS-1$ - DEBUG = value != null && value.equalsIgnoreCase("true"); //$NON-NLS-1$ - } - - private long fDelay; - - - /** local queue of dirty regions (created here) to be reconciled */ - private List fDirtyRegionQueue = Collections.synchronizedList(new ArrayList()); - - /** document that this reconciler works on */ - private IDocument fDocument = null; - - private IDocumentListener fDocumentListener = new DocumentListener(); - private IDocumentRewriteSessionListener fDocumentRewriteSessionListener = new DocumentRewriteSessionListener(); - - /** - * set true after first install to prevent duplicate work done in the - * install method (since install gets called multiple times) - */ - private boolean fIsInstalled = false; - - /** - * so we can tell if a partition changed after the last edit - */ - ITypedRegion[] fLastPartitions; - - List fNonIncrementalStrategiesAlreadyProcessed = new ArrayList(1); - - /** - * The partitioning this reconciler uses. - */ - private String fPartitioning; - - Map fReconcilingStrategies = null; - - /** for initial reconcile when document is opened */ - private TextInputListener fTextInputListener = null; - /** the text viewer */ - private ITextViewer fViewer; - boolean fInRewriteSession = false; - /** - * true if entire document needs to be reprocessed after rewrite session - */ - boolean fReprocessAfterRewrite = false; - - /** - * Creates a new StructuredRegionProcessor - */ - public DirtyRegionProcessor() { - // init job stuff - super(SSEUIMessages.proc_dirty_regions_0); //$NON-NLS-1$ - setPriority(Job.LONG); - setSystem(true); - - // init reconciler stuff - setDelay(UPDATE_DELAY); - fReconcilingStrategies = new HashMap(); - } - - /** - * Adds the given resource to the set of resources that need refreshing. - * Synchronized in order to protect the collection during add. - * - * @param resource - */ - private synchronized void addRequest(DirtyRegion newDirtyRegion) { - // NOTE: This method is called a lot so make sure it's fast - List dirtyRegionQueue = getDirtyRegionQueue(); - for (Iterator it = dirtyRegionQueue.iterator(); it.hasNext();) { - // go through list of existing dirty regions and check if any - // dirty regions need to be discarded - DirtyRegion currentExisting = (DirtyRegion) it.next(); - DirtyRegion outer = getOuterRegion(currentExisting, newDirtyRegion); - // if we already have a request which contains the new request, - // discard the new request - if (outer == currentExisting) - return; - // if new request contains any existing requests, - // remove those - if (outer == newDirtyRegion) - it.remove(); - } - dirtyRegionQueue.add(newDirtyRegion); - } - - /** - * Notifies subclasses that processing of multiple dirty regions has begun - */ - protected void beginProcessing() { - // do nothing by default - } - - /** - * @param dirtyRegion - * @return - */ - protected ITypedRegion[] computePartitioning(DirtyRegion dirtyRegion) { - int drOffset = dirtyRegion.getOffset(); - int drLength = dirtyRegion.getLength(); - - return computePartitioning(drOffset, drLength); - } - - protected ITypedRegion[] computePartitioning(int drOffset, int drLength) { - IDocument doc = getDocument(); - int docLength = doc.getLength(); - - ITypedRegion[] tr = new ITypedRegion[0]; - - if (drOffset > docLength) { - drOffset = docLength; - drLength = 0; - } - else if (drOffset + drLength > docLength) { - drLength = docLength - drOffset; - } - - try { - // dirty region may span multiple partitions - tr = TextUtilities.computePartitioning(doc, getDocumentPartitioning(), drOffset, drLength, true); - } - catch (BadLocationException e) { - String info = "dr: [" + drOffset + ":" + drLength + "] doc: [" + docLength + "] "; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ - Logger.logException(info, e); - tr = new ITypedRegion[0]; - } - return tr; - } - - /** - * Used to determine if one dirty region contains the other and if so, - * which is the one that contains it. - * - * @param root - * @param possible - * @return the outer dirty region if it contains the other dirty region, - * null otherwise - */ - protected DirtyRegion getOuterRegion(DirtyRegion root, DirtyRegion possible) { - DirtyRegion outer = null; - if (isContained(root, possible)) - outer = root; - else if (isContained(possible, root)) - outer = possible; - return outer; - } - - /** - * Used to determine of a "possible" dirty region can be discarded in - * favor of using just the "root" dirty region. - * - * @return if the root dirty region contains possible, return true, - * otherwise return false - */ - private boolean isContained(DirtyRegion root, DirtyRegion possible) { - int rootStart = root.getOffset(); - int rootEnd = rootStart + root.getLength(); - int possStart = possible.getOffset(); - int possEnd = possStart + possible.getLength(); - if (rootStart <= possStart && rootEnd >= possEnd) - return true; - return false; - } - - protected DirtyRegion createDirtyRegion(int offset, int length, String type) { - DirtyRegion durty = null; - IDocument doc = getDocument(); - - if (doc != null) { - // safety for BLE - int docLen = doc.getLength(); - if (offset > docLen) { - offset = docLen; - length = 0; - } - else if (offset + length >= docLen) - length = docLen - offset; - try { - durty = new DirtyRegion(offset, length, type, doc.get(offset, length)); - } - catch (BadLocationException e) { - String info = "dr: [" + offset + ":" + length + "] doc: [" + docLen + "] "; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ - Logger.logException(info, e); - } - } - return durty; - } - - protected DirtyRegion createDirtyRegion(ITypedRegion tr, String type) { - return createDirtyRegion(tr.getOffset(), tr.getLength(), type); - } - - protected void flushDirtyRegionQueue() { - fDirtyRegionQueue.clear(); - } - - /** - * Notifies subclasses that processing of multiple dirty regions has - * ended, for now - */ - protected void endProcessing() { - // do nothing by default - } - - /** - * Delay between processing of DirtyRegions. - * - * @return - */ - long getDelay() { - return fDelay; - } - - List getDirtyRegionQueue() { - return fDirtyRegionQueue; - } - - /** - * The IDocument on which this reconciler operates - * - * @return - */ - protected IDocument getDocument() { - return fDocument; - } - - public String getDocumentPartitioning() { - if (fPartitioning == null) - return IDocumentExtension3.DEFAULT_PARTITIONING; - return fPartitioning; - } - - protected String[] getPartitions(int drOffset, int drLength) { - - ITypedRegion[] regions = new ITypedRegion[0]; - int docLength = getDocument().getLength(); - - if (drOffset > docLength) { - drOffset = docLength; - drLength = 0; - } - else if (drOffset + drLength > docLength) { - drLength = docLength - drOffset; - } - - try { - regions = TextUtilities.computePartitioning(getDocument(), getDocumentPartitioning(), drOffset, drLength, true); - } - catch (BadLocationException e) { - Logger.logException(e); - regions = new ITypedRegion[0]; - } - String[] partitions = new String[regions.length]; - for (int i = 0; i < regions.length; i++) - partitions[i] = regions[i].getType(); - return partitions; - } - - ITypedRegion[] getPartitionRegions(int drOffset, int drLength) { - ITypedRegion[] regions = new ITypedRegion[0]; - int docLength = getDocument().getLength(); - - if (drOffset > docLength) { - drOffset = docLength; - drLength = 0; - } - else if (drOffset + drLength > docLength) { - drLength = docLength - drOffset; - } - - try { - regions = TextUtilities.computePartitioning(getDocument(), getDocumentPartitioning(), drOffset, drLength, true); - } - catch (BadLocationException e) { - Logger.logException(e); - regions = new ITypedRegion[0]; - } - return regions; - } - - - /** - * Returns the reconciling strategy registered with the reconciler for the - * specified partition type. - * - * @param partitionType - * the partition type for which to determine the reconciling - * strategy - * - * @return the reconciling strategy registered for the given partition - * type, or <code>null</code> if there is no such strategy - * - * @see org.eclipse.jface.text.reconciler.IReconciler#getReconcilingStrategy(java.lang.String) - */ - public IReconcilingStrategy getReconcilingStrategy(String partitionType) { - if (partitionType == null) - return null; - return (IReconcilingStrategy) fReconcilingStrategies.get(partitionType); - } - - /** - * This method also synchronized because it accesses the fRequests queue - * - * @return an array of the currently requested Nodes to refresh - */ - private synchronized DirtyRegion[] getRequests() { - DirtyRegion[] toRefresh = (DirtyRegion[]) fDirtyRegionQueue.toArray(new DirtyRegion[fDirtyRegionQueue.size()]); - flushDirtyRegionQueue(); - return toRefresh; - } - - /** - * Returns the text viewer this reconciler is installed on. - * - * @return the text viewer this reconciler is installed on - */ - protected ITextViewer getTextViewer() { - return fViewer; - } - - /** - * - * @param oldInput - * @param newInput - */ - void handleInputDocumentChanged(IDocument oldInput, IDocument newInput) { - // don't bother if reconciler not installed - if (isInstalled()) { - setDocument(newInput); - } - } - - /** - * @see org.eclipse.jface.text.reconciler.IReconciler#install(ITextViewer) - */ - public void install(ITextViewer textViewer) { - // we might be called multiple times with the same viewe.r, - // maybe after being uninstalled as well, so track separately - if (!isInstalled()) { - fViewer = textViewer; - fTextInputListener = new TextInputListener(); - textViewer.addTextInputListener(fTextInputListener); - setInstalled(true); - } - } - - /** - * The viewer has been set on this Reconciler. - * - * @return true if the viewer has been set on this Reconciler, false - * otherwise. - */ - public boolean isInstalled() { - return fIsInstalled; - } - - boolean isInRewriteSession() { - return fInRewriteSession; - } - - /** - * Subclasses should implement for specific handling of dirty regions. The - * method is invoked for each dirty region in the Job's queue. - * - * @param dirtyRegion - */ - protected void process(DirtyRegion dirtyRegion) { - if (isInRewriteSession()) { - return; - } - /* - * Break the dirty region into a sequence of partitions and find the - * corresponding strategy to reconcile those partitions. If a strategy - * implements INonIncrementalReconcilingStrategy, only call it once - * regardless of the number and types of partitions. - */ - ITypedRegion[] partitions = computePartitioning(dirtyRegion); - for (int i = 0; i < partitions.length; i++) { - IReconcilingStrategy strategy = getReconcilingStrategy(partitions[i].getType()); - if (strategy != null) { - strategy.reconcile(partitions[i]); - } - } - } - - /** - * Invoke dirty region processing. - * - * @param node - */ - public final void processDirtyRegion(DirtyRegion dr) { - if (dr == null) - return; - - cancel(); - addRequest(dr); - schedule(getDelay()); - - if (DEBUG) { - System.out.println("added request for: [" + dr.getText() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ - System.out.println("queue size is now: " + getDirtyRegionQueue().size()); //$NON-NLS-1$ - } - } - - protected IStatus run(IProgressMonitor monitor) { - IStatus status = Status.OK_STATUS; - if (!PlatformUI.isWorkbenchRunning()) - return status; - - try { - beginProcessing(); - - DirtyRegion[] toRefresh = getRequests(); - for (int i = 0; i < toRefresh.length; i++) { - if (monitor.isCanceled()) - throw new OperationCanceledException(); - process(toRefresh[i]); - } - } - catch (Exception e) { - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=103676 - // stop errors from popping up a dialog - // from the job manager - - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=106052 - // don't log OperationCanceledException - if (!(e instanceof OperationCanceledException)) - Logger.logException("problem with reconciling", e); //$NON-NLS-1$ - } - finally { - endProcessing(); - - monitor.done(); - } - return status; - } - - public void setDelay(long delay) { - fDelay = delay; - } - - public void setDocument(IDocument doc) { - if (fDocument != null) { - // unhook old document listener - fDocument.removeDocumentListener(fDocumentListener); - if (fDocument instanceof IDocumentExtension4) { - ((IDocumentExtension4) fDocument).removeDocumentRewriteSessionListener(fDocumentRewriteSessionListener); - } - } - - fDocument = doc; - - if (fDocument != null) { - if (fDocument instanceof IDocumentExtension4) { - ((IDocumentExtension4) fDocument).addDocumentRewriteSessionListener(fDocumentRewriteSessionListener); - } - // hook up new document listener - fDocument.addDocumentListener(fDocumentListener); - } - - setEntireDocumentDirty(doc); - } - - /** - * Sets the document partitioning for this reconciler. - * - * @param partitioning - * the document partitioning for this reconciler - */ - public void setDocumentPartitioning(String partitioning) { - fPartitioning = partitioning; - } - - /** - * Basically means process the entire document. - * - * @param document - */ - protected void setEntireDocumentDirty(IDocument document) { - - // make the entire document dirty - // this also happens on a "save as" - if (document != null && isInstalled()) { - - // since we're marking the entire doc dirty - flushDirtyRegionQueue(); - - /** - * https://bugs.eclipse.org/bugs/show_bug.cgi?id=199053 - * - * Process the strategies for the last known-good partitions to - * ensure all problem annotations are cleared if needed. - */ - if (fLastPartitions != null && document.getLength() == 0) { - for (int i = 0; i < fLastPartitions.length; i++) { - IReconcilingStrategy strategy = getReconcilingStrategy(fLastPartitions[i].getType()); - if (strategy != null) { - strategy.reconcile(fLastPartitions[i]); - } - } - } - else { - DirtyRegion entireDocument = createDirtyRegion(0, document.getLength(), DirtyRegion.INSERT); - processDirtyRegion(entireDocument); - } - } - } - - /** - * @param isInstalled - * The isInstalled to set. - */ - void setInstalled(boolean isInstalled) { - fIsInstalled = isInstalled; - } - - public void setReconcilingStrategy(String partitionType, IReconcilingStrategy strategy) { - if (partitionType == null) { - throw new IllegalArgumentException(); - } - - if (strategy == null) { - fReconcilingStrategies.remove(partitionType); - } - else { - fReconcilingStrategies.put(partitionType, strategy); - } - } - - /** - * @see org.eclipse.jface.text.reconciler.IReconciler#uninstall() - */ - public void uninstall() { - if (isInstalled()) { - // removes widget listener - getTextViewer().removeTextInputListener(fTextInputListener); - setInstalled(false); - } - setDocument(null); - } -} |