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.

summaryrefslogtreecommitdiffstats
blob: 675efa57da03ea2502f08d65fef19e3373a1db9a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/*******************************************************************************
 * Copyright (c) 2006 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.wst.html.ui.internal.projection;

import java.util.ArrayList;
import java.util.List;

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.source.projection.ProjectionAnnotationModel;
import org.eclipse.jface.text.source.projection.ProjectionViewer;
import org.eclipse.wst.html.ui.internal.Logger;

/**
 * Contains information about a projection viewer and also manages updating
 * the viewer's projection annotation model
 */
class ProjectionViewerInformation {
	// copies of this class located in:
	// org.eclipse.wst.xml.ui.internal.projection
	// org.eclipse.wst.css.ui.internal.projection
	// org.eclipse.wst.html.ui.internal.projection
	// org.eclipse.jst.jsp.ui.internal.projection

	/**
	 * Listens to document to be aware of when to update the projection
	 * annotation model.
	 */
	private class DocumentListener implements IDocumentListener {
		private ProjectionViewerInformation fInfo;

		public DocumentListener(ProjectionViewerInformation info) {
			fInfo = info;
		}

		public void documentAboutToBeChanged(DocumentEvent event) {
			IDocument document = event.getDocument();
			if (fInfo.getDocument() == document) {
				fInfo.setIsDocumentChanging(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 && fInfo.getDocument() == document) {
				if (fInfo.hasChangesQueued())
					((IDocumentExtension) document).registerPostNotificationReplace(this, new PostDocumentChangedListener(fInfo));
			}
		}
	}

	/**
	 * Essentially a post document changed listener because it is called after
	 * documentchanged has been fired.
	 */
	private class PostDocumentChangedListener implements IDocumentExtension.IReplace {
		private ProjectionViewerInformation fInfo;

		public PostDocumentChangedListener(ProjectionViewerInformation info) {
			fInfo = info;
		}

		public void perform(IDocument document, IDocumentListener owner) {
			fInfo.applyAnnotationModelChanges();
			fInfo.setIsDocumentChanging(false);
		}
	}

	/**
	 * Projection annotation model current associated with this projection
	 * viewer
	 */
	private ProjectionAnnotationModel fProjectionAnnotationModel;
	/**
	 * Document currently associated with this projection viewer
	 */
	private IDocument fDocument;
	/**
	 * Listener to fProjectionViewer's document
	 */
	private IDocumentListener fDocumentListener;
	/**
	 * Indicates whether or not document is in the middle of changing
	 */
	private boolean fIsDocumentChanging = false;
	/**
	 * List of projection annotation model changes that need to be applied
	 */
	private List fQueuedAnnotationChanges;

	public ProjectionViewerInformation(ProjectionViewer viewer) {
		fDocument = viewer.getDocument();
		fProjectionAnnotationModel = viewer.getProjectionAnnotationModel();
	}

	IDocument getDocument() {
		return fDocument;
	}

	private List getQueuedAnnotationChanges() {
		if (fQueuedAnnotationChanges == null) {
			fQueuedAnnotationChanges = new ArrayList();
		}
		return fQueuedAnnotationChanges;
	}

	void setIsDocumentChanging(boolean changing) {
		fIsDocumentChanging = changing;
	}

	private boolean isDocumentChanging() {
		return fIsDocumentChanging;
	}

	/**
	 * Applies the pending projection annotation model changes to the
	 * projection annotation model.
	 */
	void applyAnnotationModelChanges() {
		List queuedChanges = getQueuedAnnotationChanges();
		// go through all the pending annotation changes and apply
		// them to
		// the projection annotation model
		while (!queuedChanges.isEmpty()) {
			ProjectionAnnotationModelChanges changes = (ProjectionAnnotationModelChanges) queuedChanges.remove(0);
			try {
				fProjectionAnnotationModel.modifyAnnotations(changes.getDeletions(), changes.getAdditions(), changes.getModifications());
			}
			catch (Exception e) {
				// if anything goes wrong, log it and continue
				Logger.log(Logger.WARNING_DEBUG, e.getMessage(), e);
			}
		}
	}

	/**
	 * Returns true if there are annotation changes queued up, false otherwise
	 * 
	 * @return boolean
	 */
	boolean hasChangesQueued() {
		return !getQueuedAnnotationChanges().isEmpty();
	}

	/**
	 * Updates projection annotation model if document is not in flux.
	 * Otherwise, queues up the changes to be applied when document is ready.
	 */
	public void queueAnnotationModelChanges(ProjectionAnnotationModelChanges newChange) {
		/*
		 * future_TODO: maybe improve by checking if annotation projection
		 * model change already exists for node. if so, throw out old change.
		 */
		getQueuedAnnotationChanges().add(newChange);

		// if document isn't changing, go ahead and apply it
		if (!isDocumentChanging()) {
			applyAnnotationModelChanges();
		}
	}

	public void initialize() {
		// add document listener
		if (fDocumentListener == null) {
			fDocumentListener = new DocumentListener(this);
		}
		getDocument().addDocumentListener(fDocumentListener);
	}

	public void dispose() {
		// remove document listener
		if (fDocumentListener != null) {
			getDocument().removeDocumentListener(fDocumentListener);
		}

		// clear out list of queued changes since it may no longer
		// be accurate
		if (fQueuedAnnotationChanges != null) {
			fQueuedAnnotationChanges.clear();
			fQueuedAnnotationChanges = null;
		}
	}
}

Back to the top