blob: fe1832d06c33fa15d481346505c29a9946ab85e5 [file] [log] [blame]
david_williamscfdb2cd2004-11-11 08:37:49 +00001/*******************************************************************************
2 * Copyright (c) 2001, 2004 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 * Jens Lukowski/Innoopract - initial renaming/restructuring
11 *
12 *******************************************************************************/
13package org.eclipse.wst.sse.core.cleanup;
14
15import java.io.ByteArrayInputStream;
16import java.io.FileInputStream;
17import java.io.IOException;
18import java.io.InputStream;
19import java.io.OutputStream;
20import java.util.Vector;
21
22import org.eclipse.core.resources.IFile;
23import org.eclipse.core.runtime.CoreException;
24import org.eclipse.core.runtime.Platform;
25import org.eclipse.jface.text.BadLocationException;
26import org.eclipse.jface.text.IDocument;
27import org.eclipse.jface.text.IDocumentPartitioner;
28import org.eclipse.jface.text.IRegion;
29import org.eclipse.wst.common.encoding.CommonEncodingPreferenceNames;
30import org.eclipse.wst.sse.core.IModelManager;
31import org.eclipse.wst.sse.core.IModelManagerPlugin;
32import org.eclipse.wst.sse.core.IStructuredModel;
33import org.eclipse.wst.sse.core.format.IStructuredFormatProcessor;
34import org.eclipse.wst.sse.core.internal.Logger;
35import org.eclipse.wst.sse.core.text.IStructuredDocument;
36import org.w3c.dom.Attr;
37import org.w3c.dom.Node;
38
39
40public abstract class AbstractStructuredCleanupProcessor implements IStructuredCleanupProcessor {
41 public boolean refreshCleanupPreferences = true; // special flag for JUnit
42
43 // tests to skip refresh
44 // of cleanup preferences
45 // when it's set to false
46
47 public String cleanupContent(String input) throws IOException, CoreException {
48 IStructuredModel structuredModel = null;
49 InputStream inputStream = null;
50 try {
51 // setup structuredModel
52 inputStream = new ByteArrayInputStream(input.getBytes("UTF8")); //$NON-NLS-1$
53 String id = inputStream.toString() + getContentType();
54 structuredModel = getModelManager().getModelForRead(id, inputStream, null);
55
56 // cleanup
57 cleanupModel(structuredModel, 0, structuredModel.getStructuredDocument().getLength());
58
59 // return output
60 return structuredModel.getStructuredDocument().get();
61 } finally {
62 ensureClosed(null, inputStream);
63 // release from model manager
64 if (structuredModel != null)
65 structuredModel.releaseFromRead();
66 }
67 }
68
69 public String cleanupContent(String input, int start, int length) throws IOException, CoreException {
70 IStructuredModel structuredModel = null;
71 InputStream inputStream = null;
72 try {
73 // setup structuredModel
74 inputStream = new ByteArrayInputStream(input.getBytes("UTF8")); //$NON-NLS-1$
75 String id = inputStream.toString() + getContentType();
76 structuredModel = getModelManager().getModelForRead(id, inputStream, null);
77
78 // cleanup
79 cleanupModel(structuredModel, start, length);
80
81 // return output
82 return structuredModel.getStructuredDocument().get();
83 } finally {
84 ensureClosed(null, inputStream);
85 // release from model manager
86 if (structuredModel != null)
87 structuredModel.releaseFromRead();
88 }
89 }
90
91 public void cleanupDocument(IDocument document) throws IOException, CoreException {
92 if (document == null)
93 return;
94
95 IStructuredModel structuredModel = null;
96 //OutputStream outputStream = null;
97 try {
98 // setup structuredModel
99 // Note: We are getting model for edit. Will save model if model
100 // changed.
101 structuredModel = getModelManager().getExistingModelForEdit(document);
102
103 // cleanup
104 cleanupModel(structuredModel);
105
106 // save model if needed
107 if (!structuredModel.isSharedForEdit() && structuredModel.isSaveNeeded())
108 structuredModel.save();
109 } finally {
110 //ensureClosed(outputStream, null);
111 // release from model manager
112 if (structuredModel != null)
113 structuredModel.releaseFromEdit();
114 }
115 }
116
117 public void cleanupDocument(IDocument document, int start, int length) throws IOException, CoreException {
118 if (document == null)
119 return;
120
121 if (start >= 0 && length >= 0 && start + length <= document.getLength()) {
122 IStructuredModel structuredModel = null;
123 //OutputStream outputStream = null;
124 try {
125 // setup structuredModel
126 // Note: We are getting model for edit. Will save model if
127 // model changed.
128 structuredModel = getModelManager().getExistingModelForEdit(document);
129
130 // cleanup
131 cleanupModel(structuredModel, start, length);
132
133 // save model if needed
134 if (!structuredModel.isSharedForEdit() && structuredModel.isSaveNeeded())
135 structuredModel.save();
136 } finally {
137 //ensureClosed(outputStream, null);
138 // release from model manager
139 if (structuredModel != null)
140 structuredModel.releaseFromEdit();
141 }
142 }
143 }
144
145 public void cleanupFile(IFile file) throws IOException, CoreException {
146 IStructuredModel structuredModel = null;
147 //OutputStream outputStream = null;
148 try {
149 // setup structuredModel
150 structuredModel = getModelManager().getModelForRead(file);
151
152 // cleanup
153 cleanupModel(structuredModel, 0, structuredModel.getStructuredDocument().getLength());
154
155 // save output to file
156 //outputStream = new
157 // FileOutputStream(file.getLocation().toString());
158 structuredModel.save(file);
159 } finally {
160 //ensureClosed(outputStream, null);
161 // release from model manager
162 if (structuredModel != null)
163 structuredModel.releaseFromRead();
164 }
165 }
166
167 public void cleanupFile(IFile file, int start, int length) throws IOException, CoreException {
168 IStructuredModel structuredModel = null;
169 //OutputStream outputStream = null;
170 try {
171 // setup structuredModel
172 structuredModel = getModelManager().getModelForRead(file);
173
174 // cleanup
175 cleanupModel(structuredModel, start, length);
176
177 // save output to file
178 //outputStream = new
179 // FileOutputStream(file.getLocation().toString());
180 structuredModel.save(file);
181 } finally {
182 //ensureClosed(outputStream, null);
183 // release from model manager
184 if (structuredModel != null)
185 structuredModel.releaseFromRead();
186 }
187 }
188
189 public void cleanupFileName(String fileName) throws IOException, CoreException {
190 IStructuredModel structuredModel = null;
191 InputStream inputStream = null;
192 //OutputStream outputStream = null;
193 try {
194 // setup structuredModel
195 inputStream = new FileInputStream(fileName);
196 structuredModel = getModelManager().getModelForRead(fileName, inputStream, null);
197
198 // cleanup
199 cleanupModel(structuredModel, 0, structuredModel.getStructuredDocument().getLength());
200
201 // save output to file
202 //outputStream = new FileOutputStream(fileName);
203 structuredModel.save();
204 } finally {
205 //ensureClosed(outputStream, inputStream);
206 // release from model manager
207 if (structuredModel != null)
208 structuredModel.releaseFromRead();
209 }
210 }
211
212 public void cleanupFileName(String fileName, int start, int length) throws IOException, CoreException {
213 IStructuredModel structuredModel = null;
214 InputStream inputStream = null;
215 //OutputStream outputStream = null;
216 try {
217 // setup structuredModel
218 inputStream = new FileInputStream(fileName);
219 structuredModel = getModelManager().getModelForRead(fileName, inputStream, null);
220
221 // cleanup
222 cleanupModel(structuredModel, start, length);
223
224 // save output to file
225 //outputStream = new FileOutputStream(fileName);
226 structuredModel.save();
227 } finally {
228 //ensureClosed(outputStream, inputStream);
229 // release from model manager
230 if (structuredModel != null)
231 structuredModel.releaseFromRead();
232 }
233 }
234
235 public void cleanupModel(IStructuredModel structuredModel) {
236
237 int start = 0;
238 int length = structuredModel.getStructuredDocument().getLength();
239 cleanupModel(structuredModel, start, length);
240 }
241
242 public void cleanupModel(IStructuredModel structuredModel, int start, int length) {
243
244 if (structuredModel != null) {
245 if ((start >= 0) && (length <= structuredModel.getStructuredDocument().getLength())) {
246 Vector activeNodes = getActiveNodes(structuredModel, start, length);
247 if (activeNodes.size() > 0) {
248 Node firstNode = (Node) activeNodes.firstElement();
249 Node lastNode = (Node) activeNodes.lastElement();
250 boolean done = false;
251 Node eachNode = firstNode;
252 Node nextNode = null;
253 while (!done) {
254 // update "done"
255 done = (eachNode == lastNode);
256
257 // get next sibling before cleanup because eachNode
258 // may
259 // be deleted,
260 // for example when it's an empty text node
261 nextNode = eachNode.getNextSibling();
262
263 // cleanup selected node(s)
264 cleanupNode(eachNode);
265
266 // update each node
267 if (nextNode != null && nextNode.getParentNode() == null)
268 // nextNode is deleted during cleanup
269 eachNode = eachNode.getNextSibling();
270 else
271 eachNode = nextNode;
272
273 // This should not be needed, but just in case
274 // something went wrong with with eachNode.
275 // We don't want an infinite loop here.
276 if (eachNode == null)
277 done = true;
278 }
279
280 // format source
281 if (getFormatSourcePreference(structuredModel)) {
282 // format the document
283 IStructuredFormatProcessor formatProcessor = getFormatProcessor();
284 formatProcessor.formatModel(structuredModel);
285 }
286
287 // convert EOL codes
288 if (getConvertEOLCodesPreference(structuredModel)) {
289 IDocument document = structuredModel.getStructuredDocument();
290 String endOfLineCode = getEOLCodePreference(structuredModel);
291 String endOfLineCodeString = null;
292 if (endOfLineCode.compareTo(CommonEncodingPreferenceNames.LF) == 0)
293 endOfLineCodeString = CommonEncodingPreferenceNames.STRING_LF;
294 else if (endOfLineCode.compareTo(CommonEncodingPreferenceNames.CR) == 0)
295 endOfLineCodeString = CommonEncodingPreferenceNames.STRING_CR;
296 else if (endOfLineCode.compareTo(CommonEncodingPreferenceNames.CRLF) == 0)
297 endOfLineCodeString = CommonEncodingPreferenceNames.STRING_CRLF;
298 if (endOfLineCodeString != null) {
299 convertLineDelimiters(document, endOfLineCodeString);
300 // DMW: 8/24/2002 setting line delimiter in
301 // document allows
302 // subsequent editing to insert the same line
303 // delimiter.
304 if (document instanceof IStructuredDocument) {
305 ((IStructuredDocument) document).setLineDelimiter(endOfLineCodeString);
306 }
307 structuredModel.setDirtyState(true);
308 }
309 }
310 }
311 }
312 }
313 }
314
315 public void cleanupNode(Node node) {
316 if (node != null) {
317 Node cleanupNode = node;
318
319 // cleanup the owner node if it's an attribute node
320 if (cleanupNode.getNodeType() == Node.ATTRIBUTE_NODE)
321 cleanupNode = ((Attr) cleanupNode).getOwnerElement();
322
323 // refresh cleanup preferences before getting cleanup handler
324 if (refreshCleanupPreferences)
325 refreshCleanupPreferences();
326
327 // get cleanup handler
328 IStructuredCleanupHandler cleanupHandler = getCleanupHandler(cleanupNode);
329 if (cleanupHandler != null) {
330 // cleanup each node
331 cleanupHandler.cleanup(cleanupNode);
332 }
333 }
334 }
335
336 protected void convertLineDelimiters(IDocument document, String newDelimiter) {
337
338 final int lineCount = document.getNumberOfLines();
339 IDocumentPartitioner partitioner = document.getDocumentPartitioner();
340 if (partitioner != null) {
341 partitioner.disconnect();
342 document.setDocumentPartitioner(null);
343 }
344 try {
345 for (int i = 0; i < lineCount; i++) {
346 final String delimiter = document.getLineDelimiter(i);
347 if (delimiter != null && delimiter.length() > 0 && !delimiter.equals(newDelimiter)) {
348 IRegion region = document.getLineInformation(i);
349 document.replace(region.getOffset() + region.getLength(), delimiter.length(), newDelimiter);
350 }
351 }
352 } catch (BadLocationException e) {
353 Logger.logException(e);
354 } finally {
355 if (partitioner != null) {
356 partitioner.connect(document);
357 document.setDocumentPartitioner(partitioner);
358 }
359 }
360 }
361
362 protected void ensureClosed(OutputStream outputStream, InputStream inputStream) {
363 try {
364 if (inputStream != null) {
365 inputStream.close();
366 }
367 } catch (IOException e) {
368 Logger.logException(e); // hopeless
369 }
370 try {
371 if (outputStream != null) {
372 outputStream.close();
373 }
374 } catch (IOException e) {
375 Logger.logException(e); // hopeless
376 }
377 }
378
379 protected Vector getActiveNodes(IStructuredModel structuredModel, int startNodeOffset, int length) {
380 Vector activeNodes = new Vector();
381
382 if (structuredModel != null) {
383 Node startNode = (Node) structuredModel.getIndexedRegion(startNodeOffset);
384 Node endNode = (Node) structuredModel.getIndexedRegion(startNodeOffset + length);
385
386 // make sure it's an non-empty document
387 if (startNode != null) {
388 while (isSiblingOf(startNode, endNode) == false) {
389 if (endNode != null)
390 endNode = endNode.getParentNode();
391 if (endNode == null) {
392 startNode = startNode.getParentNode();
393 endNode = (Node) structuredModel.getIndexedRegion(startNodeOffset + length);
394 }
395 }
396
397 while (startNode != endNode) {
398 activeNodes.addElement(startNode);
399 startNode = startNode.getNextSibling();
400 }
401 if (startNode != null)
402 activeNodes.addElement(startNode);
403 }
404 }
405
406 return activeNodes;
407 }
408
409 abstract protected IStructuredCleanupHandler getCleanupHandler(Node node);
410
411 abstract protected String getContentType();
412
413 protected boolean getConvertEOLCodesPreference(IStructuredModel structuredModel) {
414
415 boolean convertEOLCodes = true;
416 IStructuredCleanupHandler cleanupHandler = getCleanupHandler((Node) structuredModel.getIndexedRegion(0));
417 if (cleanupHandler != null) {
418 IStructuredCleanupPreferences cleanupPreferences = cleanupHandler.getCleanupPreferences();
419 convertEOLCodes = cleanupPreferences.getConvertEOLCodes();
420 }
421 return convertEOLCodes;
422 }
423
424 protected String getEOLCodePreference(IStructuredModel structuredModel) {
425
426 String eolCode = System.getProperty("line.separator"); //$NON-NLS-1$
427
428 IStructuredCleanupHandler cleanupHandler = getCleanupHandler((Node) structuredModel.getIndexedRegion(0));
429 if (cleanupHandler != null) {
430 IStructuredCleanupPreferences cleanupPreferences = cleanupHandler.getCleanupPreferences();
431 eolCode = cleanupPreferences.getEOLCode();
432 }
433 return eolCode;
434 }
435
436 abstract protected IStructuredFormatProcessor getFormatProcessor();
437
438 protected boolean getFormatSourcePreference(IStructuredModel structuredModel) {
439
440 boolean formatSource = true;
441 IStructuredCleanupHandler cleanupHandler = getCleanupHandler((Node) structuredModel.getIndexedRegion(0));
442 if (cleanupHandler != null) {
443 IStructuredCleanupPreferences cleanupPreferences = cleanupHandler.getCleanupPreferences();
444 formatSource = cleanupPreferences.getFormatSource();
445 }
446 return formatSource;
447 }
448
449 private IModelManager getModelManager() {
450
451 IModelManagerPlugin plugin = (IModelManagerPlugin) Platform.getPlugin(IModelManagerPlugin.ID);
452 return plugin.getModelManager();
453 }
454
455 protected boolean isSiblingOf(Node node, Node endNode) {
456 if (endNode == null) {
457 return true;
458 } else {
459 Node siblingNode = node;
460 while (siblingNode != null) {
461 if (siblingNode == endNode)
462 return true;
463 else
464 siblingNode = siblingNode.getNextSibling();
465 }
466 return false;
467 }
468 }
469
470 abstract protected void refreshCleanupPreferences();
471}