47a77989f5cc8f9e6ed399dc4dde503e289cc3f8
[phpeclipse.git] / net.sourceforge.phpeclipse.ui / src / net / sourceforge / phpeclipse / xml / ui / internal / text / XMLReconcilingStrategy.java
1 /*
2  * Copyright (c) 2003-2004 Christopher Lenz and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     Christopher Lenz - initial API and implementation
10  * 
11  * $Id: XMLReconcilingStrategy.java,v 1.3 2006-10-21 23:14:13 pombredanne Exp $
12  */
13 package net.sourceforge.phpeclipse.xml.ui.internal.text;
14
15 import java.lang.reflect.InvocationTargetException;
16 import java.util.Iterator;
17
18 import net.sourceforge.phpeclipse.ui.text.IReconcilingParticipant;
19
20 import org.eclipse.core.runtime.IProgressMonitor;
21 import org.eclipse.jface.operation.IRunnableWithProgress;
22 import org.eclipse.jface.text.IDocument;
23 import org.eclipse.jface.text.IRegion;
24 import org.eclipse.jface.text.Position;
25 import org.eclipse.jface.text.reconciler.DirtyRegion;
26 import org.eclipse.jface.text.reconciler.IReconcileResult;
27 import org.eclipse.jface.text.reconciler.IReconcileStep;
28 import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
29 import org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension;
30 import org.eclipse.jface.text.source.Annotation;
31 import org.eclipse.jface.text.source.IAnnotationModel;
32 import org.eclipse.ui.IEditorInput;
33 import org.eclipse.ui.actions.WorkspaceModifyOperation;
34 import org.eclipse.ui.texteditor.ITextEditor;
35
36 /**
37  * Reconciling strategy for XML document. This class is responsible for keeping
38  * the parsed model in sync with the text.
39  */
40 public class XMLReconcilingStrategy implements IReconcilingStrategy,
41                 IReconcilingStrategyExtension {
42
43         // Instance Variables ------------------------------------------------------
44
45         /**
46          * The associated text editor.
47          */
48         private ITextEditor editor;
49
50         /**
51          * A progress monitor that should be used for long-running operations.
52          */
53         IProgressMonitor progressMonitor;
54
55         /**
56          * The first (and only) reconcile step is the parsing of the style sheet.
57          */
58         private IReconcileStep firstStep;
59
60         // Constructors ------------------------------------------------------------
61
62         public XMLReconcilingStrategy(ITextEditor editor) {
63                 this.editor = editor;
64                 firstStep = new XMLReconcileStep(editor);
65         }
66
67         // IReconcilingStrategy Implementation -------------------------------------
68
69         /**
70          * @see IReconcilingStrategy#reconcile(DirtyRegion, IRegion)
71          */
72         public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
73                 removeTemporaryAnnotations();
74                 process(firstStep.reconcile(dirtyRegion, subRegion));
75         }
76
77         /**
78          * @see IReconcilingStrategy#reconcile(IRegion)
79          */
80         public void reconcile(IRegion partition) {
81                 removeTemporaryAnnotations();
82                 process(firstStep.reconcile(partition));
83         }
84
85         /**
86          * @see IReconcilingStrategy#setDocument(IDocument)
87          */
88         public void setDocument(IDocument document) {
89                 // FIXME
90                 firstStep.setInputModel(null); // new DocumentAdapter(document);
91         }
92
93         // IReconcilingStrategyExtension Implementation ----------------------------
94
95         /**
96          * @see IReconcilingStrategyExtension#initialReconcile()
97          */
98         public void initialReconcile() {
99                 process(firstStep.reconcile(null));
100         }
101
102         /**
103          * @see IReconcilingStrategyExtension#setProgressMonitor(IProgressMonitor)
104          */
105         public void setProgressMonitor(IProgressMonitor monitor) {
106                 firstStep.setProgressMonitor(monitor);
107                 progressMonitor = monitor;
108         }
109
110         // Private Methods ---------------------------------------------------------
111
112         /**
113          * Returns the annotation model for the editor input.
114          * 
115          * @return the annotation model
116          */
117         IAnnotationModel getAnnotationModel() {
118                 IEditorInput input = editor.getEditorInput();
119                 return editor.getDocumentProvider().getAnnotationModel(input);
120         }
121
122         /**
123          * Adds results of the reconcilation to the annotation model.
124          */
125         private void process(final IReconcileResult[] results) {
126                 if (results == null) {
127                         return;
128                 }
129
130                 IRunnableWithProgress runnable = new WorkspaceModifyOperation() {
131                         protected void execute(IProgressMonitor monitor) {
132                                 for (int i = 0; i < results.length; i++) {
133                                         if ((progressMonitor != null)
134                                                         && (progressMonitor.isCanceled())) {
135                                                 return;
136                                         }
137
138                                         if (results[i] instanceof AnnotationAdapter) {
139                                                 AnnotationAdapter result = (AnnotationAdapter) results[i];
140                                                 Position pos = result.getPosition();
141                                                 Annotation annotation = result.createAnnotation();
142                                                 getAnnotationModel().addAnnotation(annotation, pos);
143                                         }
144                                 }
145                         }
146                 };
147
148                 try {
149                         runnable.run(null);
150                 } catch (InvocationTargetException e) {
151                         e.printStackTrace();
152                 } catch (InterruptedException e) {
153                         e.printStackTrace();
154                 }
155
156                 if (editor instanceof IReconcilingParticipant) {
157                         ((IReconcilingParticipant) editor).reconciled();
158                 }
159         }
160
161         /*
162          * TODO A "real" implementation must be smarter, i.e. don't remove and add
163          * the annotations which are the same.
164          */
165         private void removeTemporaryAnnotations() {
166                 Iterator i = getAnnotationModel().getAnnotationIterator();
167                 while (i.hasNext()) {
168                         Annotation annotation = (Annotation) i.next();
169                         if (!annotation.isPersistent()) {
170                                 getAnnotationModel().removeAnnotation(annotation);
171                         }
172                 }
173         }
174 }