blob: 2bdf4f6d22a287e588f2020128f6f34971d28749 [file] [log] [blame]
nitind7de149b2005-10-31 21:12:32 +00001/*******************************************************************************
2 * Copyright (c) 2005 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 *
11 *******************************************************************************/
david_williamsb1f75052005-02-18 00:25:37 +000012package org.eclipse.wst.dtd.ui.internal.projection;
13
14import java.util.Iterator;
15import java.util.List;
16
17import org.eclipse.core.runtime.Platform;
18import org.eclipse.jface.text.BadLocationException;
19import org.eclipse.jface.text.IDocument;
20import org.eclipse.jface.text.Position;
21import org.eclipse.jface.text.source.projection.IProjectionListener;
22import org.eclipse.jface.text.source.projection.ProjectionAnnotation;
23import org.eclipse.jface.text.source.projection.ProjectionViewer;
nitindd6e591d2005-03-14 22:21:57 +000024import org.eclipse.wst.dtd.core.internal.DTDFile;
25import org.eclipse.wst.dtd.core.internal.DTDNode;
26import org.eclipse.wst.dtd.core.internal.TopLevelNode;
27import org.eclipse.wst.dtd.core.internal.document.DTDModelImpl;
28import org.eclipse.wst.dtd.core.internal.event.IDTDFileListener;
29import org.eclipse.wst.dtd.core.internal.event.NodesEvent;
david_williams4ad020f2005-04-18 08:00:30 +000030import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
31import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
32import org.eclipse.wst.sse.core.internal.provisional.StructuredModelManager;
david_williamsb1f75052005-02-18 00:25:37 +000033import org.eclipse.wst.sse.ui.internal.projection.IStructuredTextFoldingProvider;
34import org.w3c.dom.Node;
35
36/**
37 * Updates the projection model of a structured model for DTD.
38 */
39public class StructuredTextFoldingProviderDTD implements IStructuredTextFoldingProvider, IProjectionListener, IDTDFileListener {
40 private final static boolean debugProjectionPerf = "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.wst.dtd.ui/projectionperf")); //$NON-NLS-1$ //$NON-NLS-2$
41
42 private class TagProjectionAnnotation extends ProjectionAnnotation {
43 private Node fNode;
44
45 public TagProjectionAnnotation(Node node, boolean isCollapsed) {
46 super(isCollapsed);
47 fNode = node;
48 }
49
50 public Node getNode() {
51 return fNode;
52 }
53
54 public void setNode(Node node) {
55 fNode = node;
56 }
57 }
58
59 private IDocument fDocument;
60 private ProjectionViewer fViewer;
61
62
63 /**
64 * Goes through every node creates projection annotation if needed
65 *
66 * @param DTDFile
67 * assumes file is not null
68 */
69 private void addAllAnnotations(DTDFile file) {
70 long start = System.currentTimeMillis();
71
72 List nodes = file.getNodes();
73 Iterator it = nodes.iterator();
74 while (it.hasNext()) {
75 DTDNode node = (DTDNode) it.next();
76 Position newPos = createProjectionPosition(node);
77 if (newPos != null) {
78 TagProjectionAnnotation newAnnotation = new TagProjectionAnnotation(node, false);
79 // add to map containing annotations to add
80 fViewer.getProjectionAnnotationModel().addAnnotation(newAnnotation, newPos);
81 }
82 }
83
84 long end = System.currentTimeMillis();
85 if (debugProjectionPerf)
david_williams38046012005-04-08 19:04:29 +000086 System.out.println("StructuredTextFoldingProviderDTD.addAllAnnotations: " + (end - start)); //$NON-NLS-1$
david_williamsb1f75052005-02-18 00:25:37 +000087 }
88
89 /**
90 * Create a projection position from the given node. Able to get
91 * projection position if node isNodeProjectable.
92 *
93 * @param node
94 * @return null if no projection position possible, a Position otherwise
95 */
96 private Position createProjectionPosition(Node node) {
97 Position pos = null;
98 if (isNodeProjectable(node) && node instanceof IndexedRegion) {
99 IDocument document = fViewer.getDocument();
100 if (document != null) {
101 IndexedRegion inode = (IndexedRegion) node;
102 int start = inode.getStartOffset();
103 int end = inode.getEndOffset();
104 if (start >= 0 && start < end) {
105 try {
106 int startLine = fDocument.getLineOfOffset(start);
107 int endLine = fDocument.getLineOfOffset(end);
108 // checks if projection start/end region is on the
109 // same line
110 if ((startLine < endLine) && (endLine + 1 < fDocument.getNumberOfLines())) {
111 int offset = fDocument.getLineOffset(startLine);
112 int endOffset = fDocument.getLineOffset(endLine + 1);
113 pos = new Position(offset, endOffset - offset);
114 }
115 }
116 catch (BadLocationException x) {
117 // Logger.log(Logger.WARNING_DEBUG, null, x);
118 }
119 }
120 }
121 }
122 return pos;
123 }
124
125 /**
126 * Searches through projection annotation model and retrieves
127 * TagProjectionAnnotation for node
128 *
129 * @param node
130 * @return TagProjectionAnnotation for node or null if could not be found
131 */
132 private TagProjectionAnnotation findExistingAnnotation(Node node) {
133 TagProjectionAnnotation anno = null;
134
135 if (node != null) {
136 Iterator it = fViewer.getProjectionAnnotationModel().getAnnotationIterator();
137 while (it.hasNext() && anno == null) {
138 TagProjectionAnnotation a = (TagProjectionAnnotation) it.next();
139 if (node.equals(a.getNode()))
140 anno = a;
141 }
142 }
143 return anno;
144 }
145
146 /**
147 * Get the dtd file for the fDocument
148 *
149 * @param document
150 * @return
151 */
152 private DTDFile getDTDFile() {
153 DTDFile dtdFile = null;
154
155 IStructuredModel sModel = null;
156 try {
157 sModel = StructuredModelManager.getModelManager().getExistingModelForRead(fDocument);
158 if (sModel instanceof DTDModelImpl) {
159 dtdFile = ((DTDModelImpl) sModel).getDTDFile();
160 }
161 }
162 finally {
163 if (sModel != null) {
164 sModel.releaseFromRead();
165 }
166 }
167 return dtdFile;
168 }
169
170 /**
171 * Initialize this provider with the correct document. Assumes projection
172 * is enabled. (otherwise, only install would have been called)
173 */
174 public void initialize() {
175 if (!isInstalled())
176 return;
177
178 // remove dtd file listener from old dtd file
179 DTDFile file = getDTDFile();
180 if (file != null) {
181 file.removeDTDFileListener(this);
182 }
183
184 // clear out all annotations
185 if (fViewer.getProjectionAnnotationModel() != null)
186 fViewer.getProjectionAnnotationModel().removeAllAnnotations();
187
188 fDocument = fViewer.getDocument();
189 file = getDTDFile();
190 if (file != null) {
191 // add dtd file listener to new dtd file
192 file.addDTDFileListener(this);
193
194 addAllAnnotations(file);
195 }
196 }
197
198 /**
199 * Associate a ProjectionViewer with this IStructuredTextFoldingProvider
200 *
201 * @param viewer
202 */
203 public void install(ProjectionViewer viewer) {
204 // uninstall before trying to install new viewer
205 if (isInstalled()) {
206 uninstall();
207 }
208 fViewer = viewer;
209 fViewer.addProjectionListener(this);
210 }
211
212 private boolean isInstalled() {
213 return fViewer != null;
214 }
215
216 /**
217 * Returns true if node is a node type able to fold
218 *
219 * @param node
220 * @return boolean true if node is projectable, false otherwise
221 */
222 private boolean isNodeProjectable(Node node) {
223 if (node != null) {
224 if (node instanceof TopLevelNode)
225 return true;
226 }
227 return false;
228 }
229
230 public void nodeChanged(DTDNode node) {
231 long start = System.currentTimeMillis();
232
233 // recalculate projection annotations for node
234 // check if this was even a projectable node to start with
235 if (isNodeProjectable(node)) {
236 // find the existing annotation
237 TagProjectionAnnotation anno = findExistingAnnotation(node);
238 // if able to project node see if projection annotation was
239 // already created and create new if needed
240 Position newPos = createProjectionPosition(node);
241 if (newPos != null && anno == null) {
242 TagProjectionAnnotation newAnnotation = new TagProjectionAnnotation(node, false);
243 // add to map containing annotations to add
244 fViewer.getProjectionAnnotationModel().addAnnotation(newAnnotation, newPos);
245 }
246 // if not able to project node see if projection annotation was
247 // already created and remove it
248 if (newPos == null && anno != null) {
249 fViewer.getProjectionAnnotationModel().removeAnnotation(anno);
250 }
251 }
252
253 long end = System.currentTimeMillis();
254 if (debugProjectionPerf) {
david_williams38046012005-04-08 19:04:29 +0000255 String nodeName = node != null ? node.getNodeName() : "null"; //$NON-NLS-1$
256 System.out.println("StructuredTextFoldingProviderDTD.nodeChanged (" + nodeName + "):" + (end - start)); //$NON-NLS-1$ //$NON-NLS-2$
david_williamsb1f75052005-02-18 00:25:37 +0000257 }
258 }
259
260 public void nodesAdded(NodesEvent event) {
261 long start = System.currentTimeMillis();
262
263 // add projection annotations for all nodes in event.getNodes()
264 List nodes = event.getNodes();
265 Iterator it = nodes.iterator();
266 while (it.hasNext()) {
267 DTDNode node = (DTDNode) it.next();
268 if (isNodeProjectable(node)) {
269 // add
270 Position newPos = createProjectionPosition(node);
271 if (newPos != null) {
272 TagProjectionAnnotation newAnnotation = new TagProjectionAnnotation(node, false);
273 // add to map containing annotations to add
274 fViewer.getProjectionAnnotationModel().addAnnotation(newAnnotation, newPos);
275 }
276 }
277 }
278
279 long end = System.currentTimeMillis();
280 if (debugProjectionPerf)
david_williams38046012005-04-08 19:04:29 +0000281 System.out.println("StructuredTextFoldingProviderDTD.nodesAdded: " + (end - start)); //$NON-NLS-1$
david_williamsb1f75052005-02-18 00:25:37 +0000282 }
283
284 public void nodesRemoved(NodesEvent event) {
285 long start = System.currentTimeMillis();
286
287 // remove projection annotations for all nodes in event.getNodes()
288 List nodes = event.getNodes();
289 Iterator it = nodes.iterator();
290 while (it.hasNext()) {
291 DTDNode node = (DTDNode) it.next();
292 // check if removed node was projectable in the first place
293 if (isNodeProjectable(node)) {
294 // remove
295 TagProjectionAnnotation anno = findExistingAnnotation(node);
296 if (anno != null)
297 fViewer.getProjectionAnnotationModel().removeAnnotation(anno);
298 }
299 }
300
301 long end = System.currentTimeMillis();
302 if (debugProjectionPerf)
david_williams38046012005-04-08 19:04:29 +0000303 System.out.println("StructuredTextFoldingProviderDTD.nodesRemoved: " + (end - start)); //$NON-NLS-1$
david_williamsb1f75052005-02-18 00:25:37 +0000304 }
305
306 public void projectionDisabled() {
307 DTDFile file = getDTDFile();
308 if (file != null) {
309 file.removeDTDFileListener(this);
310 }
311
312 fDocument = null;
313 }
314
315 public void projectionEnabled() {
316 initialize();
317 }
318
319 /**
320 * Disconnect this IStructuredTextFoldingProvider from projection viewer
321 */
322 public void uninstall() {
323 if (isInstalled()) {
324 projectionDisabled();
325
326 fViewer.removeProjectionListener(this);
327 fViewer = null;
328 }
329 }
330}