Skip to main content

This CGIT instance is deprecated, and repositories have been moved to Gitlab or Github. See the repository descriptions for specific locations.

aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoramywu2006-06-14 05:08:57 +0000
committeramywu2006-06-14 05:08:57 +0000
commit91c25668b070581fe23302535f43218de5ae94d8 (patch)
tree4dd7c6788a3402343860338d664875aa0b7af102 /bundles/org.eclipse.wst.dtd.ui/src/org/eclipse/wst/dtd/ui/internal
parent17320ce8c78b0ce4ed422893bd04c66834404c4d (diff)
downloadwebtools.sourceediting-91c25668b070581fe23302535f43218de5ae94d8.tar.gz
webtools.sourceediting-91c25668b070581fe23302535f43218de5ae94d8.tar.xz
webtools.sourceediting-91c25668b070581fe23302535f43218de5ae94d8.zip
[73271] Folding for XML/HTML family languages editors
Diffstat (limited to 'bundles/org.eclipse.wst.dtd.ui/src/org/eclipse/wst/dtd/ui/internal')
-rw-r--r--bundles/org.eclipse.wst.dtd.ui/src/org/eclipse/wst/dtd/ui/internal/projection/StructuredTextFoldingProviderDTD.java403
1 files changed, 311 insertions, 92 deletions
diff --git a/bundles/org.eclipse.wst.dtd.ui/src/org/eclipse/wst/dtd/ui/internal/projection/StructuredTextFoldingProviderDTD.java b/bundles/org.eclipse.wst.dtd.ui/src/org/eclipse/wst/dtd/ui/internal/projection/StructuredTextFoldingProviderDTD.java
index 0f171596ca..b66b3117d6 100644
--- a/bundles/org.eclipse.wst.dtd.ui/src/org/eclipse/wst/dtd/ui/internal/projection/StructuredTextFoldingProviderDTD.java
+++ b/bundles/org.eclipse.wst.dtd.ui/src/org/eclipse/wst/dtd/ui/internal/projection/StructuredTextFoldingProviderDTD.java
@@ -11,22 +11,32 @@
*******************************************************************************/
package org.eclipse.wst.dtd.ui.internal.projection;
+import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.Platform;
-import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IDocumentExtension;
+import org.eclipse.jface.text.IDocumentListener;
+import org.eclipse.jface.text.ITextInputListener;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.source.projection.IProjectionListener;
import org.eclipse.jface.text.source.projection.ProjectionAnnotation;
+import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel;
import org.eclipse.jface.text.source.projection.ProjectionViewer;
+import org.eclipse.swt.graphics.FontMetrics;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
import org.eclipse.wst.dtd.core.internal.DTDFile;
import org.eclipse.wst.dtd.core.internal.DTDNode;
import org.eclipse.wst.dtd.core.internal.TopLevelNode;
import org.eclipse.wst.dtd.core.internal.document.DTDModelImpl;
import org.eclipse.wst.dtd.core.internal.event.IDTDFileListener;
import org.eclipse.wst.dtd.core.internal.event.NodesEvent;
+import org.eclipse.wst.dtd.ui.internal.Logger;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
@@ -36,10 +46,11 @@ import org.w3c.dom.Node;
/**
* Updates the projection model of a structured model for DTD.
*/
-public class StructuredTextFoldingProviderDTD implements IStructuredTextFoldingProvider, IProjectionListener, IDTDFileListener {
+public class StructuredTextFoldingProviderDTD implements IStructuredTextFoldingProvider, IProjectionListener, IDTDFileListener, ITextInputListener {
private final static boolean debugProjectionPerf = "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.wst.dtd.ui/projectionperf")); //$NON-NLS-1$ //$NON-NLS-2$
private class TagProjectionAnnotation extends ProjectionAnnotation {
+ private boolean fIsVisible = false; /* workaround for BUG85874 */
private Node fNode;
public TagProjectionAnnotation(Node node, boolean isCollapsed) {
@@ -54,11 +65,171 @@ public class StructuredTextFoldingProviderDTD implements IStructuredTextFoldingP
public void setNode(Node node) {
fNode = node;
}
+
+ /**
+ * Does not paint hidden annotations. Annotations are hidden when they
+ * only span one line.
+ *
+ * @see ProjectionAnnotation#paint(org.eclipse.swt.graphics.GC,
+ * org.eclipse.swt.widgets.Canvas,
+ * org.eclipse.swt.graphics.Rectangle)
+ */
+ public void paint(GC gc, Canvas canvas, Rectangle rectangle) {
+ /* workaround for BUG85874 */
+ /*
+ * only need to check annotations that are expanded because hidden
+ * annotations should never have been given the chance to
+ * collapse.
+ */
+ if (!isCollapsed()) {
+ // working with rectangle, so line height
+ FontMetrics metrics = gc.getFontMetrics();
+ if (metrics != null) {
+ // do not draw annotations that only span one line and
+ // mark them as not visible
+ if ((rectangle.height / metrics.getHeight()) <= 1) {
+ fIsVisible = false;
+ return;
+ }
+ }
+ }
+ fIsVisible = true;
+ super.paint(gc, canvas, rectangle);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.text.source.projection.ProjectionAnnotation#markCollapsed()
+ */
+ public void markCollapsed() {
+ /* workaround for BUG85874 */
+ // do not mark collapsed if annotation is not visible
+ if (fIsVisible)
+ super.markCollapsed();
+ }
+ }
+
+ /**
+ * Listens to document to be aware of when to update the projection
+ * annotation model.
+ */
+ class DocumentListener implements IDocumentListener {
+ public void documentAboutToBeChanged(DocumentEvent event) {
+ if (fDocument == event.getDocument())
+ fIsDocumentChanging = true;
+ }
+
+ public void documentChanged(DocumentEvent event) {
+ // register a post notification replace so that projection
+ // annotation model will be updated after all documentChanged
+ // listeners have been notified
+ IDocument document = event.getDocument();
+ if (document instanceof IDocumentExtension && fDocument == document) {
+ if (fViewer != null && fQueuedNodeChanges != null && !fQueuedNodeChanges.isEmpty()) {
+ ((IDocumentExtension) document).registerPostNotificationReplace(this, new PostDocumentChangedListener());
+ }
+ }
+ }
+ }
+
+ /**
+ * Essentially a post document changed listener because it is called after
+ * documentchanged has been fired.
+ */
+ class PostDocumentChangedListener implements IDocumentExtension.IReplace {
+ public void perform(IDocument document, IDocumentListener owner) {
+ applyAnnotationModelChanges();
+ fIsDocumentChanging = false;
+ }
+ }
+
+ /**
+ * Contains node and an indication on how it changed
+ */
+ class NodeChange {
+ static final int ADD = 1;
+ static final int REMOVE = 2;
+
+ private Node fNode;
+ private int fChangeType;
+
+ public NodeChange(Node node, int changeType) {
+ fNode = node;
+ fChangeType = changeType;
+ }
+
+ public Node getNode() {
+ return fNode;
+ }
+
+ public int getChangeType() {
+ return fChangeType;
+ }
}
- private IDocument fDocument;
- private ProjectionViewer fViewer;
+ IDocument fDocument;
+ ProjectionViewer fViewer;
+ private boolean fProjectionNeedsToBeEnabled = false;
+ /**
+ * Listener to fProjectionViewer's document
+ */
+ private IDocumentListener fDocumentListener;
+ /**
+ * Indicates whether or not document is in the middle of changing
+ */
+ boolean fIsDocumentChanging = false;
+ /**
+ * List of changed nodes that need to be recalculated
+ */
+ List fQueuedNodeChanges = null;
+ /**
+ * Processes all the queued node changes and updates projection annotation
+ * model.
+ */
+ void applyAnnotationModelChanges() {
+ if (fViewer != null && fQueuedNodeChanges != null && !fQueuedNodeChanges.isEmpty()) {
+ ProjectionAnnotationModel annotationModel = fViewer.getProjectionAnnotationModel();
+
+ // go through all the pending annotation changes and apply them to
+ // the projection annotation model
+ while (!fQueuedNodeChanges.isEmpty()) {
+ NodeChange changes = (NodeChange) fQueuedNodeChanges.remove(0);
+ if (changes.getChangeType() == NodeChange.ADD) {
+ // add
+ Node node = changes.getNode();
+ Position newPos = createProjectionPosition(node);
+ if (newPos != null) {
+ TagProjectionAnnotation newAnnotation = new TagProjectionAnnotation(node, false);
+ // add to map containing annotations to add
+ try {
+ annotationModel.addAnnotation(newAnnotation, newPos);
+ }
+ catch (Exception e) {
+ // if anything goes wrong, log it and continue
+ Logger.log(Logger.WARNING_DEBUG, e.getMessage(), e);
+ }
+ }
+ }
+ else if (changes.getChangeType() == NodeChange.REMOVE) {
+ // remove
+ Node node = changes.getNode();
+ TagProjectionAnnotation anno = findExistingAnnotation(node);
+ if (anno != null) {
+ try {
+ annotationModel.removeAnnotation(anno);
+ }
+ catch (Exception e) {
+ // if anything goes wrong, log it and continue
+ Logger.log(Logger.WARNING_DEBUG, e.getMessage(), e);
+ }
+ }
+ }
+ }
+ fQueuedNodeChanges = null;
+ }
+ }
/**
* Goes through every node creates projection annotation if needed
@@ -81,9 +252,10 @@ public class StructuredTextFoldingProviderDTD implements IStructuredTextFoldingP
}
}
- long end = System.currentTimeMillis();
- if (debugProjectionPerf)
+ if (debugProjectionPerf) {
+ long end = System.currentTimeMillis();
System.out.println("StructuredTextFoldingProviderDTD.addAllAnnotations: " + (end - start)); //$NON-NLS-1$
+ }
}
/**
@@ -102,20 +274,7 @@ public class StructuredTextFoldingProviderDTD implements IStructuredTextFoldingP
int start = inode.getStartOffset();
int end = inode.getEndOffset();
if (start >= 0 && start < end) {
- try {
- int startLine = fDocument.getLineOfOffset(start);
- int endLine = fDocument.getLineOfOffset(end);
- // checks if projection start/end region is on the
- // same line
- if ((startLine < endLine) && (endLine + 1 < fDocument.getNumberOfLines())) {
- int offset = fDocument.getLineOffset(startLine);
- int endOffset = fDocument.getLineOffset(endLine + 1);
- pos = new Position(offset, endOffset - offset);
- }
- }
- catch (BadLocationException x) {
- // Logger.log(Logger.WARNING_DEBUG, null, x);
- }
+ pos = new Position(start, end - start);
}
}
}
@@ -146,22 +305,23 @@ public class StructuredTextFoldingProviderDTD implements IStructuredTextFoldingP
/**
* Get the dtd file for the fDocument
*
- * @param document
- * @return
+ * @return DTDFile if it exists, null otherwise
*/
private DTDFile getDTDFile() {
DTDFile dtdFile = null;
- IStructuredModel sModel = null;
- try {
- sModel = StructuredModelManager.getModelManager().getExistingModelForRead(fDocument);
- if (sModel instanceof DTDModelImpl) {
- dtdFile = ((DTDModelImpl) sModel).getDTDFile();
+ if (fDocument != null) {
+ IStructuredModel sModel = null;
+ try {
+ sModel = StructuredModelManager.getModelManager().getExistingModelForRead(fDocument);
+ if (sModel instanceof DTDModelImpl) {
+ dtdFile = ((DTDModelImpl) sModel).getDTDFile();
+ }
}
- }
- finally {
- if (sModel != null) {
- sModel.releaseFromRead();
+ finally {
+ if (sModel != null) {
+ sModel.releaseFromRead();
+ }
}
}
return dtdFile;
@@ -175,24 +335,24 @@ public class StructuredTextFoldingProviderDTD implements IStructuredTextFoldingP
if (!isInstalled())
return;
- // remove dtd file listener from old dtd file
+ // remove old info
+ projectionDisabled();
+
+ fDocument = fViewer.getDocument();
DTDFile file = getDTDFile();
- if (file != null) {
- file.removeDTDFileListener(this);
- }
- // clear out all annotations
- if (fViewer.getProjectionAnnotationModel() != null)
- fViewer.getProjectionAnnotationModel().removeAllAnnotations();
+ if (fDocument != null && file != null && fViewer.getProjectionAnnotationModel() != null) {
+ if (fDocumentListener == null)
+ fDocumentListener = new DocumentListener();
+
+ fDocument.addDocumentListener(fDocumentListener);
- fDocument = fViewer.getDocument();
- file = getDTDFile();
- if (file != null) {
// add dtd file listener to new dtd file
file.addDTDFileListener(this);
addAllAnnotations(file);
}
+ fProjectionNeedsToBeEnabled = false;
}
/**
@@ -207,6 +367,7 @@ public class StructuredTextFoldingProviderDTD implements IStructuredTextFoldingP
}
fViewer = viewer;
fViewer.addProjectionListener(this);
+ fViewer.addTextInputListener(this);
}
private boolean isInstalled() {
@@ -228,79 +389,103 @@ public class StructuredTextFoldingProviderDTD implements IStructuredTextFoldingP
}
public void nodeChanged(DTDNode node) {
+ /*
+ * Don't believe this is necessary (used to need it to only add
+ * projection annotations to elements that span more than one line,
+ * but now just always add projection annotation)
+ */
+ // long start = System.currentTimeMillis();
+ // // recalculate projection annotations for node
+ // // check if this was even a projectable node to start with
+ // if (isNodeProjectable(node)) {
+ // // find the existing annotation
+ // TagProjectionAnnotation anno = findExistingAnnotation(node);
+ // // if able to project node see if projection annotation was
+ // // already created and create new if needed
+ // Position newPos = createProjectionPosition(node);
+ // if (newPos != null && anno == null) {
+ // TagProjectionAnnotation newAnnotation = new
+ // TagProjectionAnnotation(node, false);
+ // // add to map containing annotations to add
+ // fViewer.getProjectionAnnotationModel().addAnnotation(newAnnotation,
+ // newPos);
+ // }
+ // // if not able to project node see if projection annotation was
+ // // already created and remove it
+ // if (newPos == null && anno != null) {
+ // fViewer.getProjectionAnnotationModel().removeAnnotation(anno);
+ // }
+ // }
+ //
+ // long end = System.currentTimeMillis();
+ // if (debugProjectionPerf) {
+ // String nodeName = node != null ? node.getNodeName() : "null";
+ // //$NON-NLS-1$
+ // System.out.println("StructuredTextFoldingProviderDTD.nodeChanged ("
+ // + nodeName + "):" + (end - start)); //$NON-NLS-1$ //$NON-NLS-2$
+ // }
+ }
+
+ public void nodesAdded(NodesEvent event) {
long start = System.currentTimeMillis();
- // recalculate projection annotations for node
- // check if this was even a projectable node to start with
- if (isNodeProjectable(node)) {
- // find the existing annotation
- TagProjectionAnnotation anno = findExistingAnnotation(node);
- // if able to project node see if projection annotation was
- // already created and create new if needed
- Position newPos = createProjectionPosition(node);
- if (newPos != null && anno == null) {
- TagProjectionAnnotation newAnnotation = new TagProjectionAnnotation(node, false);
- // add to map containing annotations to add
- fViewer.getProjectionAnnotationModel().addAnnotation(newAnnotation, newPos);
- }
- // if not able to project node see if projection annotation was
- // already created and remove it
- if (newPos == null && anno != null) {
- fViewer.getProjectionAnnotationModel().removeAnnotation(anno);
- }
- }
+ processNodesEvent(event, NodeChange.ADD);
- long end = System.currentTimeMillis();
if (debugProjectionPerf) {
- String nodeName = node != null ? node.getNodeName() : "null"; //$NON-NLS-1$
- System.out.println("StructuredTextFoldingProviderDTD.nodeChanged (" + nodeName + "):" + (end - start)); //$NON-NLS-1$ //$NON-NLS-2$
+ long end = System.currentTimeMillis();
+ System.out.println("StructuredTextFoldingProviderDTD.nodesAdded: " + (end - start)); //$NON-NLS-1$
}
}
- public void nodesAdded(NodesEvent event) {
- long start = System.currentTimeMillis();
-
- // add projection annotations for all nodes in event.getNodes()
+ /**
+ * Goes through every changed node in event and add to queue of node
+ * changes that will be recalculated for projection annotation model.
+ *
+ * @param event
+ * @param changeType
+ */
+ private void processNodesEvent(NodesEvent event, int changeType) {
List nodes = event.getNodes();
Iterator it = nodes.iterator();
while (it.hasNext()) {
DTDNode node = (DTDNode) it.next();
if (isNodeProjectable(node)) {
- // add
- Position newPos = createProjectionPosition(node);
- if (newPos != null) {
- TagProjectionAnnotation newAnnotation = new TagProjectionAnnotation(node, false);
- // add to map containing annotations to add
- fViewer.getProjectionAnnotationModel().addAnnotation(newAnnotation, newPos);
+ if (fQueuedNodeChanges == null) {
+ fQueuedNodeChanges = new ArrayList();
+ }
+
+ int existingIndex = fQueuedNodeChanges.indexOf(node);
+ if (existingIndex > -1) {
+ // node is already queued up
+ NodeChange existingChange = (NodeChange) fQueuedNodeChanges.remove(existingIndex);
+ // don't add if added then removed node or vice versa
+ if (existingChange.getChangeType() == changeType) {
+ NodeChange newChange = new NodeChange(node, changeType);
+ fQueuedNodeChanges.add(newChange);
+ }
+ }
+ else {
+ // not queued up yet, so queue node
+ NodeChange newChange = new NodeChange(node, changeType);
+ fQueuedNodeChanges.add(newChange);
}
}
}
-
- long end = System.currentTimeMillis();
- if (debugProjectionPerf)
- System.out.println("StructuredTextFoldingProviderDTD.nodesAdded: " + (end - start)); //$NON-NLS-1$
+ // if document isn't changing, go ahead and apply it
+ if (!fIsDocumentChanging) {
+ applyAnnotationModelChanges();
+ }
}
public void nodesRemoved(NodesEvent event) {
long start = System.currentTimeMillis();
- // remove projection annotations for all nodes in event.getNodes()
- List nodes = event.getNodes();
- Iterator it = nodes.iterator();
- while (it.hasNext()) {
- DTDNode node = (DTDNode) it.next();
- // check if removed node was projectable in the first place
- if (isNodeProjectable(node)) {
- // remove
- TagProjectionAnnotation anno = findExistingAnnotation(node);
- if (anno != null)
- fViewer.getProjectionAnnotationModel().removeAnnotation(anno);
- }
- }
+ processNodesEvent(event, NodeChange.REMOVE);
- long end = System.currentTimeMillis();
- if (debugProjectionPerf)
+ if (debugProjectionPerf) {
+ long end = System.currentTimeMillis();
System.out.println("StructuredTextFoldingProviderDTD.nodesRemoved: " + (end - start)); //$NON-NLS-1$
+ }
}
public void projectionDisabled() {
@@ -309,13 +494,46 @@ public class StructuredTextFoldingProviderDTD implements IStructuredTextFoldingP
file.removeDTDFileListener(this);
}
+ // remove document listener
+ if (fDocumentListener != null && fDocument != null) {
+ fDocument.removeDocumentListener(fDocumentListener);
+ fDocument = null;
+
+ // clear out list of queued changes since it may no longer be
+ // accurate
+ if (fQueuedNodeChanges != null) {
+ fQueuedNodeChanges.clear();
+ fQueuedNodeChanges = null;
+ }
+ }
+
fDocument = null;
+ fProjectionNeedsToBeEnabled = false;
}
public void projectionEnabled() {
initialize();
}
+ public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) {
+ // if folding is enabled and new document is going to be a totally
+ // different document, disable projection
+ if (fDocument != null && fDocument != newInput) {
+ // disable projection and disconnect everything
+ projectionDisabled();
+ fProjectionNeedsToBeEnabled = true;
+ }
+ }
+
+ public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {
+ // if projection was previously enabled before input document changed
+ // and new document is different than old document
+ if (fProjectionNeedsToBeEnabled && fDocument == null && newInput != null) {
+ projectionEnabled();
+ fProjectionNeedsToBeEnabled = false;
+ }
+ }
+
/**
* Disconnect this IStructuredTextFoldingProvider from projection viewer
*/
@@ -324,6 +542,7 @@ public class StructuredTextFoldingProviderDTD implements IStructuredTextFoldingP
projectionDisabled();
fViewer.removeProjectionListener(this);
+ fViewer.addTextInputListener(this);
fViewer = null;
}
}

Back to the top