comparison dwtx/jface/text/templates/TemplateContextType.d @ 129:eb30df5ca28b

Added JFace Text sources
author Frank Benoit <benoit@tionex.de>
date Sat, 23 Aug 2008 19:10:48 +0200
parents
children c4fb132a086c
comparison
equal deleted inserted replaced
128:8df1d4193877 129:eb30df5ca28b
1 /*******************************************************************************
2 * Copyright (c) 2000, 2008 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 * Port to the D programming language:
11 * Frank Benoit <benoit@tionex.de>
12 *******************************************************************************/
13 module dwtx.jface.text.templates.TemplateContextType;
14
15 import dwt.dwthelper.utils;
16
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Map;
23
24 import dwtx.core.runtime.Assert;
25 import dwtx.jface.text.BadLocationException;
26 import dwtx.jface.text.Document;
27 import dwtx.jface.text.IDocument;
28 import dwtx.text.edits.MalformedTreeException;
29 import dwtx.text.edits.MultiTextEdit;
30 import dwtx.text.edits.RangeMarker;
31 import dwtx.text.edits.ReplaceEdit;
32 import dwtx.text.edits.TextEdit;
33
34
35 /**
36 * A context type defines a context within which templates are resolved. It
37 * stores a number of <code>TemplateVariableResolver</code>s. A
38 * <code>TemplateBuffer</code> can be resolved in a
39 * <code>TemplateContext</code> using the
40 * {@link #resolve(TemplateBuffer, TemplateContext)} method.
41 * <p>
42 * Clients may extend this class.
43 * </p>
44 *
45 * @since 3.0
46 */
47 public class TemplateContextType {
48
49 /** The id of the context type. */
50 private /* final */ String fId= null;
51
52 /** Variable resolvers used by this content type. */
53 private final Map fResolvers= new HashMap();
54
55 /** The name of the context type. */
56 private String fName= null;
57
58 /**
59 * Creates a context type with an identifier. The identifier must be unique,
60 * a qualified name is suggested. The id is also used as name.
61 *
62 * @param id the unique identifier of the context type
63 */
64 public TemplateContextType(String id) {
65 this(id, id);
66 }
67
68 /**
69 * Creates a context type with an identifier. The identifier must be unique, a qualified name is suggested.
70 *
71 * @param id the unique identifier of the context type
72 * @param name the name of the context type
73 */
74 public TemplateContextType(String id, String name) {
75 Assert.isNotNull(id);
76 Assert.isNotNull(name);
77 fId= id;
78 fName= name;
79 }
80
81 /**
82 * Returns the id of the context type.
83 *
84 * @return the id of the receiver
85 */
86 public String getId() {
87 return fId;
88 }
89
90
91 /**
92 * Returns the name of the context type.
93 *
94 * @return the name of the context type
95 */
96 public String getName() {
97 return fName;
98 }
99
100 /**
101 * Creates a context type with a <code>null</code> identifier.
102 * <p>
103 * This is a framework-only constructor that exists only so that context
104 * types can be contributed via an extension point and that should not be
105 * called in client code except for subclass constructors; use
106 * {@link #TemplateContextType(String)} instead.
107 * </p>
108 */
109 public TemplateContextType() {
110 }
111
112 /**
113 * Sets the id of this context.
114 * <p>
115 * This is a framework-only method that exists solely so that context types
116 * can be contributed via an extension point and that should not be called
117 * in client code; use {@link #TemplateContextType(String)} instead.
118 * </p>
119 *
120 * @param id the identifier of this context
121 * @throws RuntimeException an unspecified exception if the id has already
122 * been set on this context type
123 */
124 public final void setId(String id) throws RuntimeException {
125 Assert.isNotNull(id);
126 Assert.isTrue(fId is null); // may only be called once when the context is instantiated
127 fId= id;
128 }
129
130 /**
131 * Sets the name of the context type.
132 *
133 * <p>
134 * This is a framework-only method that exists solely so that context types
135 * can be contributed via an extension point and that should not be called
136 * in client code; use {@link #TemplateContextType(String, String)} instead.
137 * </p>
138 *
139 * @param name the name of the context type
140 */
141 public final void setName(String name) {
142 Assert.isTrue(fName is null); // only initialized by extension code
143 fName= name;
144 }
145
146 /**
147 * Adds a variable resolver to the context type. If there already is a resolver
148 * for the same type, the previous one gets replaced by <code>resolver</code>.
149 *
150 * @param resolver the resolver to be added under its name
151 */
152 public void addResolver(TemplateVariableResolver resolver) {
153 Assert.isNotNull(resolver);
154 fResolvers.put(resolver.getType(), resolver);
155 }
156
157 /**
158 * Removes a template variable from the context type.
159 *
160 * @param resolver the variable to be removed
161 */
162 public void removeResolver(TemplateVariableResolver resolver) {
163 Assert.isNotNull(resolver);
164 fResolvers.remove(resolver.getType());
165 }
166
167 /**
168 * Removes all template variables from the context type.
169 */
170 public void removeAllResolvers() {
171 fResolvers.clear();
172 }
173
174 /**
175 * Returns an iterator for the variables known to the context type.
176 *
177 * @return an iterator over the variables in this context type
178 */
179 public Iterator resolvers() {
180 return Collections.unmodifiableMap(fResolvers).values().iterator();
181 }
182
183 /**
184 * Returns the resolver for the given type.
185 *
186 * @param type the type for which a resolver is needed
187 * @return a resolver for the given type, or <code>null</code> if none is registered
188 */
189 protected TemplateVariableResolver getResolver(String type) {
190 return (TemplateVariableResolver) fResolvers.get(type);
191 }
192
193 /**
194 * Validates a pattern, a <code>TemplateException</code> is thrown if
195 * validation fails.
196 *
197 * @param pattern the template pattern to validate
198 * @throws TemplateException if the pattern is invalid
199 */
200 public void validate(String pattern) throws TemplateException {
201 TemplateTranslator translator= new TemplateTranslator();
202 TemplateBuffer buffer= translator.translate(pattern);
203 validateVariables(buffer.getVariables());
204 }
205
206 /**
207 * Validates the variables in this context type. If a variable is not valid,
208 * e.g. if its type is not known in this context type, a
209 * <code>TemplateException</code> is thrown.
210 * <p>
211 * The default implementation does nothing.
212 * </p>
213 *
214 * @param variables the variables to validate
215 * @throws TemplateException if one of the variables is not valid in this
216 * context type
217 */
218 protected void validateVariables(TemplateVariable[] variables) throws TemplateException {
219 }
220
221 /**
222 * Resolves the variables in <code>buffer</code> within <code>context</code>
223 * and edits the template buffer to reflect the resolved variables.
224 *
225 * @param buffer the template buffer
226 * @param context the template context
227 * @throws MalformedTreeException if the positions in the buffer overlap
228 * @throws BadLocationException if the buffer cannot be successfully modified
229 */
230 public void resolve(TemplateBuffer buffer, TemplateContext context) throws MalformedTreeException, BadLocationException {
231 Assert.isNotNull(context);
232 TemplateVariable[] variables= buffer.getVariables();
233
234 List positions= variablesToPositions(variables);
235 List edits= new ArrayList(5);
236
237 // iterate over all variables and try to resolve them
238 for (int i= 0; i !is variables.length; i++) {
239 TemplateVariable variable= variables[i];
240
241 if (!variable.isResolved())
242 resolve(variable, context);
243
244 String value= variable.getDefaultValue();
245 int[] offsets= variable.getOffsets();
246 // update buffer to reflect new value
247 for (int k= 0; k !is offsets.length; k++)
248 edits.add(new ReplaceEdit(offsets[k], variable.getInitialLength(), value));
249
250 }
251
252 IDocument document= new Document(buffer.getString());
253 MultiTextEdit edit= new MultiTextEdit(0, document.getLength());
254 edit.addChildren((TextEdit[]) positions.toArray(new TextEdit[positions.size()]));
255 edit.addChildren((TextEdit[]) edits.toArray(new TextEdit[edits.size()]));
256 edit.apply(document, TextEdit.UPDATE_REGIONS);
257
258 positionsToVariables(positions, variables);
259
260 buffer.setContent(document.get(), variables);
261 }
262
263 /**
264 * Resolves a single variable in a context. Resolving is delegated to the registered resolver.
265 *
266 * @param variable the variable to resolve
267 * @param context the context in which to resolve the variable
268 * @since 3.3
269 */
270 public void resolve(TemplateVariable variable, TemplateContext context) {
271 String type= variable.getType();
272 TemplateVariableResolver resolver= (TemplateVariableResolver) fResolvers.get(type);
273 if (resolver is null)
274 resolver= new TemplateVariableResolver(type, ""); //$NON-NLS-1$
275 resolver.resolve(variable, context);
276 }
277
278 private static List variablesToPositions(TemplateVariable[] variables) {
279 List positions= new ArrayList(5);
280 for (int i= 0; i !is variables.length; i++) {
281 int[] offsets= variables[i].getOffsets();
282 for (int j= 0; j !is offsets.length; j++)
283 positions.add(new RangeMarker(offsets[j], 0));
284 }
285
286 return positions;
287 }
288
289 private static void positionsToVariables(List positions, TemplateVariable[] variables) {
290 Iterator iterator= positions.iterator();
291
292 for (int i= 0; i !is variables.length; i++) {
293 TemplateVariable variable= variables[i];
294
295 int[] offsets= new int[variable.getOffsets().length];
296 for (int j= 0; j !is offsets.length; j++)
297 offsets[j]= ((TextEdit) iterator.next()).getOffset();
298
299 variable.setOffsets(offsets);
300 }
301 }
302 }