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